From owner-svn-src-head@FreeBSD.ORG Sat Dec 5 19:53:29 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6B7431065670; Sat, 5 Dec 2009 19:53:29 +0000 (UTC) (envelope-from ed@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5913B8FC13; Sat, 5 Dec 2009 19:53:29 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nB5JrTQK098047; Sat, 5 Dec 2009 19:53:29 GMT (envelope-from ed@svn.freebsd.org) Received: (from ed@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nB5JrTRs098035; Sat, 5 Dec 2009 19:53:29 GMT (envelope-from ed@svn.freebsd.org) Message-Id: <200912051953.nB5JrTRs098035@svn.freebsd.org> From: Ed Schouten Date: Sat, 5 Dec 2009 19:53:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r200153 - head/lib/libulog X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 05 Dec 2009 19:53:29 -0000 Author: ed Date: Sat Dec 5 19:53:29 2009 New Revision: 200153 URL: http://svn.freebsd.org/changeset/base/200153 Log: Massively extend libulog: - Just like struct utmp, store strings inside struct utmpx itself. This is needed to make things like pututxline() work. - Add ut_id and ut_pid fields, even though they have little use in our implementation. - It turns out our "reboot" wtmp entries indicate a system boot, so remove REBOOT_TIME - Implement getutxline() and pututxline - Add getutxuser() and setutxfile(), which allows us to crawl wtmp and lastlog files as well. - Add _ULOG_POSIX_NAMES, so we can already use the POSIX names if we really want to. Added: head/lib/libulog/ulog_pututxline.c (contents, props changed) head/lib/libulog/ulog_setutxfile.3 (contents, props changed) head/lib/libulog/ulog_util.c (contents, props changed) Modified: head/lib/libulog/Makefile head/lib/libulog/Symbol.map head/lib/libulog/ulog.h head/lib/libulog/ulog_getutxent.3 head/lib/libulog/ulog_getutxent.c head/lib/libulog/ulog_internal.h head/lib/libulog/ulog_login.3 head/lib/libulog/ulog_login.c Modified: head/lib/libulog/Makefile ============================================================================== --- head/lib/libulog/Makefile Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/Makefile Sat Dec 5 19:53:29 2009 (r200153) @@ -3,15 +3,25 @@ LIB= ulog SHLIB_MAJOR= 0 INCS= ulog.h -SRCS= ulog.h ulog_getutxent.c ulog_internal.h \ - ulog_login.c ulog_login_pseudo.c +SRCS= ulog.h ulog_getutxent.c ulog_internal.h ulog_login.c \ + ulog_login_pseudo.c ulog_pututxline.c ulog_util.c -MAN= ulog_getutxent.3 ulog_login.3 +MAN= ulog_getutxent.3 ulog_login.3 ulog_setutxfile.3 MLINKS+=ulog_getutxent.3 ulog_endutxent.3 \ + ulog_getutxent.3 ulog_getutxline.3 \ + ulog_getutxent.3 ulog_pututxline.3 \ ulog_getutxent.3 ulog_setutxent.3 \ ulog_login.3 ulog_login_pseudo.3 \ ulog_login.3 ulog_logout.3 \ - ulog_login.3 ulog_logout_pseudo.3 + ulog_login.3 ulog_logout_pseudo.3 \ + ulog_setutxfile.3 ulog_getutxuser.3 + +# Add links to -style functions. +MLINKS+=ulog_endutxent.3 endutxent.3 \ + ulog_getutxent.3 getutxent.3 \ + ulog_getutxline.3 getutxline.3 \ + ulog_pututxline.3 pututxline.3 \ + ulog_setutxent.3 setutxent.3 WARNS?= 6 Modified: head/lib/libulog/Symbol.map ============================================================================== --- head/lib/libulog/Symbol.map Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/Symbol.map Sat Dec 5 19:53:29 2009 (r200153) @@ -5,9 +5,13 @@ FBSD_1.2 { ulog_endutxent; ulog_getutxent; + ulog_getutxline; + ulog_getutxuser; ulog_login; ulog_login_pseudo; ulog_logout; ulog_logout_pseudo; + ulog_pututxline; ulog_setutxent; + ulog_setutxfile; }; Modified: head/lib/libulog/ulog.h ============================================================================== --- head/lib/libulog/ulog.h Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/ulog.h Sat Dec 5 19:53:29 2009 (r200153) @@ -31,6 +31,12 @@ #include #include +#include + +#ifndef _PID_T_DECLARED +typedef __pid_t pid_t; +#define _PID_T_DECLARED +#endif /* * libulog. @@ -42,61 +48,61 @@ * processes as well, provided that they hold a file descriptor to a * pseudo-terminal master device. * - * Unlike struct utmpx, the buffers containing the strings are not - * stored inside struct ulog_utmpx itself. Processes should never - * handcraft these structures anyway. - * * This library (or at least parts of it) will hopefully deprecate over * time, when we provide the API. */ -#define _UTX_USERDISPSIZE 16 -#define _UTX_LINEDISPSIZE 8 -#define _UTX_HOSTDISPSIZE 16 - struct ulog_utmpx { - char *ut_user; -#if 0 - char *ut_id; -#endif - char *ut_line; - char *ut_host; -#if 0 - pid_t ut_pid; -#endif - short ut_type; + char ut_user[32]; + char ut_id[8]; /* XXX: unsupported. */ + char ut_line[32]; + char ut_host[256]; + pid_t ut_pid; /* XXX: unsupported. */ + short ut_type; #define EMPTY 0 -#if 0 #define BOOT_TIME 1 -#endif #define OLD_TIME 2 #define NEW_TIME 3 #define USER_PROCESS 4 -#if 0 -#define INIT_PROCESS 5 -#define LOGIN_PROCESS 6 -#endif +#define INIT_PROCESS 5 /* XXX: unsupported. */ +#define LOGIN_PROCESS 6 /* XXX: unsupported. */ #define DEAD_PROCESS 7 - #define SHUTDOWN_TIME 8 -#define REBOOT_TIME 9 - struct timeval ut_tv; + struct timeval ut_tv; }; __BEGIN_DECLS +/* POSIX routines. */ void ulog_endutxent(void); struct ulog_utmpx *ulog_getutxent(void); #if 0 -struct ulog_utmpx *ulog_getutxid(const struct ulog_utmpx *id); -struct ulog_utmpx *ulog_getutxline(const struct ulog_utmpx *line); -struct ulog_utmpx *ulog_pututxline(const struct ulog_utmpx *utmpx); +struct ulog_utmpx *ulog_getutxid(const struct ulog_utmpx *); #endif +struct ulog_utmpx *ulog_getutxline(const struct ulog_utmpx *); +struct ulog_utmpx *ulog_pututxline(const struct ulog_utmpx *); void ulog_setutxent(void); +/* Extensions. */ +struct ulog_utmpx *ulog_getutxuser(const char *); +int ulog_setutxfile(int, const char *); +#define UTXF_UTMP 0 +#define UTXF_WTMP 1 +#define UTXF_LASTLOG 2 + +/* Login/logout utility functions. */ void ulog_login(const char *, const char *, const char *); void ulog_login_pseudo(int, const char *); void ulog_logout(const char *); void ulog_logout_pseudo(int); __END_DECLS +#ifdef _ULOG_POSIX_NAMES +#define utmpx ulog_utmpx +#define endutxent ulog_endutxent +#define getutxent ulog_getutxent +#define getutxline ulog_getutxline +#define pututxline ulog_pututxline +#define setutxent ulog_setutxent +#endif /* _ULOG_POSIX_NAMES */ + #endif /* !_ULOG_H_ */ Modified: head/lib/libulog/ulog_getutxent.3 ============================================================================== --- head/lib/libulog/ulog_getutxent.3 Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/ulog_getutxent.3 Sat Dec 5 19:53:29 2009 (r200153) @@ -24,11 +24,13 @@ .\" .\" $FreeBSD$ .\" -.Dd December 2, 2009 +.Dd December 5, 2009 .Os .Dt ULOG_GETUTXENT 3 .Sh NAME .Nm ulog_getutxent , +.Nm ulog_getutxline , +.Nm ulog_pututxline , .Nm ulog_setutxent , .Nm ulog_endutxent .Nd read user login records @@ -38,6 +40,10 @@ .In ulog.h .Ft struct ulog_utmpx * .Fn ulog_getutxent "void" +.Ft struct ulog_utmpx * +.Fn ulog_getutxline "const struct ulog_utmpx *line" +.Ft struct ulog_utmpx * +.Fn ulog_pututxline "const struct ulog_utmpx *utmpx" .Ft void .Fn ulog_setutxent "void" .Ft void @@ -49,10 +55,12 @@ function returns a pointer to an object, containing stored information of an active user login session. .Bd -literal struct ulog_utmpx { - char *ut_user; /* Username. */ - char *ut_line; /* TTY device. */ - char *ut_host; /* Remote hostname. */ - short ut_type; /* Type of entry. */ + char ut_user[]; /* Username. */ + char ut_id[]; /* Private data. */ + char ut_line[]; /* TTY device. */ + char ut_host[]; /* Remote hostname. */ + pid_t ut_pid; /* Process identifier. */ + short ut_type; /* Type of entry. */ struct timeval ut_tv; /* Timestamp. */ }; .Ed @@ -61,6 +69,9 @@ The fields are as follows: .Bl -tag -width ut_user .It Fa ut_user The username of the logged in user. +.It Fa ut_id +Private data that can be used to later identify the record. +This implementation is not capable of storing this value on disk. .It Fa ut_line The pathname of the TTY device, without the leading .Pa /dev/ @@ -68,6 +79,9 @@ directory. .It Fa ut_host An optional hostname of a remote system, if the login session is provided through a networked login service. +.It Fa ut_pid +Process identifier of the session leader of the login session. +This implementation is not capable of storing this value on disk. .It Fa ut_type The .Fa ut_type @@ -76,28 +90,42 @@ following values: .Bl -tag -width SHUTDOWN_TIME .It Dv EMPTY No valid user accounting information. +.It Dv BOOT_TIME +Identifies time of system boot. .It Dv OLD_TIME Identifies time when system clock changed. .It Dv NEW_TIME Identifies time after system clock changed. .It Dv USER_PROCESS Identifies a process. +.It Dv INIT_PROCESS +Identifies a process spawned by the init process. +.It Dv LOGIN_PROCESS +Identifies the session leader of a logged-in user. .It Dv DEAD_PROCESS Identifies a session leader who has exited. .It Dv SHUTDOWN_TIME Identifies time when system was shut down. -.It Dv REBOOT_TIME -Identifies time when system was rebooted. .El .It Fa ut_tv Timestamp indicating when the entry was last modified. .El .Pp +This implementation guarantees all strings returned in the structure to +be null terminated. +.Pp The .Fn ulog_getutxent function reads the next entry from the utmp file, opening the file if necessary. The +.Fn ulog_getutxline +function reads entries from the utmp file, until finding an entry which +shares the same +.Fa ut_line +as the structure +.Fa line . +The .Fn ulog_setutxent opens the file, closing it first if already opened. The @@ -106,15 +134,50 @@ function closes any open files. .Pp The .Fn ulog_getutxent -function reads from the beginning of the file until and EOF is +and +.Fn ulog_getutxline +functions read from the beginning of the file until and EOF is encountered. +.Pp +The +.Fn ulog_pututxline +function writes a new entry to the file. .Sh RETURN VALUES The .Fn ulog_getutxent -function returns a null pointer on EOF or error. +and +.Fn ulog_getutxline +functions return a null pointer on EOF or error. .Sh SEE ALSO .Xr ulog_login 3 , +.Xr ulog_setutxfile 3 , .Xr utmp 5 +.Sh STANDARDS +This interface is similar to +.In utmpx.h +described in +.St -p1003.1-2008 , +but incompatible. +The underlying file format does not allow a correctly behaving +implementation of the standardized interface. +.Pp +This programming interface has been designed to ease the migration +towards +.In utmpx.h . +If +.Dv _ULOG_POSIX_NAMES +is set before inclusion of +.In ulog.h , +it is also possible to use the +.Vt utmpx +structure and the +.Fn getutxent , +.Fn getutxline , +.Fn pututxline , +.Fn setutxent +and +.Fn endutxent +functions. .Sh HISTORY These functions appeared in .Fx 9.0 . Modified: head/lib/libulog/ulog_getutxent.c ============================================================================== --- head/lib/libulog/ulog_getutxent.c Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/ulog_getutxent.c Sat Dec 5 19:53:29 2009 (r200153) @@ -27,6 +27,9 @@ #include __FBSDID("$FreeBSD$"); +#include + +#include #include #include #include @@ -35,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include "ulog_internal.h" static FILE *ufile; +static int ufiletype = -1; void ulog_endutxent(void) @@ -44,56 +48,255 @@ ulog_endutxent(void) ufile = NULL; } -struct ulog_utmpx * -ulog_getutxent(void) -{ - struct futmp ut; - static struct ulog_utmpx utx; +/* + * Conversion from on-disk formats to generic ulog_utmpx structure. + */ - /* Open the utmp file if not already done so. */ - if (ufile == NULL) - ulog_setutxent(); - if (ufile == NULL) - return (NULL); +static void +ulog_futmp_to_utmpx(const struct futmp *ut, struct ulog_utmpx *utx) +{ - if (fread(&ut, sizeof ut, 1, ufile) != 1) - return (NULL); -#define COPY_STRING(field) do { \ - free(utx.ut_ ## field); \ - utx.ut_ ## field = strndup(ut.ut_ ## field, \ - sizeof ut.ut_ ## field); \ - if (utx.ut_ ## field == NULL) \ - utx.ut_ ## field = __DECONST(char *, ""); \ + memset(utx, 0, sizeof *utx); +#define COPY_STRING(field) do { \ + strncpy(utx->ut_ ## field, ut->ut_ ## field, \ + MIN(sizeof utx->ut_ ## field - 1, sizeof ut->ut_ ## field));\ } while (0) COPY_STRING(user); COPY_STRING(line); COPY_STRING(host); - utx.ut_tv.tv_sec = _time32_to_time(ut.ut_time); - utx.ut_tv.tv_usec = 0; -#define MATCH(field, value) (strcmp(utx.ut_ ## field, (value)) == 0) - if (MATCH(user, "date") && MATCH(line, "|")) - utx.ut_type = OLD_TIME; +#undef COPY_STRING +#define MATCH(field, value) (strcmp(utx->ut_ ## field, (value)) == 0) + if (MATCH(user, "reboot") && MATCH(line, "~")) + utx->ut_type = BOOT_TIME; + else if (MATCH(user, "date") && MATCH(line, "|")) + utx->ut_type = OLD_TIME; else if (MATCH(user, "date") && MATCH(line, "{")) - utx.ut_type = NEW_TIME; + utx->ut_type = NEW_TIME; else if (MATCH(user, "shutdown") && MATCH(line, "~")) - utx.ut_type = SHUTDOWN_TIME; - else if (MATCH(user, "reboot") && MATCH(line, "~")) - utx.ut_type = REBOOT_TIME; + utx->ut_type = SHUTDOWN_TIME; else if (MATCH(user, "") && MATCH(host, "")) - utx.ut_type = DEAD_PROCESS; - else if (!MATCH(user, "")) - utx.ut_type = USER_PROCESS; + utx->ut_type = DEAD_PROCESS; + else if (!MATCH(user, "") && !MATCH(line, "") && ut->ut_time != 0) + utx->ut_type = USER_PROCESS; + else + utx->ut_type = EMPTY; + utx->ut_tv.tv_sec = _time32_to_time(ut->ut_time); + utx->ut_tv.tv_usec = 0; +} + +static void +ulog_flastlog_to_utmpx(const struct flastlog *ll, struct ulog_utmpx *utx) +{ + + memset(utx, 0, sizeof *utx); +#define COPY_STRING(field) do { \ + strncpy(utx->ut_ ## field, ll->ll_ ## field, \ + MIN(sizeof utx->ut_ ## field - 1, sizeof ll->ll_ ## field));\ +} while (0) + COPY_STRING(line); + COPY_STRING(host); +#undef COPY_STRING + if (!MATCH(line, "") && ll->ll_time != 0) + utx->ut_type = USER_PROCESS; else - utx.ut_type = EMPTY; - + utx->ut_type = EMPTY; + utx->ut_tv.tv_sec = _time32_to_time(ll->ll_time); + utx->ut_tv.tv_usec = 0; +} + +/* + * File I/O. + */ + +static inline off_t +ulog_tell(void) +{ + + if (ufiletype == UTXF_LASTLOG) + return (ftello(ufile) / sizeof(struct flastlog)); + else + return (ftello(ufile) / sizeof(struct futmp)); +} + +static struct ulog_utmpx * +ulog_read(off_t off, int whence, int resolve_user) +{ + static struct ulog_utmpx utx; + + if (ufile == NULL) + ulog_setutxent(); + if (ufile == NULL) + return (NULL); + + /* Only allow seeking to move forward. */ + if (whence == SEEK_SET && ulog_tell() > off) + return (NULL); + + if (ufiletype == UTXF_LASTLOG) { + struct flastlog ll; + struct passwd *pw = NULL; + uid_t uid; + + if (fseeko(ufile, off * sizeof ll, whence) != 0) + return (NULL); + uid = ulog_tell(); + if (fread(&ll, sizeof ll, 1, ufile) != 1) + return (NULL); + ulog_flastlog_to_utmpx(&ll, &utx); + if (utx.ut_type == USER_PROCESS && resolve_user) + pw = getpwuid(uid); + if (pw != NULL) + strlcpy(utx.ut_user, pw->pw_name, sizeof utx.ut_user); + else + sprintf(utx.ut_user, "%u", (unsigned int)uid); + } else { + struct futmp ut; + + if (fseeko(ufile, off * sizeof(struct futmp), whence) != 0) + return (NULL); + if (fread(&ut, sizeof ut, 1, ufile) != 1) + return (NULL); + ulog_futmp_to_utmpx(&ut, &utx); + } return (&utx); } -void -ulog_setutxent(void) +/* + * getutxent(). + * + * Read the next entry from the file. + */ + +struct ulog_utmpx * +ulog_getutxent(void) +{ + + return ulog_read(0, SEEK_CUR, 1); +} + +/* + * ulog_getutxline(). + * + * Read entries from the file, until reaching an entry which matches the + * provided TTY device name. We can optimize the case for utmp files, + * because they are indexed by TTY device name. + */ + +struct ulog_utmpx * +ulog_getutxline(const struct ulog_utmpx *line) { + struct ulog_utmpx *utx; + + if (ufile == NULL) + ulog_setutxent(); + if (ufile == NULL) + return (NULL); + + if (ufiletype == UTXF_UTMP) { + unsigned int slot; + + slot = ulog_ttyslot(line->ut_line); + if (slot == 0) + return (NULL); + utx = ulog_read(slot, SEEK_SET, 1); + if (utx->ut_type == USER_PROCESS && + strcmp(utx->ut_line, line->ut_line) == 0) + return (utx); + return (NULL); + } else { + for (;;) { + utx = ulog_read(0, SEEK_CUR, 1); + if (utx == NULL) + return (NULL); + if (utx->ut_type == USER_PROCESS && + strcmp(utx->ut_line, line->ut_line) == 0) + return (utx); + } + } +} + +/* + * ulog_getutxuser(). + * + * Read entries from the file, until reaching an entry which matches the + * provided username. We can optimize the case for lastlog files, + * because they are indexed by user ID. + */ + +struct ulog_utmpx * +ulog_getutxuser(const char *user) +{ + struct ulog_utmpx *utx; + + if (ufiletype == UTXF_LASTLOG) { + struct passwd *pw; + + pw = getpwnam(user); + if (pw == NULL) + return (NULL); + utx = ulog_read(pw->pw_uid, SEEK_SET, 0); + if (utx != NULL) + strlcpy(utx->ut_user, user, sizeof utx->ut_user); + return (utx); + } else { + for (;;) { + utx = ulog_read(0, SEEK_CUR, 1); + if (utx == NULL) + return (NULL); + if (utx->ut_type == USER_PROCESS && + strcmp(utx->ut_user, user) == 0) + return (utx); + } + } +} + +/* + * ulog_setutxfile(). + * + * Switch to a different record file. When no filename is provided, the + * system default is opened. + */ + +int +ulog_setutxfile(int type, const char *file) +{ + + /* Supply default files. */ + switch (type) { + case UTXF_UTMP: + if (file == NULL) + file = _PATH_UTMP; + break; + case UTXF_WTMP: + if (file == NULL) + file = _PATH_WTMP; + break; + case UTXF_LASTLOG: + if (file == NULL) + file = _PATH_LASTLOG; + break; + default: + return (-1); + } if (ufile != NULL) fclose(ufile); - ufile = fopen(_PATH_UTMP, "r"); + ufile = fopen(file, "r"); + ufiletype = type; + if (ufile == NULL) + return (-1); + return (0); +} + +/* + * ulog_endutxfile(). + * + * Close any opened files. + */ + +void +ulog_setutxent(void) +{ + + ulog_setutxfile(UTXF_UTMP, NULL); } Modified: head/lib/libulog/ulog_internal.h ============================================================================== --- head/lib/libulog/ulog_internal.h Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/ulog_internal.h Sat Dec 5 19:53:29 2009 (r200153) @@ -33,6 +33,8 @@ #include "ulog.h" +unsigned int ulog_ttyslot(const char *); + /* * On-disk format. */ Modified: head/lib/libulog/ulog_login.3 ============================================================================== --- head/lib/libulog/ulog_login.3 Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/ulog_login.3 Sat Dec 5 19:53:29 2009 (r200153) @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 2, 2009 +.Dd December 5, 2009 .Os .Dt ULOG_LOGIN 3 .Sh NAME Modified: head/lib/libulog/ulog_login.c ============================================================================== --- head/lib/libulog/ulog_login.c Sat Dec 5 19:44:16 2009 (r200152) +++ head/lib/libulog/ulog_login.c Sat Dec 5 19:53:29 2009 (r200153) @@ -27,109 +27,48 @@ #include __FBSDID("$FreeBSD$"); -#include -#include +#include #include -#include #include -#include -#include -#include -#include #include "ulog_internal.h" void ulog_login(const char *line, const char *user, const char *host) { - struct futmp fu; - struct flastlog fl; - int fd; + struct ulog_utmpx utx; /* Remove /dev/ component. */ if (strncmp(line, _PATH_DEV, sizeof _PATH_DEV - 1) == 0) line += sizeof _PATH_DEV - 1; - /* Prepare log entries. */ - memset(&fu, 0, sizeof fu); - strlcpy(fu.ut_line, line, sizeof fu.ut_line); - strlcpy(fu.ut_user, user, sizeof fu.ut_user); - if (host != NULL) - strlcpy(fu.ut_host, host, sizeof fu.ut_host); - fu.ut_time = _time_to_time32(time(NULL)); - - fl.ll_time = fu.ut_time; - memcpy(fl.ll_line, fu.ut_line, sizeof fl.ll_line); - memcpy(fl.ll_host, fu.ut_host, sizeof fl.ll_host); - - /* Update utmp entry. */ - if ((fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) { - struct ttyent *ty; - int idx; - - setttyent(); - for (idx = 1; (ty = getttyent()) != NULL; ++idx) { - if (strcmp(ty->ty_name, line) != 0) - continue; - lseek(fd, (off_t)(idx * sizeof fu), L_SET); - write(fd, &fu, sizeof fu); - break; - } - endttyent(); - close(fd); - } - - /* Add wtmp entry. */ - if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { - write(fd, &fu, sizeof fu); - close(fd); - } - - /* Update lastlog entry. */ - if ((fd = open(_PATH_LASTLOG, O_WRONLY, 0)) >= 0) { - struct passwd *pw; - - pw = getpwnam(user); - if (pw != NULL) { - lseek(fd, (off_t)(pw->pw_uid * sizeof fl), L_SET); - write(fd, &fl, sizeof fl); - } - close(fd); - } + memset(&utx, 0, sizeof utx); + + /* XXX: ut_id, ut_pid missing. */ + utx.ut_type = USER_PROCESS; + strncpy(utx.ut_line, line, sizeof utx.ut_line); + strncpy(utx.ut_user, user, sizeof utx.ut_user); + strncpy(utx.ut_host, host, sizeof utx.ut_host); + gettimeofday(&utx.ut_tv, NULL); + + ulog_pututxline(&utx); } void ulog_logout(const char *line) { - struct futmp ut; - int fd, found; + struct ulog_utmpx utx; /* Remove /dev/ component. */ if (strncmp(line, _PATH_DEV, sizeof _PATH_DEV - 1) == 0) line += sizeof _PATH_DEV - 1; - /* Mark entry in utmp as logged out. */ - if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0) - return; - found = 0; - while (read(fd, &ut, sizeof ut) == sizeof ut) { - if (ut.ut_user[0] == '\0' || - strncmp(ut.ut_line, line, sizeof ut.ut_line) != 0) - continue; - memset(ut.ut_user, 0, sizeof ut.ut_user); - memset(ut.ut_host, 0, sizeof ut.ut_host); - ut.ut_time = _time_to_time32(time(NULL)); - lseek(fd, -(off_t)sizeof ut, L_INCR); - write(fd, &ut, sizeof ut); - found = 1; - } - close(fd); - if (!found) - return; - - /* utmp entry found. Also add logout entry to wtmp. */ - if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { - write(fd, &ut, sizeof ut); - close(fd); - } + memset(&utx, 0, sizeof utx); + + /* XXX: ut_id, ut_pid missing. ut_line not needed */ + utx.ut_type = DEAD_PROCESS; + strncpy(utx.ut_line, line, sizeof utx.ut_line); + gettimeofday(&utx.ut_tv, NULL); + + ulog_pututxline(&utx); } Added: head/lib/libulog/ulog_pututxline.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libulog/ulog_pututxline.c Sat Dec 5 19:53:29 2009 (r200153) @@ -0,0 +1,208 @@ +/*- + * Copyright (c) 2009 Ed Schouten + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include "ulog_internal.h" + +static void +ulog_utmpx_to_futmp(const struct ulog_utmpx *utx, struct futmp *ut) +{ + + memset(ut, 0, sizeof *ut); +#define COPY_STRING(field) do { \ + strncpy(ut->ut_ ## field, utx->ut_ ## field, \ + MIN(sizeof ut->ut_ ## field, sizeof utx->ut_ ## field)); \ +} while (0) + switch (utx->ut_type) { + case BOOT_TIME: + strcpy(ut->ut_user, "reboot"); + ut->ut_line[0] = '~'; + break; + case OLD_TIME: + strcpy(ut->ut_user, "date"); + ut->ut_line[0] = '|'; + break; + case NEW_TIME: + strcpy(ut->ut_user, "date"); + ut->ut_line[0] = '{'; + break; + case USER_PROCESS: + COPY_STRING(user); + COPY_STRING(line); + COPY_STRING(host); + break; + case DEAD_PROCESS: + COPY_STRING(line); + break; + case SHUTDOWN_TIME: + strcpy(ut->ut_user, "shutdown"); + ut->ut_line[0] = '~'; + break; + } +#undef COPY_STRING + ut->ut_time = _time_to_time32(utx->ut_tv.tv_sec); +} + +static void +ulog_utmpx_to_flastlog(const struct ulog_utmpx *utx, struct flastlog *ll) +{ + + memset(ll, 0, sizeof *ll); +#define COPY_STRING(field) do { \ + strncpy(ll->ll_ ## field, utx->ut_ ## field, \ + MIN(sizeof ll->ll_ ## field, sizeof utx->ut_ ## field)); \ +} while (0) + switch (utx->ut_type) { + case USER_PROCESS: + COPY_STRING(line); + COPY_STRING(host); + break; + } +#undef COPY_STRING + ll->ll_time = _time_to_time32(utx->ut_tv.tv_sec); +} + +static void +ulog_write_utmp_fast(const struct futmp *ut) +{ + unsigned int idx; + char line[sizeof ut->ut_line + 1]; + int fd; + + if ((fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) < 0) + return; + strlcpy(line, ut->ut_line, sizeof line); + idx = ulog_ttyslot(line); + if (idx > 0) { + lseek(fd, (off_t)(idx * sizeof *ut), SEEK_SET); + write(fd, ut, sizeof *ut); + } + close(fd); +} + +static int +ulog_write_utmp_slow(const struct futmp *ut) +{ + struct futmp utf; + int fd, found; + + if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0) + return (0); + found = 0; + while (read(fd, &utf, sizeof utf) == sizeof utf) { + if (utf.ut_user[0] == '\0' || + strncmp(utf.ut_line, ut->ut_line, sizeof utf.ut_line) != 0) + continue; + lseek(fd, -(off_t)sizeof utf, SEEK_CUR); + write(fd, &ut, sizeof ut); + found = 1; + } + close(fd); + return (found); +} + +static void +ulog_write_wtmp(const struct futmp *ut) +{ + int fd; + + if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) + return; + write(fd, ut, sizeof *ut); + close(fd); +} + +static void +ulog_write_lastlog(const struct flastlog *ll, const char *user) +{ + struct passwd *pw; + int fd; + + if ((fd = open(_PATH_LASTLOG, O_WRONLY, 0)) < 0) + return; + pw = getpwnam(user); + if (pw != NULL) { + lseek(fd, (off_t)(pw->pw_uid * sizeof *ll), SEEK_SET); + write(fd, ll, sizeof *ll); + } + close(fd); +} + +struct ulog_utmpx * +ulog_pututxline(const struct ulog_utmpx *utmpx) +{ + static struct ulog_utmpx utx; + struct futmp ut; + struct flastlog ll; + char user[sizeof utmpx->ut_user + 1]; + + switch (utmpx->ut_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + case SHUTDOWN_TIME: + ulog_utmpx_to_futmp(utmpx, &ut); + + /* Only log to wtmp. */ + ulog_write_wtmp(&ut); + break; + case USER_PROCESS: + ulog_utmpx_to_futmp(utmpx, &ut); + ulog_utmpx_to_flastlog(utmpx, &ll); + + /* Log to utmp, wtmp and lastlog. */ + ulog_write_utmp_fast(&ut); + ulog_write_wtmp(&ut); + strlcpy(user, utmpx->ut_user, sizeof user); + ulog_write_lastlog(&ll, user); + break; + case DEAD_PROCESS: + ulog_utmpx_to_futmp(utmpx, &ut); + + /* Only log to wtmp if logged in utmp. */ + if (ulog_write_utmp_slow(&ut)) + ulog_write_wtmp(&ut); + break; + default: + return (NULL); + } + + /* XXX: Can't we just return utmpx itself? */ + memcpy(&utx, utmpx, sizeof utx); + utx.ut_user[sizeof utx.ut_user - 1] = '\0'; + utx.ut_line[sizeof utx.ut_line - 1] = '\0'; + utx.ut_host[sizeof utx.ut_host - 1] = '\0'; + return (&utx); +} Added: head/lib/libulog/ulog_setutxfile.3 ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libulog/ulog_setutxfile.3 Sat Dec 5 19:53:29 2009 (r200153) @@ -0,0 +1,94 @@ +.\" Copyright (c) 2009 Ed Schouten +.\" All rights reserved. *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***