thad@cup.portal.com (Thad P Floryan) (01/09/90)
Recently there have been 3 different programs posted which, among other things, report the last-login date-and-time of a user on a SystemV system: Greg Woods' lastlog (in alt.sources), Lenny Tropiano's logininit 2.1 (in comp.sys.att and unix-pc.sources), and my lastlogin 1.0 (in comp.sys.att and unix-pc.sources). Each program uses different strategies, and each has a related problem! If it could be GUARANTEED that any of the programs above would ONLY be invoked from one's .profile, then they DO work. But ... As one is on-line for awhile, circumstances change, and conditions may cause the programs to fail. I'm not talking about just the situation where one user may have multiple simultaneous sessions whose "last logins" affect the results. No. Something much more fundamental: Failure to UNIQUELY identify the user. Greg's and Lenny's programs, when this happens, essentially report the failure with a message similar to "cannot locate utmp entry for tty"; my program fails by reporting the information for root and alters the non-root user's file with root's last login date&time. (Well, whaddya expect for a free program and a 1 pico Second warranty? :-) So, what is the source of these failures? After some experimentation: 1) using getuid(), or 2) assuming the user HAS a controlling terminal. ^^^^^^^^ (There's THAT word again; Benny Hill's probably laughing his head off! :-) So, how are these failures invoked? 1) "su", or 2) redirecting stdin, stdout AND stderr (by whatever means). I put together a "test" program that exercises the causes and displays the symptoms of the failures. The program is ugly as sin as it was pieced together as I was flipping through all the SysV docs. If anyone's interested I could email a copy; the source is only 3K and is uncommented though its output is nicely formatted. From my experiments and reading the docs, it appears that the ONLY parameter one can get with 100% certainty in these regards is the login name of the user. It does NOT "appear" possible to always identify the specific "terminal" of the user so as to match the entry(ies) in the /etc/utmp file ... unless, perhaps, one uses nlist() on /unix and starts peeking through system memory, which is beyond the capabilities of any program(s) that may be developed by the "normal" user. It also appears the only things that "could" be matched in the /etc/utmp file (using "normally" available information) are the user's login name and the controlling terminal; all this using the getutent(), getutid() or getutline(). The writeup of getlogin(3C) claims the correct way to determine the login name is to use cuserid(3S); or getlogin(3C) (if getlogin() fails then getpwuid(), and if getpwuid() fails (re: getuid()), then one is SOL.) If one is su'd to root or another user, getuid() does NOT return your UID, but, instead, that of the user to which you've su'd. If stdin, stdout and stderr are ALL redirected (e.g." < infil > outfil 2>&1 " ) then ttyslot(3C) and ttyname(3C) both fail if none of the file descriptors reference a terminal (such as is the case during "total" redirection). I've also discovered that a portion of the docs for ttyslot(3C) is WRONG regarding returned value, because a returned value of 0 is a valid "index" into /etc/utmp. The value that it DOES return on failure, as shown by running my test program under one of the failure-mode conditions, is -1. And before you say "Aw, just some more piddling UNIXPC-specific problems", let it be known I've tested the program on several implementations of SysV on AT&T machines and two different implementations of HP-UX; same problem on all systems to which I have access. A friend is checking this out for me on an Amdahl UTS machine as I'm writing this, but I believe she'll find the same problem (she's also checking out the HDB Dialers & Devices stuff :-) A simple demonstration of the problem using who(1): $ who am i thad p0 Jan 7 16:21 $ ls -l fish -rw-r--r-- 1 thad users 0 Jan 7 18:34 fish $ cat fish $ who am i < fish > crap 2>&1 $ cat crap ===> process not attached to terminal Usage: who [-rbtpludAasT] [am i] [utmp_like_file] ... help output deleted ... Aha! Just received a call back from my friend at Amdahl (she works on the UTS kernel software (SysV-derived)) and: 1) $ who am i < fish > crap 2>&1 $ cat crap ===> You must have a terminal attached. 2) The Dialers and Devices require the same "\M", "\m" and ",M" as do the systems we've recently been discussing in another message thread and for the same reasons. Sheesh, a wide-spread problem & "solution". Pardon the use of "cat crap" in the above example, but my friend has two cats and she thought it was hilarious! Then she zingered me with: Amdahl is now producing their UNIX 7300 systems, running the UTS kernel. Now I wonder where they got THAT number ^^^^ ?!?! :-) In any event, what this all boils down to is the "simple" question: ===> Is there a way to 100% positively, absolutely, unequivocally, <=== ===> unerringly identify the current login user's /etc/utmp session <=== ===> record under ALL conditions of su'iness and output redirection <=== ===> and multiple simultaneous logins? <=== That identification of the login user's record: 1) MUST succeed even if there are multiple same-user sessions online (meaning logging in twice from two different terminals), 2) MUST succeed even if the user is su'd, and 3) MUST succeed even if all standard streams are re-directed. Sounds simple, no? I've gone through every page of all xxx(2*) and xxx(3*) man pages looking for an answer and nothing is apparent. If you have an answer to that "simple" question, that runs non-privileged (heck, even privileged (at this stage of the game)), I'm sure that enquiring minds would like to know. Thad Floryan [ thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
jay@banzai.PCC.COM (Jay Schuster) (01/10/90)
thad@cup.portal.com (Thad P Floryan) writes: >In any event, what this all boils down to is the "simple" question: > ===> Is there a way to 100% positively, absolutely, unequivocally, <=== > ===> unerringly identify the current login user's /etc/utmp session <=== > ===> record under ALL conditions of su'iness and output redirection <=== > ===> and multiple simultaneous logins? <=== Without reading /dev/kmem, I believe not. If there was some way of getting your tty group ID, you could search through utmp and find its pid there. But I don't think there's any wany of finding your tty group id without searching through /dev/kmem. End even then, if the process had detached itself (called setpgrp()), it has no controlling terminal, and you wouldn't be able to find its tty slot because the kernel will tell you that it has none. >Sounds simple, no? It doesn't sound simple, because UNIX doesn't really care what tty you are logged on to, and loses that information rather easily. It cares about the uid you are, but allows you to change it (su). -- Jay Schuster <jay@pcc.COM> uunet!uvm-gen!banzai!jay, attmail!banzai!jay The People's Computer Company `Revolutionary Programming'
comeau@utoday.UUCP (Greg Comeau) (01/11/90)
In article <25730@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: > ===> Is there a way to 100% positively, absolutely, unequivocally, <=== > ===> unerringly identify the current login user's /etc/utmp session <=== > ===> record under ALL conditions of su'iness and output redirection <=== > ===> and multiple simultaneous logins? <=== It appears you wanted to do more than what is stores in u/w/tmp anyway, so you nest bet may be to forget that file and create whatever you need tocreate via /etc/profile (which will only therefore catch interactive logins and not stuff like uucp which can be handled in another way) as well as front-ending or re-writing su for the audits you need. -- Greg, Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418 Producers of CC C++, SysAdm columnist for UNIX Today!, Microsoft Systems Journal (C programming), + others. Also, BIX c.language & c.plus.plus conf. moderator. Here:attmail!csanta!greg / BIX:comeau / CIS:72331, 3421 / voice:718-849-2355
woods@eci386.uucp (Greg A. Woods) (01/12/90)
In article <25730@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: > Recently there have been 3 different programs posted which, among other things, > report the last-login date-and-time of a user on a SystemV system: > > Each program uses different strategies, and each has a related problem! My version (lastlog) is complete and sufficient for the purposes it was designed for, and it is reasonably difficult to subvert its intentions in a well managed system. 1. lastlog should be placed in /etc/profile, as I suggested in the readme. In this environment, it functions correctly and is always called (except for uucp logins, though this can be remedied by writing a shell around uucico). The normal case of a user executing lastlog after his session has started is harmless, since the effect is nil. 2. lastlog cannot be fooled into reporting on a different utmp line, since to fool ttyslot(3c), one would have to have read permission on another tty with a current utmp entry. I make the assumption that other ttys should never be readable by the average user. Further checking could be done to assert the current uid matched the one in the utmp entry. 3. If someone fools lastlog by using a different uid, then either your system has a bad security hole, or that user knows another's password. In any case there is no loss of information; current information for the subverted user's id is recorded. It would be nice if su knew about lastlog too. 4. lastlog information cannot be deleted by the average user. This is the most important point for me. The SysVr3.2 login keeps similar data in the ctime of the inode for the .lastlogin file in each user's home directory. Although you cannot set this value to represent some date in the past, this scheme is still not perfect. If file is deleted, you know only that a break in to your account was attempted, but it is not easy to determine when it occured, though the ctime of your home directory might be a clue. One of the reasons I wrote lastlog and ported finger was because they provide one of the simple security related features of BSD that I really missed in the SysV world. Perhaps someday I'll write my own login replacement for SysV (which isn't actually that difficult, I've done it for V7), and be done with the uncertainty of a user-accessable lastlog programme. -- Greg A. Woods woods@{eci386,gate,robohack,ontmoh,tmsoft,gpu.utcs.UToronto.CA,utorgpu.BITNET} +1-416-443-1734 [h] +1-416-595-5425 [w] VE3-TCP Toronto, Ontario CANADA
ssb@quest.UUCP (Scott S. Bertilson) (01/12/90)
jay@banzai.PCC.COM (Jay Schuster) writes: >If there was some way of getting your tty group ID, you could search >through utmp and find its pid there. But I don't think there's any >wany of finding your tty group id without searching through /dev/kmem. On my SVR2 Altos, there *IS* a "getpgrp". It would seem to me that one could grab that and scan the "utmp" file to find what port the process is on. If the process has detached via "setpgrp", it would seem that your "utmp" entry doesn't apply anymore anyway. (I'd look at my 3b1, but it's at home..) -- Scott S. Bertilson ...uunet!rosevax!rose3!quest!ssb scott@poincare.geom.umn.edu
thad@cup.portal.com (Thad P Floryan) (01/12/90)
comeau@utoday.UUCP (Greg Comeau) in <1143@utoday.UUCP> writes:
It appears you wanted to do more than what is stores in u/w/tmp anyway,
so you nest bet may be to forget that file and create whatever you need
tocreate via /etc/profile (which will only therefore catch interactive
logins and not stuff like uucp which can be handled in another way)
as well as front-ending or re-writing su for the audits you need.
regarding my question whether it's possible to uniquely identify a user under
all conceivable circumstances. "Uniquely identify" pertaining to username and
to "controlling terminal" such that one could, if so desired, locate the specif
c
/etc/utmp entry.
Results so far:
username: YES (via cuserid(3S))
terminal: NO (if all streams are redirected)
This "quest for truth" is solely for my own edification after I discovered
my own lastlogin program "failed" when I was running su'd root:
I cannot ASSUME the $HOME will always be inviolate.
I cannot ASSUME the user will never "su".
I cannot ASSUME the user won't redirect stdin, stdout and stderr.
Due to other posted events since Jan.2, I have now removed the word "ASSUME"
from my vocabulary! :-)
Examples abound re: nlist()'ing /unix, so that's not the problem. The question
was whether there's a non-privileged way of accurately identifying the user.
It appears there is NO such way per (email) responses received to date.
My purpose was not to audit, but to write a PD "who" that would highlight the
present user (either with "*" or reverse video or whatever's applicable) per:
$ who
guest tty000 Jan 11 22:43
thad w1 Jan 10 01:59
thad * p0 Jan 12 00:32
thad ph1 Jan 11 23:57
And, don't laugh; I've had over 16 people (myself multiple times, too) logged
into one of my UNIXPCs at ONE TIME. This was during a party last month when I
became weary of a boor bragging about his system supporting multiple users at
one time (and, no, it was not any AT&T system although its name did begin with
the letter "A") that (thanks to StarLAN) I just started firing up the online
jobs and had them run GNU EMACS, gcc, several graphics demos, etc. Needless
to say, the boor quickly became quiet! It became very apparent very quickly
the UNIXPC outperformed a Mac II A/UX Version 1 (esp. with respect to disk
I/O); he brought his machine over from next door and there was simply NO doubt
in anyone's mind which machine was quicker.
Thad Floryan [ thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
comeau@utoday.UUCP (Greg Comeau) (01/13/90)
In article <25845@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: >Examples abound re: nlist()'ing /unix, so that's not the problem. The question >was whether there's a non-privileged way of accurately identifying the user. >It appears there is NO such way per (email) responses received to date. >My purpose was not to audit, but to write a PD "who" that would highlight the >present user (either with "*" or reverse video or whatever's applicable) per: > $ who > thad w1 Jan 10 01:59 > thad * p0 Jan 12 00:32 Um, if that's what you want to do then assuming (there's that work again!) a non-esotric use of windows why not just cross check the /dev/tty minor/ major with the minor/major of the dev stored in u/w/tmp? Or you could even write a shell script comboing probably the who command, the tty command, and the sed command. >And, don't laugh; I've had over 16 people (myself multiple times, too) logged >into one of my UNIXPCs at ONE TIME. Interesting. Via what mechanism? -- Greg, Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418 Producers of CC C++, SysAdm columnist for UNIX Today!, Microsoft Systems Journal (C programming), + others. Also, BIX c.language & c.plus.plus conf. moderator. Here:attmail!csanta!greg / BIX:comeau / CIS:72331, 3421 / voice:718-849-2355
karl@MorningStar.Com (Karl Fox) (01/13/90)
My UNIX-PC (3.51+Development) *does* have getpgrp(). I tried this quick
hack and haven't been able to make it fail yet. It works while su'd,
nohup'ed and totally redirected.
# include <sys/types.h>
# include <utmp.h>
# define SO "\033[7m"
# define SE "\033[m"
main()
{
extern struct utmp *getutent();
register int pgrp = getpgrp();
register struct utmp *up;
while (up = getutent())
printf("%s%8s %4s %12s %5d %d %d/%d%s\n",
pgrp == up -> ut_pid ? SO : "",
up -> ut_user,
up -> ut_id,
up -> ut_line,
up -> ut_pid,
up -> ut_type,
up -> ut_exit.e_termination,
up -> ut_exit.e_exit,
pgrp == up -> ut_pid ? SE : "");
}
--
Karl Fox, Morning Star Technologies karl@MorningStar.Com
thad@cup.portal.com (Thad P Floryan) (01/14/90)
comeau@utoday.UUCP (Greg Comeau) in <1155@utoday.UUCP> writes: >And, don't laugh; I've had over 16 people (myself multiple times, >too) logged into one of my UNIXPCs at ONE TIME. Interesting. Via what mechanism? Hmmm, did the article get truncated? If so, here's the last paragraph again in which I detail the how's and wherefore's (using StarLAN): " And, don't laugh; I've had over 16 people (myself multiple times, too) logged into one of my UNIXPCs at ONE TIME. This was during a party last month when I became weary of a boor bragging about his system supporting multiple users at one time (and, no, it was not any AT&T system although its name did begin with the letter "A") that (thanks to StarLAN) I just started firing up the online ^^^^^^^^^^^^^^^^^ jobs and had them run GNU EMACS, gcc, several graphics demos, etc. Needless to say, the boor quickly became quiet! It became very apparent very quickly the UNIXPC outperformed a Mac II A/UX Version 1 (esp. with respect to disk I/O); he brought his machine over from next door and there was simply NO doubt in anyone's mind which machine was quicker. " I have a moderate-size StarLAN network to which many things are connected, including a lot of terminals. The StarLAN software (for the UNIXPC) claims up to 32 users may be connected via StarLAN to a single machine (in addition to which there are the 7 RS-232 ports, the onboard modem, and the console window, for a max of 41 online users logged-in at one time) but I haven't tried that many (yet! :-) Thad Floryan [ thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
thad@cup.portal.com (Thad P Floryan) (01/14/90)
karl@MorningStar.Com (Karl Fox) in <KARL.90Jan13104731@crappie.MorningStar.Com> writes: My UNIX-PC (3.51+Development) *does* have getpgrp(). I tried this quick hack and haven't been able to make it fail yet. It works while su'd, nohup'ed and totally redirected. Believe it or not, I did an almost identical program just minutes after Scott S. Bertilson mentioned the getpgrp(). The docs for getpgrp(2) didn't really give any hints as to how it'd be used, but INTRO(2) said the process group ID is the PID of the "group leader", and examination of a "ps -ef" output showed the relationship. The { getpgrp() ... getutent() } strategy "almost" works: 1. logging in on console (window), all cases work, 2. logging in through /dev/ph0, all cases work, 3. logging in through /dev/tty???, all cases work, but ===> 4. logging in through StarLAN, -=<NO>=- cases work. Sigh. :-( The "problem" is that /etc/utmp doesn't contain any entry(ies) for a StarLAN "listener" process. Doing a "who -a" shows there's no process ID in /etc/utmp matching what's shown by "ps -ef". My approach to solving a problem is exemplified by a recent quote posted to comp.mail.uucp by Erik Naggum (enag@ifi.uio.no): `` "get things _right_", not "get things _working_". "Working" is a subset of "right." '' At this point, I've started looking at the proc structure <sys/proc.h> and at the user structure <sys/user.h>, and have so far coded what's shown in the fragment enclosure. I need to look carefully at what this new program will do since I have the distinct impression it's possible a process' entry could disappear out from under me while reading /dev/kmem. If anyone has suggestions how to handle THAT problem (browsing dynamically changing structures), advice would be appreciated; the "ps" program must do it, but I don't have sources. Thad -------------------- program fragment #include <stdio.h> #include <sys/types.h> #include <sys/proc.h> #include <sys/user.h> #include <fcntl.h> #include <nlist.h> struct nlist adrget[3] = { { "proc" }, /* info for sys/proc.h */ { "u" }, /* info for sys/user.h */ { NULL } }; main(argc, argv) int argc; char *argv[]; { void perror(); int close(), fprintf(), getpgrp(), nlist(), open(); long lseek(); int kmemfd; register int pgrp = getpgrp(); register int results = nlist("/unix", adrget); if (results < 0 || adrget[0].n_value == 0 || adrget[1].n_value == 0) { fprintf(stderr, "%s: namelist error for /unix\n", argv[0]); exit(1); } if ((kmemfd = open("/dev/kmem", O_RDONLY)) == -1) { perror("/dev/kmem"); exit(1); } if (lseek(kmemfd, adrget[0].n_value, 0) < 0) { perror("lseek /dev/kmem"); exit(1); } /* program "guts" to be inserted here */ close(kmemfd); }
comeau@utoday.UUCP (Greg Comeau) (01/15/90)
In article <25932@cup.portal.com> thad@cup.portal.com (Thad P Floryan) writes: >I need to look carefully at what this new program will do >since I have the distinct impression it's possible a process' entry could >disappear out from under me while reading /dev/kmem. >If anyone has suggestions how to handle THAT problem (browsing dynamically >changing structures), advice would be appreciated; the "ps" program must do >it, but I don't have sources. > Your worry is proper: entries can disappear out from under you. 'ps' *doesn't* do it though. It is strictly a snapshot and quite often gets things wrong. Problem is that without a driver, you are not part of the kernel and therefore there is nothing you can do about it except zoom around. And have fun with the guts of your program: you are assured an interesting coupla days! -- Greg, Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418 Producers of CC C++, SysAdm columnist for UNIX Today!, Microsoft Systems Journal (C programming), + others. Also, BIX c.language & c.plus.plus conf. moderator. Here:attmail!csanta!greg / BIX:comeau / CIS:72331, 3421 / voice:718-849-2355