?? utmp.c
字號:
/* * @(#) utmp.c RCS: $Revision: 1.8 $ $Date: 95/03/08 01:13:19 $ * * This file contains machine specific code for making sure getlogin() works. * See the function setlogin below. * * Make sure login database is updated getut(3c), but this is not * available in POSIX, or SYSV XPG3; it's only a SYSV XPG2 feature. * There thus is no machine independent way to make getlogin work. * * There are two distinct flavors of utmp.h files: * * System V style: SGI's IRIX, Solaris, OSF1, HP-UX, UNICOS # #define ut_name ut_user * struct utmp { * char[] ut_user, ut_id, ut_line; * short ut_pid, ut_type; * struct { short e_termination; short e_exit } ut_exit; except linux * time_t ut_time; * char ut_host[]; // HP-UX, OSF1, UNICOS linux only !Solaris <utmp.h> * } * * UTMPX style: Solaris <utmpx.h> (*almost* the same as system V style!) * struct utmpx { <- different name * char[] ut_user, ut_id, ut_line; * pid_t ut_pid; * short ut_type; * struct exit_status ut_exit; <- same * struct timeval ut_tv; <- different! (BSD style timeofday) * long ut_session; * short ut_syslen; * char ut_host[]; * } * * BSD style: Ultrix, SunOS4.2, UNICOS * struct utmp { * char ut_line[8], ut_name[8], ut_host[16]; * long ut_time; * } * * The least-common denominator of utmp entries: * char ut_line[] device name without path component (e.g. "ttyp4") * 8 chars on BSD, 12 on hp-ux, longer on osf1 * time_t ut_time time entry was made (long on BSD) * char ut_name[8] login name of the user * * The following field is not present on SGI's IRIX and Solaris. * char ut_host[16] host name if remote * * Unfortunately, BSD and System V use different names for the field containing * the user login name (ut_name, ut_user respectively). Fortunately, all * SYSV machines I can find have a #define for ut_name. * * For BSD, empty slots are indicated by ut_name is a null string. * Remote users are indicated by a non-null ut_host field. * * For System V, empty slots are indicated by ut_type field as * DEAD_PROCESS. All other fields must be valid as usual. * * Solaris has two utmp files with different struct formats: * /var/adm/utmp based on <utmp.h> using struct utmp. UTMP_FILE * /var/adm/utmpx based on <utmpx.h> using struct utmpx. UTMPX_FILE * * Changes UTMPX_FILE will not be noticed by the "last" and "who" commands * unless UTMP_FILE is also updated. UTMPX_FILE has an rhost field. */#define _POSIX_SOURCE /* this isn't quite posix source *//* * This is a mess. HP-UX ANSI C won't define pid_t in <sys/types.h> unless * _POSIX_SOURCE is defined. Other machines may refuse to define it. Pick * what's appropriate. <utmp.h> uses pid_t. */#if defined(__SOLARIS__) /* { */#undef _POSIX_SOURCE /* allows struct timeval to be defined */#undef _POSIX_C_SOURCE#include <sys/types.h> /* uid_t size_t */#include <time.h> /* time (also needed for "utmp.h") */#define _POSIX_SOURCE#define _POSIX_C_SOURCE#else /* } { */#include <sys/types.h> /* uid_t size_t */#include <time.h> /* time (also needed for "utmp.h") */#endif /* } */#include <unistd.h> /* open read write lseek getuid */#include <stdio.h>#include <fcntl.h> /* O_RDWR */#include <string.h> /* strchr memset */#include <pwd.h> /* struct passwd, getpwuid */#define OFFSET(s, m) ((unsigned) &(((s *)0)->m))#include "utmp.h" /* UTMP_FILE WTMP_FILE <utmp.h> or <utmpx.h> */#include "log.h"#include "deslogin.h" /* progName ERRMSG *//* * Update the system's "currently logged in users" file (used by "who") * * Input: * utmp_file - the name of the file to update * ut - address of the record insert into file * utbuf - storage for a temporary buffer * utsz - the size of the ut and utbuf record's storage * lineoff - the offset into the record for the ut_line field * linesz - the size of the ut_line field * * Must minimize the time the file is open to prevent write conflict with * other processes trying to update utmp. */int update_utmp(utmp_file, ut, utbuf, utsz, lineoff, linesz) char *utmp_file; void *ut, *utbuf; unsigned utsz, lineoff, linesz;{ int fd, count, res = -1; long offset = 0, lres; fd = open(utmp_file, O_RDWR); if (fd < 0) { log("%s: (update_utmp) open(\"%s\", O_RDWR) failed -- %s\n", progName, utmp_file, ERRMSG); return -1; } /* * Find offset of entry with the same line value if present */ while ((count = read(fd, utbuf, utsz)) == utsz) { if (strncmp((char *)ut+lineoff, (char *)utbuf+lineoff, linesz) == 0) { break; } offset += count; } if (count < 0) { log("%s: (update_utmp) read failed from \"%s\" -- %s\n", progName, utmp_file, ERRMSG); goto utmp_failed; } lres = lseek(fd, (off_t) offset, SEEK_SET); if (lres < 0) { log("%s: (update_utmp) lseek to offset %ld failed in \"%s\" -- %s\n", progName, offset, utmp_file, ERRMSG); goto utmp_failed; } count = write(fd, (char *) ut, utsz); if (count < 0) { log("%s: (update_utmp) write failed to \"%s\" -- %s\n", progName, utmp_file, ERRMSG); goto utmp_failed; } if (count != utsz) { log("%s: (update_utmp) short write to \"%s\"\n", progName, utmp_file); goto utmp_failed; } res = 0; /* success */utmp_failed: close(fd); return res;}/* * Update the system login history file (used by "last" and "lastb") * * Must minimize the time the file is open to prevent write conflict with * other processes trying to update utmp. */int update_wtmp(wtmp_file, ut, utsz) char *wtmp_file; void *ut; unsigned utsz;{ int fd, count, res = -1; fd = open(wtmp_file, O_WRONLY | O_APPEND); if (fd < 0) { log("%s: (update_wtmp) open(\"%s\", O_WRONLY|O_APPEND) failed -- %s\n", progName, wtmp_file, ERRMSG); return -1; } count = write(fd, ut, utsz); if (count < 0) { log("%s: (update_wtmp) write failed to \"%s\" -- %s\n", progName, wtmp_file, ERRMSG); goto wtmp_failed; } if (count != utsz) { log("%s: (update_wtmp) short write to \"%s\"\n", progName, wtmp_file); goto wtmp_failed; } res = 0; /* success */wtmp_failed: close(fd); return res;}/* * The inverse of the POSIX getlogin call. Setup the login for the given * user name. * * Input: * tty = the device file assigned as the controlling terminal * name = the login name (only first 8 characters signifacant) * rhost = the hostname of the remote host (only 1st 16 chars used) * statloc = the address of the process exit status * (if zero, then this is a new process stating up) * * The calling process should ensure that it owns the tty before it calls * this routine, or it could overwrite a legitimate processes tty. * * Returns: 0 success, -1 failure. */int setlogin(tty, username, rhost, statloc) char *tty, *username, *rhost; int *statloc;{ char *line, *id; long offset; int res; struct utmp ut, utbuf;#if defined(UTMPX_FILE) /* { */ struct utmpx utx, utxbuf;#endif /* } */ if ((tty == 0) || (username == 0) || (rhost == 0)) return -1; /* * There are two possibly conflicting ways to get the line: * 1) take the last component of the path (SYSV) (e.g. fails for /dev/pts/6) * 2) Strip of the first component of the path. (irix) (/dev/pts/6 = pts/6) * 3) Don't strip any components at all (Solaris) * * Which one is the most "popular"? Probably should be a compile-time test. * I'm using the last component of the path. */ line = strchr(tty, '/'); if (line == tty) { line = strchr(tty + 1, '/'); if (line == (char *) 0) line = tty; } if (line == (char *) 0) line = tty; else line++; /* * The id field (for init) is the last two characters of the line on SYSV * For SOLARIS, id is prefixed by two character service abbreviation. * (e.g. Telnet is 'tn', rlogin is 'rl') * I'm using the last two characters of the line. */ offset = strlen(line) - 2; if (offset < 0) offset = 0; id = line + offset;#if defined(UTMPX_FILE) /* { */ memset(&utx, '\0', sizeof utx);#endif /* } */ memset(&ut, '\0', sizeof ut); time((time_t *) &ut.ut_time); strncpy(ut.ut_line, line, sizeof ut.ut_line); strncpy(ut.ut_name, username, sizeof ut.ut_name); #if defined(USER_PROCESS) /* { SYSV */ strncpy(ut.ut_id, id, sizeof ut.ut_id); ut.ut_pid = getpid(); ut.ut_type = USER_PROCESS; /* assume login until proven othewise */ if (statloc != 0) { /* process exit */ ut.ut_type = DEAD_PROCESS;#if !defined(_LINUX_SOURCE) /* { */ ut.ut_exit.e_termination = *statloc & 0xff; ut.ut_exit.e_exit = (*statloc >> 8) & 0xff;#endif /* } */ }#else /* } { BSD */ if (statloc != 0) { ut.ut_name[0] = '\0'; }#endif /* } BSD */#if !defined(__sgi) && !defined(__DYNIX__) && !defined(__SOLARIS__) /* { */ strncpy(ut.ut_host, rhost, sizeof ut.ut_host);#endif /* } */ /* * This used to be broken for __DYNIX__ and __SOLARIS__. * Version 1.3 fixed this. If not, mail barrett@asgard.cs.colorado.edu */ res = update_utmp(UTMP_FILE, &ut, &utbuf, sizeof ut, OFFSET(struct utmp, ut_line), sizeof ut.ut_line); if (res >= 0) { res = update_wtmp(WTMP_FILE, &ut, sizeof ut); }#if defined(UTMPX_FILE) /* { __SOLARIS__ <utmpx.h> */ getutmpx(&ut, &utx); /* no return result */ gettimeofday(&utx.ut_tv); /* shouldn't be necessary; do it anyway */ strncpy(utx.ut_host, rhost, sizeof utx.ut_host); if (res >= 0) { res = update_utmp(UTMPX_FILE, &utx, &utxbuf, sizeof utx, OFFSET(struct utmpx, ut_line), sizeof utx.ut_line); } if (res >= 0) { res = update_wtmp(WTMPX_FILE, &utx, sizeof utx); }#endif /* } */ return res;}/* * Because of severe braindamage, the POSIX getlogin() call has a * high-probability of failing to work on many machines. The things to * consider are: * * This process must have a controlling terminal to determine the tty line * to lookup in utmp. * * There must be a (unique) entry for that line in utmp. * * There is no guarantee that the contents of utmp is correct. (It's world * writable on most SUN BSD machines for example! Thus, the login name * returned there may not be correct at all. * * cuserid() is obsolete. The problem is that it could return the login * name corresponding to the effective user id instead of the real user id. * * There may be multiple user names corresponding to each user id. * * The bottom line is that there is *no way* to accurately determine which * of the (possibly many) login names were used to get this particular real * user id. * * I've decided not to trust utmp at all, and just to get the first valid * user id using the POSIX.1 conformant calls to <pwd.h>, getpwuid. * * Note that the only "portable" fields of a struct passwd are: * * char *pw_name * char *pw_passwd * uid_t pw_uid * gid_t pw_gid * * The only way this routine should fail (returning (char *) 0) is if * /etc/passwd is not readable. Note that yellow-pages lookups could occur * as a result of using this function. * * AnnexB.4.2.4:2682-2694 * The getlogin() function returns a pointer to the user's login name. The * same user ID may be shared by several login names. If it is desired to get * the user database entry that is used during login, the result of getlogin() * should be used to provide the argument to the getpwnam() function. (This * might be used to determine the user's login shell, particularly where a * single user has multiple login shells with distinct login names, but the * same user ID.) * The information provided by the cuserid() function, which was originally * defined in IEEE Std 1003.1-1990 and subsequently removed, can be obtained * by the following: getpwuid(geteuid()), while the information provided by * historical implementations of cuserid() can be obtained by: * getpwuid(getuid()). */char *getLoginName() { register uid_t uid = getuid(); register struct passwd *pwent; pwent = getpwuid(uid); if (pwent == (struct passwd *) 0) { return (char *) 0; } else { return pwent->pw_name; }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -