183d2307dSDag-Erling Smørgrav /* 283d2307dSDag-Erling Smørgrav * Copyright (c) 2000 Andre Lucas. All rights reserved. 383d2307dSDag-Erling Smørgrav * Portions copyright (c) 1998 Todd C. Miller 483d2307dSDag-Erling Smørgrav * Portions copyright (c) 1996 Jason Downs 583d2307dSDag-Erling Smørgrav * Portions copyright (c) 1996 Theo de Raadt 683d2307dSDag-Erling Smørgrav * 783d2307dSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 883d2307dSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 983d2307dSDag-Erling Smørgrav * are met: 1083d2307dSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 1183d2307dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 1283d2307dSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 1383d2307dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 1483d2307dSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 1583d2307dSDag-Erling Smørgrav * 3. All advertising materials mentioning features or use of this software 1683d2307dSDag-Erling Smørgrav * must display the following acknowledgement: 1783d2307dSDag-Erling Smørgrav * This product includes software developed by Markus Friedl. 1883d2307dSDag-Erling Smørgrav * 4. The name of the author may not be used to endorse or promote products 1983d2307dSDag-Erling Smørgrav * derived from this software without specific prior written permission. 2083d2307dSDag-Erling Smørgrav * 2183d2307dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2283d2307dSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2383d2307dSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2483d2307dSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2583d2307dSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2683d2307dSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2783d2307dSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2883d2307dSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2983d2307dSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3083d2307dSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3183d2307dSDag-Erling Smørgrav */ 3283d2307dSDag-Erling Smørgrav 3383d2307dSDag-Erling Smørgrav /** 3483d2307dSDag-Erling Smørgrav ** loginrec.c: platform-independent login recording and lastlog retrieval 3583d2307dSDag-Erling Smørgrav **/ 3683d2307dSDag-Erling Smørgrav 3783d2307dSDag-Erling Smørgrav /* 3883d2307dSDag-Erling Smørgrav The new login code explained 3983d2307dSDag-Erling Smørgrav ============================ 4083d2307dSDag-Erling Smørgrav 4183d2307dSDag-Erling Smørgrav This code attempts to provide a common interface to login recording 4283d2307dSDag-Erling Smørgrav (utmp and friends) and last login time retrieval. 4383d2307dSDag-Erling Smørgrav 4483d2307dSDag-Erling Smørgrav Its primary means of achieving this is to use 'struct logininfo', a 4583d2307dSDag-Erling Smørgrav union of all the useful fields in the various different types of 4683d2307dSDag-Erling Smørgrav system login record structures one finds on UNIX variants. 4783d2307dSDag-Erling Smørgrav 4883d2307dSDag-Erling Smørgrav We depend on autoconf to define which recording methods are to be 4983d2307dSDag-Erling Smørgrav used, and which fields are contained in the relevant data structures 5083d2307dSDag-Erling Smørgrav on the local system. Many C preprocessor symbols affect which code 5183d2307dSDag-Erling Smørgrav gets compiled here. 5283d2307dSDag-Erling Smørgrav 5383d2307dSDag-Erling Smørgrav The code is designed to make it easy to modify a particular 5483d2307dSDag-Erling Smørgrav recording method, without affecting other methods nor requiring so 5583d2307dSDag-Erling Smørgrav many nested conditional compilation blocks as were commonplace in 5683d2307dSDag-Erling Smørgrav the old code. 5783d2307dSDag-Erling Smørgrav 5883d2307dSDag-Erling Smørgrav For login recording, we try to use the local system's libraries as 5983d2307dSDag-Erling Smørgrav these are clearly most likely to work correctly. For utmp systems 6083d2307dSDag-Erling Smørgrav this usually means login() and logout() or setutent() etc., probably 6183d2307dSDag-Erling Smørgrav in libutil, along with logwtmp() etc. On these systems, we fall back 6283d2307dSDag-Erling Smørgrav to writing the files directly if we have to, though this method 6383d2307dSDag-Erling Smørgrav requires very thorough testing so we do not corrupt local auditing 6483d2307dSDag-Erling Smørgrav information. These files and their access methods are very system 6583d2307dSDag-Erling Smørgrav specific indeed. 6683d2307dSDag-Erling Smørgrav 6783d2307dSDag-Erling Smørgrav For utmpx systems, the corresponding library functions are 6883d2307dSDag-Erling Smørgrav setutxent() etc. To the author's knowledge, all utmpx systems have 6983d2307dSDag-Erling Smørgrav these library functions and so no direct write is attempted. If such 7083d2307dSDag-Erling Smørgrav a system exists and needs support, direct analogues of the [uw]tmp 7183d2307dSDag-Erling Smørgrav code should suffice. 7283d2307dSDag-Erling Smørgrav 7383d2307dSDag-Erling Smørgrav Retrieving the time of last login ('lastlog') is in some ways even 7483d2307dSDag-Erling Smørgrav more problemmatic than login recording. Some systems provide a 7583d2307dSDag-Erling Smørgrav simple table of all users which we seek based on uid and retrieve a 7683d2307dSDag-Erling Smørgrav relatively standard structure. Others record the same information in 7783d2307dSDag-Erling Smørgrav a directory with a separate file, and others don't record the 7883d2307dSDag-Erling Smørgrav information separately at all. For systems in the latter category, 7983d2307dSDag-Erling Smørgrav we look backwards in the wtmp or wtmpx file for the last login entry 8083d2307dSDag-Erling Smørgrav for our user. Naturally this is slower and on busy systems could 8183d2307dSDag-Erling Smørgrav incur a significant performance penalty. 8283d2307dSDag-Erling Smørgrav 8383d2307dSDag-Erling Smørgrav Calling the new code 8483d2307dSDag-Erling Smørgrav -------------------- 8583d2307dSDag-Erling Smørgrav 8683d2307dSDag-Erling Smørgrav In OpenSSH all login recording and retrieval is performed in 8783d2307dSDag-Erling Smørgrav login.c. Here you'll find working examples. Also, in the logintest.c 8883d2307dSDag-Erling Smørgrav program there are more examples. 8983d2307dSDag-Erling Smørgrav 9083d2307dSDag-Erling Smørgrav Internal handler calling method 9183d2307dSDag-Erling Smørgrav ------------------------------- 9283d2307dSDag-Erling Smørgrav 9383d2307dSDag-Erling Smørgrav When a call is made to login_login() or login_logout(), both 9483d2307dSDag-Erling Smørgrav routines set a struct logininfo flag defining which action (log in, 9583d2307dSDag-Erling Smørgrav or log out) is to be taken. They both then call login_write(), which 9683d2307dSDag-Erling Smørgrav calls whichever of the many structure-specific handlers autoconf 9783d2307dSDag-Erling Smørgrav selects for the local system. 9883d2307dSDag-Erling Smørgrav 9983d2307dSDag-Erling Smørgrav The handlers themselves handle system data structure specifics. Both 10083d2307dSDag-Erling Smørgrav struct utmp and struct utmpx have utility functions (see 10183d2307dSDag-Erling Smørgrav construct_utmp*()) to try to make it simpler to add extra systems 10283d2307dSDag-Erling Smørgrav that introduce new features to either structure. 10383d2307dSDag-Erling Smørgrav 10483d2307dSDag-Erling Smørgrav While it may seem terribly wasteful to replicate so much similar 10583d2307dSDag-Erling Smørgrav code for each method, experience has shown that maintaining code to 10683d2307dSDag-Erling Smørgrav write both struct utmp and utmpx in one function, whilst maintaining 10783d2307dSDag-Erling Smørgrav support for all systems whether they have library support or not, is 10883d2307dSDag-Erling Smørgrav a difficult and time-consuming task. 10983d2307dSDag-Erling Smørgrav 11083d2307dSDag-Erling Smørgrav Lastlog support proceeds similarly. Functions login_get_lastlog() 11183d2307dSDag-Erling Smørgrav (and its OpenSSH-tuned friend login_get_lastlog_time()) call 11283d2307dSDag-Erling Smørgrav getlast_entry(), which tries one of three methods to find the last 11383d2307dSDag-Erling Smørgrav login time. It uses local system lastlog support if it can, 11483d2307dSDag-Erling Smørgrav otherwise it tries wtmp or wtmpx before giving up and returning 0, 11583d2307dSDag-Erling Smørgrav meaning "tilt". 11683d2307dSDag-Erling Smørgrav 11783d2307dSDag-Erling Smørgrav Maintenance 11883d2307dSDag-Erling Smørgrav ----------- 11983d2307dSDag-Erling Smørgrav 12083d2307dSDag-Erling Smørgrav In many cases it's possible to tweak autoconf to select the correct 12183d2307dSDag-Erling Smørgrav methods for a particular platform, either by improving the detection 12283d2307dSDag-Erling Smørgrav code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE 12383d2307dSDag-Erling Smørgrav symbols for the platform. 12483d2307dSDag-Erling Smørgrav 12583d2307dSDag-Erling Smørgrav Use logintest to check which symbols are defined before modifying 12683d2307dSDag-Erling Smørgrav configure.ac and loginrec.c. (You have to build logintest yourself 12783d2307dSDag-Erling Smørgrav with 'make logintest' as it's not built by default.) 12883d2307dSDag-Erling Smørgrav 12983d2307dSDag-Erling Smørgrav Otherwise, patches to the specific method(s) are very helpful! 13083d2307dSDag-Erling Smørgrav 13183d2307dSDag-Erling Smørgrav */ 13283d2307dSDag-Erling Smørgrav 13383d2307dSDag-Erling Smørgrav /** 13483d2307dSDag-Erling Smørgrav ** TODO: 13583d2307dSDag-Erling Smørgrav ** homegrown ttyslot() 13683d2307dSDag-Erling Smørgrav ** test, test, test 13783d2307dSDag-Erling Smørgrav ** 13883d2307dSDag-Erling Smørgrav ** Platform status: 13983d2307dSDag-Erling Smørgrav ** ---------------- 14083d2307dSDag-Erling Smørgrav ** 14183d2307dSDag-Erling Smørgrav ** Known good: 14283d2307dSDag-Erling Smørgrav ** Linux (Redhat 6.2, Debian) 14383d2307dSDag-Erling Smørgrav ** Solaris 14483d2307dSDag-Erling Smørgrav ** HP-UX 10.20 (gcc only) 14583d2307dSDag-Erling Smørgrav ** IRIX 14683d2307dSDag-Erling Smørgrav ** NeXT - M68k/HPPA/Sparc (4.2/3.3) 14783d2307dSDag-Erling Smørgrav ** 14883d2307dSDag-Erling Smørgrav ** Testing required: Please send reports! 14983d2307dSDag-Erling Smørgrav ** NetBSD 15083d2307dSDag-Erling Smørgrav ** HP-UX 11 15183d2307dSDag-Erling Smørgrav ** AIX 15283d2307dSDag-Erling Smørgrav ** 15383d2307dSDag-Erling Smørgrav ** Platforms with known problems: 15483d2307dSDag-Erling Smørgrav ** Some variants of Slackware Linux 15583d2307dSDag-Erling Smørgrav ** 15683d2307dSDag-Erling Smørgrav **/ 15783d2307dSDag-Erling Smørgrav 15883d2307dSDag-Erling Smørgrav #include "includes.h" 15983d2307dSDag-Erling Smørgrav 16083d2307dSDag-Erling Smørgrav #include "ssh.h" 16183d2307dSDag-Erling Smørgrav #include "xmalloc.h" 16283d2307dSDag-Erling Smørgrav #include "loginrec.h" 16383d2307dSDag-Erling Smørgrav #include "log.h" 16483d2307dSDag-Erling Smørgrav #include "atomicio.h" 16583d2307dSDag-Erling Smørgrav 166e73e9afaSDag-Erling Smørgrav RCSID("$Id: loginrec.c,v 1.47 2003/03/10 00:23:07 djm Exp $"); 167a9f7d76bSDag-Erling Smørgrav RCSID("$FreeBSD$"); 16883d2307dSDag-Erling Smørgrav 16983d2307dSDag-Erling Smørgrav #ifdef HAVE_UTIL_H 17083d2307dSDag-Erling Smørgrav # include <util.h> 17183d2307dSDag-Erling Smørgrav #endif 17283d2307dSDag-Erling Smørgrav 17383d2307dSDag-Erling Smørgrav #ifdef HAVE_LIBUTIL_H 17483d2307dSDag-Erling Smørgrav # include <libutil.h> 17583d2307dSDag-Erling Smørgrav #endif 17683d2307dSDag-Erling Smørgrav 17783d2307dSDag-Erling Smørgrav /** 17883d2307dSDag-Erling Smørgrav ** prototypes for helper functions in this file 17983d2307dSDag-Erling Smørgrav **/ 18083d2307dSDag-Erling Smørgrav 18183d2307dSDag-Erling Smørgrav #if HAVE_UTMP_H 18283d2307dSDag-Erling Smørgrav void set_utmp_time(struct logininfo *li, struct utmp *ut); 18383d2307dSDag-Erling Smørgrav void construct_utmp(struct logininfo *li, struct utmp *ut); 18483d2307dSDag-Erling Smørgrav #endif 18583d2307dSDag-Erling Smørgrav 18683d2307dSDag-Erling Smørgrav #ifdef HAVE_UTMPX_H 18783d2307dSDag-Erling Smørgrav void set_utmpx_time(struct logininfo *li, struct utmpx *ut); 18883d2307dSDag-Erling Smørgrav void construct_utmpx(struct logininfo *li, struct utmpx *ut); 18983d2307dSDag-Erling Smørgrav #endif 19083d2307dSDag-Erling Smørgrav 19183d2307dSDag-Erling Smørgrav int utmp_write_entry(struct logininfo *li); 19283d2307dSDag-Erling Smørgrav int utmpx_write_entry(struct logininfo *li); 19383d2307dSDag-Erling Smørgrav int wtmp_write_entry(struct logininfo *li); 19483d2307dSDag-Erling Smørgrav int wtmpx_write_entry(struct logininfo *li); 19583d2307dSDag-Erling Smørgrav int lastlog_write_entry(struct logininfo *li); 19683d2307dSDag-Erling Smørgrav int syslogin_write_entry(struct logininfo *li); 19783d2307dSDag-Erling Smørgrav 19883d2307dSDag-Erling Smørgrav int getlast_entry(struct logininfo *li); 19983d2307dSDag-Erling Smørgrav int lastlog_get_entry(struct logininfo *li); 20083d2307dSDag-Erling Smørgrav int wtmp_get_entry(struct logininfo *li); 20183d2307dSDag-Erling Smørgrav int wtmpx_get_entry(struct logininfo *li); 20283d2307dSDag-Erling Smørgrav 20383d2307dSDag-Erling Smørgrav /* pick the shortest string */ 20483d2307dSDag-Erling Smørgrav #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) ) 20583d2307dSDag-Erling Smørgrav 20683d2307dSDag-Erling Smørgrav /** 20783d2307dSDag-Erling Smørgrav ** platform-independent login functions 20883d2307dSDag-Erling Smørgrav **/ 20983d2307dSDag-Erling Smørgrav 21083d2307dSDag-Erling Smørgrav /* login_login(struct logininfo *) -Record a login 21183d2307dSDag-Erling Smørgrav * 21283d2307dSDag-Erling Smørgrav * Call with a pointer to a struct logininfo initialised with 21383d2307dSDag-Erling Smørgrav * login_init_entry() or login_alloc_entry() 21483d2307dSDag-Erling Smørgrav * 21583d2307dSDag-Erling Smørgrav * Returns: 21683d2307dSDag-Erling Smørgrav * >0 if successful 21783d2307dSDag-Erling Smørgrav * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 21883d2307dSDag-Erling Smørgrav */ 21983d2307dSDag-Erling Smørgrav int 22083d2307dSDag-Erling Smørgrav login_login (struct logininfo *li) 22183d2307dSDag-Erling Smørgrav { 22283d2307dSDag-Erling Smørgrav li->type = LTYPE_LOGIN; 22383d2307dSDag-Erling Smørgrav return login_write(li); 22483d2307dSDag-Erling Smørgrav } 22583d2307dSDag-Erling Smørgrav 22683d2307dSDag-Erling Smørgrav 22783d2307dSDag-Erling Smørgrav /* login_logout(struct logininfo *) - Record a logout 22883d2307dSDag-Erling Smørgrav * 22983d2307dSDag-Erling Smørgrav * Call as with login_login() 23083d2307dSDag-Erling Smørgrav * 23183d2307dSDag-Erling Smørgrav * Returns: 23283d2307dSDag-Erling Smørgrav * >0 if successful 23383d2307dSDag-Erling Smørgrav * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 23483d2307dSDag-Erling Smørgrav */ 23583d2307dSDag-Erling Smørgrav int 23683d2307dSDag-Erling Smørgrav login_logout(struct logininfo *li) 23783d2307dSDag-Erling Smørgrav { 23883d2307dSDag-Erling Smørgrav li->type = LTYPE_LOGOUT; 23983d2307dSDag-Erling Smørgrav return login_write(li); 24083d2307dSDag-Erling Smørgrav } 24183d2307dSDag-Erling Smørgrav 24283d2307dSDag-Erling Smørgrav /* login_get_lastlog_time(int) - Retrieve the last login time 24383d2307dSDag-Erling Smørgrav * 24483d2307dSDag-Erling Smørgrav * Retrieve the last login time for the given uid. Will try to use the 24583d2307dSDag-Erling Smørgrav * system lastlog facilities if they are available, but will fall back 24683d2307dSDag-Erling Smørgrav * to looking in wtmp/wtmpx if necessary 24783d2307dSDag-Erling Smørgrav * 24883d2307dSDag-Erling Smørgrav * Returns: 24983d2307dSDag-Erling Smørgrav * 0 on failure, or if user has never logged in 25083d2307dSDag-Erling Smørgrav * Time in seconds from the epoch if successful 25183d2307dSDag-Erling Smørgrav * 25283d2307dSDag-Erling Smørgrav * Useful preprocessor symbols: 25383d2307dSDag-Erling Smørgrav * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog 25483d2307dSDag-Erling Smørgrav * info 25583d2307dSDag-Erling Smørgrav * USE_LASTLOG: If set, indicates the presence of system lastlog 25683d2307dSDag-Erling Smørgrav * facilities. If this and DISABLE_LASTLOG are not set, 25783d2307dSDag-Erling Smørgrav * try to retrieve lastlog information from wtmp/wtmpx. 25883d2307dSDag-Erling Smørgrav */ 25983d2307dSDag-Erling Smørgrav unsigned int 26083d2307dSDag-Erling Smørgrav login_get_lastlog_time(const int uid) 26183d2307dSDag-Erling Smørgrav { 26283d2307dSDag-Erling Smørgrav struct logininfo li; 26383d2307dSDag-Erling Smørgrav 26483d2307dSDag-Erling Smørgrav if (login_get_lastlog(&li, uid)) 26583d2307dSDag-Erling Smørgrav return li.tv_sec; 26683d2307dSDag-Erling Smørgrav else 26783d2307dSDag-Erling Smørgrav return 0; 26883d2307dSDag-Erling Smørgrav } 26983d2307dSDag-Erling Smørgrav 27083d2307dSDag-Erling Smørgrav /* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry 27183d2307dSDag-Erling Smørgrav * 27283d2307dSDag-Erling Smørgrav * Retrieve a logininfo structure populated (only partially) with 27383d2307dSDag-Erling Smørgrav * information from the system lastlog data, or from wtmp/wtmpx if no 27483d2307dSDag-Erling Smørgrav * system lastlog information exists. 27583d2307dSDag-Erling Smørgrav * 27683d2307dSDag-Erling Smørgrav * Note this routine must be given a pre-allocated logininfo. 27783d2307dSDag-Erling Smørgrav * 27883d2307dSDag-Erling Smørgrav * Returns: 27983d2307dSDag-Erling Smørgrav * >0: A pointer to your struct logininfo if successful 28083d2307dSDag-Erling Smørgrav * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 28183d2307dSDag-Erling Smørgrav * 28283d2307dSDag-Erling Smørgrav */ 28383d2307dSDag-Erling Smørgrav struct logininfo * 28483d2307dSDag-Erling Smørgrav login_get_lastlog(struct logininfo *li, const int uid) 28583d2307dSDag-Erling Smørgrav { 28683d2307dSDag-Erling Smørgrav struct passwd *pw; 28783d2307dSDag-Erling Smørgrav 28883d2307dSDag-Erling Smørgrav memset(li, '\0', sizeof(*li)); 28983d2307dSDag-Erling Smørgrav li->uid = uid; 29083d2307dSDag-Erling Smørgrav 29183d2307dSDag-Erling Smørgrav /* 29283d2307dSDag-Erling Smørgrav * If we don't have a 'real' lastlog, we need the username to 29383d2307dSDag-Erling Smørgrav * reliably search wtmp(x) for the last login (see 29483d2307dSDag-Erling Smørgrav * wtmp_get_entry().) 29583d2307dSDag-Erling Smørgrav */ 29683d2307dSDag-Erling Smørgrav pw = getpwuid(uid); 29783d2307dSDag-Erling Smørgrav if (pw == NULL) 29883d2307dSDag-Erling Smørgrav fatal("login_get_lastlog: Cannot find account for uid %i", uid); 29983d2307dSDag-Erling Smørgrav 30083d2307dSDag-Erling Smørgrav /* No MIN_SIZEOF here - we absolutely *must not* truncate the 30183d2307dSDag-Erling Smørgrav * username */ 30283d2307dSDag-Erling Smørgrav strlcpy(li->username, pw->pw_name, sizeof(li->username)); 30383d2307dSDag-Erling Smørgrav 30483d2307dSDag-Erling Smørgrav if (getlast_entry(li)) 30583d2307dSDag-Erling Smørgrav return li; 30683d2307dSDag-Erling Smørgrav else 30783d2307dSDag-Erling Smørgrav return NULL; 30883d2307dSDag-Erling Smørgrav } 30983d2307dSDag-Erling Smørgrav 31083d2307dSDag-Erling Smørgrav 31183d2307dSDag-Erling Smørgrav /* login_alloc_entry(int, char*, char*, char*) - Allocate and initialise 31283d2307dSDag-Erling Smørgrav * a logininfo structure 31383d2307dSDag-Erling Smørgrav * 31483d2307dSDag-Erling Smørgrav * This function creates a new struct logininfo, a data structure 31583d2307dSDag-Erling Smørgrav * meant to carry the information required to portably record login info. 31683d2307dSDag-Erling Smørgrav * 31783d2307dSDag-Erling Smørgrav * Returns a pointer to a newly created struct logininfo. If memory 31883d2307dSDag-Erling Smørgrav * allocation fails, the program halts. 31983d2307dSDag-Erling Smørgrav */ 32083d2307dSDag-Erling Smørgrav struct 32183d2307dSDag-Erling Smørgrav logininfo *login_alloc_entry(int pid, const char *username, 32283d2307dSDag-Erling Smørgrav const char *hostname, const char *line) 32383d2307dSDag-Erling Smørgrav { 32483d2307dSDag-Erling Smørgrav struct logininfo *newli; 32583d2307dSDag-Erling Smørgrav 32683d2307dSDag-Erling Smørgrav newli = (struct logininfo *) xmalloc (sizeof(*newli)); 32783d2307dSDag-Erling Smørgrav (void)login_init_entry(newli, pid, username, hostname, line); 32883d2307dSDag-Erling Smørgrav return newli; 32983d2307dSDag-Erling Smørgrav } 33083d2307dSDag-Erling Smørgrav 33183d2307dSDag-Erling Smørgrav 33283d2307dSDag-Erling Smørgrav /* login_free_entry(struct logininfo *) - free struct memory */ 33383d2307dSDag-Erling Smørgrav void 33483d2307dSDag-Erling Smørgrav login_free_entry(struct logininfo *li) 33583d2307dSDag-Erling Smørgrav { 33683d2307dSDag-Erling Smørgrav xfree(li); 33783d2307dSDag-Erling Smørgrav } 33883d2307dSDag-Erling Smørgrav 33983d2307dSDag-Erling Smørgrav 34083d2307dSDag-Erling Smørgrav /* login_init_entry(struct logininfo *, int, char*, char*, char*) 34183d2307dSDag-Erling Smørgrav * - initialise a struct logininfo 34283d2307dSDag-Erling Smørgrav * 34383d2307dSDag-Erling Smørgrav * Populates a new struct logininfo, a data structure meant to carry 34483d2307dSDag-Erling Smørgrav * the information required to portably record login info. 34583d2307dSDag-Erling Smørgrav * 34683d2307dSDag-Erling Smørgrav * Returns: 1 34783d2307dSDag-Erling Smørgrav */ 34883d2307dSDag-Erling Smørgrav int 34983d2307dSDag-Erling Smørgrav login_init_entry(struct logininfo *li, int pid, const char *username, 35083d2307dSDag-Erling Smørgrav const char *hostname, const char *line) 35183d2307dSDag-Erling Smørgrav { 35283d2307dSDag-Erling Smørgrav struct passwd *pw; 35383d2307dSDag-Erling Smørgrav 35483d2307dSDag-Erling Smørgrav memset(li, 0, sizeof(*li)); 35583d2307dSDag-Erling Smørgrav 35683d2307dSDag-Erling Smørgrav li->pid = pid; 35783d2307dSDag-Erling Smørgrav 35883d2307dSDag-Erling Smørgrav /* set the line information */ 35983d2307dSDag-Erling Smørgrav if (line) 36083d2307dSDag-Erling Smørgrav line_fullname(li->line, line, sizeof(li->line)); 36183d2307dSDag-Erling Smørgrav 36283d2307dSDag-Erling Smørgrav if (username) { 36383d2307dSDag-Erling Smørgrav strlcpy(li->username, username, sizeof(li->username)); 36483d2307dSDag-Erling Smørgrav pw = getpwnam(li->username); 36583d2307dSDag-Erling Smørgrav if (pw == NULL) 36683d2307dSDag-Erling Smørgrav fatal("login_init_entry: Cannot find user \"%s\"", li->username); 36783d2307dSDag-Erling Smørgrav li->uid = pw->pw_uid; 36883d2307dSDag-Erling Smørgrav } 36983d2307dSDag-Erling Smørgrav 37083d2307dSDag-Erling Smørgrav if (hostname) 37183d2307dSDag-Erling Smørgrav strlcpy(li->hostname, hostname, sizeof(li->hostname)); 37283d2307dSDag-Erling Smørgrav 37383d2307dSDag-Erling Smørgrav return 1; 37483d2307dSDag-Erling Smørgrav } 37583d2307dSDag-Erling Smørgrav 37683d2307dSDag-Erling Smørgrav /* login_set_current_time(struct logininfo *) - set the current time 37783d2307dSDag-Erling Smørgrav * 37883d2307dSDag-Erling Smørgrav * Set the current time in a logininfo structure. This function is 37983d2307dSDag-Erling Smørgrav * meant to eliminate the need to deal with system dependencies for 38083d2307dSDag-Erling Smørgrav * time handling. 38183d2307dSDag-Erling Smørgrav */ 38283d2307dSDag-Erling Smørgrav void 38383d2307dSDag-Erling Smørgrav login_set_current_time(struct logininfo *li) 38483d2307dSDag-Erling Smørgrav { 38583d2307dSDag-Erling Smørgrav struct timeval tv; 38683d2307dSDag-Erling Smørgrav 38783d2307dSDag-Erling Smørgrav gettimeofday(&tv, NULL); 38883d2307dSDag-Erling Smørgrav 38983d2307dSDag-Erling Smørgrav li->tv_sec = tv.tv_sec; 39083d2307dSDag-Erling Smørgrav li->tv_usec = tv.tv_usec; 39183d2307dSDag-Erling Smørgrav } 39283d2307dSDag-Erling Smørgrav 39383d2307dSDag-Erling Smørgrav /* copy a sockaddr_* into our logininfo */ 39483d2307dSDag-Erling Smørgrav void 39583d2307dSDag-Erling Smørgrav login_set_addr(struct logininfo *li, const struct sockaddr *sa, 39683d2307dSDag-Erling Smørgrav const unsigned int sa_size) 39783d2307dSDag-Erling Smørgrav { 39883d2307dSDag-Erling Smørgrav unsigned int bufsize = sa_size; 39983d2307dSDag-Erling Smørgrav 40083d2307dSDag-Erling Smørgrav /* make sure we don't overrun our union */ 40183d2307dSDag-Erling Smørgrav if (sizeof(li->hostaddr) < sa_size) 40283d2307dSDag-Erling Smørgrav bufsize = sizeof(li->hostaddr); 40383d2307dSDag-Erling Smørgrav 40483d2307dSDag-Erling Smørgrav memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize); 40583d2307dSDag-Erling Smørgrav } 40683d2307dSDag-Erling Smørgrav 40783d2307dSDag-Erling Smørgrav 40883d2307dSDag-Erling Smørgrav /** 40983d2307dSDag-Erling Smørgrav ** login_write: Call low-level recording functions based on autoconf 41083d2307dSDag-Erling Smørgrav ** results 41183d2307dSDag-Erling Smørgrav **/ 41283d2307dSDag-Erling Smørgrav int 41383d2307dSDag-Erling Smørgrav login_write (struct logininfo *li) 41483d2307dSDag-Erling Smørgrav { 41583d2307dSDag-Erling Smørgrav #ifndef HAVE_CYGWIN 41683d2307dSDag-Erling Smørgrav if ((int)geteuid() != 0) { 41783d2307dSDag-Erling Smørgrav log("Attempt to write login records by non-root user (aborting)"); 41883d2307dSDag-Erling Smørgrav return 1; 41983d2307dSDag-Erling Smørgrav } 42083d2307dSDag-Erling Smørgrav #endif 42183d2307dSDag-Erling Smørgrav 42283d2307dSDag-Erling Smørgrav /* set the timestamp */ 42383d2307dSDag-Erling Smørgrav login_set_current_time(li); 42483d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN 42583d2307dSDag-Erling Smørgrav syslogin_write_entry(li); 42683d2307dSDag-Erling Smørgrav #endif 42783d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG 42883d2307dSDag-Erling Smørgrav if (li->type == LTYPE_LOGIN) { 42983d2307dSDag-Erling Smørgrav lastlog_write_entry(li); 43083d2307dSDag-Erling Smørgrav } 43183d2307dSDag-Erling Smørgrav #endif 43283d2307dSDag-Erling Smørgrav #ifdef USE_UTMP 43383d2307dSDag-Erling Smørgrav utmp_write_entry(li); 43483d2307dSDag-Erling Smørgrav #endif 43583d2307dSDag-Erling Smørgrav #ifdef USE_WTMP 43683d2307dSDag-Erling Smørgrav wtmp_write_entry(li); 43783d2307dSDag-Erling Smørgrav #endif 43883d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX 43983d2307dSDag-Erling Smørgrav utmpx_write_entry(li); 44083d2307dSDag-Erling Smørgrav #endif 44183d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX 44283d2307dSDag-Erling Smørgrav wtmpx_write_entry(li); 44383d2307dSDag-Erling Smørgrav #endif 44483d2307dSDag-Erling Smørgrav return 0; 44583d2307dSDag-Erling Smørgrav } 44683d2307dSDag-Erling Smørgrav 44783d2307dSDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX 44883d2307dSDag-Erling Smørgrav int 44983d2307dSDag-Erling Smørgrav login_utmp_only(struct logininfo *li) 45083d2307dSDag-Erling Smørgrav { 45183d2307dSDag-Erling Smørgrav li->type = LTYPE_LOGIN; 45283d2307dSDag-Erling Smørgrav login_set_current_time(li); 45383d2307dSDag-Erling Smørgrav # ifdef USE_UTMP 45483d2307dSDag-Erling Smørgrav utmp_write_entry(li); 45583d2307dSDag-Erling Smørgrav # endif 45683d2307dSDag-Erling Smørgrav # ifdef USE_WTMP 45783d2307dSDag-Erling Smørgrav wtmp_write_entry(li); 45883d2307dSDag-Erling Smørgrav # endif 45983d2307dSDag-Erling Smørgrav # ifdef USE_UTMPX 46083d2307dSDag-Erling Smørgrav utmpx_write_entry(li); 46183d2307dSDag-Erling Smørgrav # endif 46283d2307dSDag-Erling Smørgrav # ifdef USE_WTMPX 46383d2307dSDag-Erling Smørgrav wtmpx_write_entry(li); 46483d2307dSDag-Erling Smørgrav # endif 46583d2307dSDag-Erling Smørgrav return 0; 46683d2307dSDag-Erling Smørgrav } 46783d2307dSDag-Erling Smørgrav #endif 46883d2307dSDag-Erling Smørgrav 46983d2307dSDag-Erling Smørgrav /** 47083d2307dSDag-Erling Smørgrav ** getlast_entry: Call low-level functions to retrieve the last login 47183d2307dSDag-Erling Smørgrav ** time. 47283d2307dSDag-Erling Smørgrav **/ 47383d2307dSDag-Erling Smørgrav 47483d2307dSDag-Erling Smørgrav /* take the uid in li and return the last login time */ 47583d2307dSDag-Erling Smørgrav int 47683d2307dSDag-Erling Smørgrav getlast_entry(struct logininfo *li) 47783d2307dSDag-Erling Smørgrav { 47883d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG 47983d2307dSDag-Erling Smørgrav return(lastlog_get_entry(li)); 48083d2307dSDag-Erling Smørgrav #else /* !USE_LASTLOG */ 48183d2307dSDag-Erling Smørgrav 48283d2307dSDag-Erling Smørgrav #ifdef DISABLE_LASTLOG 48383d2307dSDag-Erling Smørgrav /* On some systems we shouldn't even try to obtain last login 48483d2307dSDag-Erling Smørgrav * time, e.g. AIX */ 48583d2307dSDag-Erling Smørgrav return 0; 48683d2307dSDag-Erling Smørgrav # else /* DISABLE_LASTLOG */ 48783d2307dSDag-Erling Smørgrav /* Try to retrieve the last login time from wtmp */ 48883d2307dSDag-Erling Smørgrav # if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) 48983d2307dSDag-Erling Smørgrav /* retrieve last login time from utmp */ 49083d2307dSDag-Erling Smørgrav return (wtmp_get_entry(li)); 49183d2307dSDag-Erling Smørgrav # else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */ 49283d2307dSDag-Erling Smørgrav /* If wtmp isn't available, try wtmpx */ 49383d2307dSDag-Erling Smørgrav # if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) 49483d2307dSDag-Erling Smørgrav /* retrieve last login time from utmpx */ 49583d2307dSDag-Erling Smørgrav return (wtmpx_get_entry(li)); 49683d2307dSDag-Erling Smørgrav # else 49783d2307dSDag-Erling Smørgrav /* Give up: No means of retrieving last login time */ 49883d2307dSDag-Erling Smørgrav return 0; 49983d2307dSDag-Erling Smørgrav # endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */ 50083d2307dSDag-Erling Smørgrav # endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */ 50183d2307dSDag-Erling Smørgrav # endif /* DISABLE_LASTLOG */ 50283d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */ 50383d2307dSDag-Erling Smørgrav } 50483d2307dSDag-Erling Smørgrav 50583d2307dSDag-Erling Smørgrav 50683d2307dSDag-Erling Smørgrav 50783d2307dSDag-Erling Smørgrav /* 50883d2307dSDag-Erling Smørgrav * 'line' string utility functions 50983d2307dSDag-Erling Smørgrav * 51083d2307dSDag-Erling Smørgrav * These functions process the 'line' string into one of three forms: 51183d2307dSDag-Erling Smørgrav * 51283d2307dSDag-Erling Smørgrav * 1. The full filename (including '/dev') 51383d2307dSDag-Erling Smørgrav * 2. The stripped name (excluding '/dev') 51483d2307dSDag-Erling Smørgrav * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00 51583d2307dSDag-Erling Smørgrav * /dev/pts/1 -> ts/1 ) 51683d2307dSDag-Erling Smørgrav * 51783d2307dSDag-Erling Smørgrav * Form 3 is used on some systems to identify a .tmp.? entry when 51883d2307dSDag-Erling Smørgrav * attempting to remove it. Typically both addition and removal is 51983d2307dSDag-Erling Smørgrav * performed by one application - say, sshd - so as long as the choice 52083d2307dSDag-Erling Smørgrav * uniquely identifies a terminal it's ok. 52183d2307dSDag-Erling Smørgrav */ 52283d2307dSDag-Erling Smørgrav 52383d2307dSDag-Erling Smørgrav 52483d2307dSDag-Erling Smørgrav /* line_fullname(): add the leading '/dev/' if it doesn't exist make 52583d2307dSDag-Erling Smørgrav * sure dst has enough space, if not just copy src (ugh) */ 52683d2307dSDag-Erling Smørgrav char * 52783d2307dSDag-Erling Smørgrav line_fullname(char *dst, const char *src, int dstsize) 52883d2307dSDag-Erling Smørgrav { 52983d2307dSDag-Erling Smørgrav memset(dst, '\0', dstsize); 53083d2307dSDag-Erling Smørgrav if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) { 53183d2307dSDag-Erling Smørgrav strlcpy(dst, src, dstsize); 53283d2307dSDag-Erling Smørgrav } else { 53383d2307dSDag-Erling Smørgrav strlcpy(dst, "/dev/", dstsize); 53483d2307dSDag-Erling Smørgrav strlcat(dst, src, dstsize); 53583d2307dSDag-Erling Smørgrav } 53683d2307dSDag-Erling Smørgrav return dst; 53783d2307dSDag-Erling Smørgrav } 53883d2307dSDag-Erling Smørgrav 53983d2307dSDag-Erling Smørgrav /* line_stripname(): strip the leading '/dev' if it exists, return dst */ 54083d2307dSDag-Erling Smørgrav char * 54183d2307dSDag-Erling Smørgrav line_stripname(char *dst, const char *src, int dstsize) 54283d2307dSDag-Erling Smørgrav { 54383d2307dSDag-Erling Smørgrav memset(dst, '\0', dstsize); 54483d2307dSDag-Erling Smørgrav if (strncmp(src, "/dev/", 5) == 0) 54583d2307dSDag-Erling Smørgrav strlcpy(dst, src + 5, dstsize); 54683d2307dSDag-Erling Smørgrav else 54783d2307dSDag-Erling Smørgrav strlcpy(dst, src, dstsize); 54883d2307dSDag-Erling Smørgrav return dst; 54983d2307dSDag-Erling Smørgrav } 55083d2307dSDag-Erling Smørgrav 55183d2307dSDag-Erling Smørgrav /* line_abbrevname(): Return the abbreviated (usually four-character) 55283d2307dSDag-Erling Smørgrav * form of the line (Just use the last <dstsize> characters of the 55383d2307dSDag-Erling Smørgrav * full name.) 55483d2307dSDag-Erling Smørgrav * 55583d2307dSDag-Erling Smørgrav * NOTE: use strncpy because we do NOT necessarily want zero 55683d2307dSDag-Erling Smørgrav * termination */ 55783d2307dSDag-Erling Smørgrav char * 55883d2307dSDag-Erling Smørgrav line_abbrevname(char *dst, const char *src, int dstsize) 55983d2307dSDag-Erling Smørgrav { 56083d2307dSDag-Erling Smørgrav size_t len; 56183d2307dSDag-Erling Smørgrav 56283d2307dSDag-Erling Smørgrav memset(dst, '\0', dstsize); 56383d2307dSDag-Erling Smørgrav 56483d2307dSDag-Erling Smørgrav /* Always skip prefix if present */ 56583d2307dSDag-Erling Smørgrav if (strncmp(src, "/dev/", 5) == 0) 56683d2307dSDag-Erling Smørgrav src += 5; 56783d2307dSDag-Erling Smørgrav 56883d2307dSDag-Erling Smørgrav #ifdef WITH_ABBREV_NO_TTY 56983d2307dSDag-Erling Smørgrav if (strncmp(src, "tty", 3) == 0) 57083d2307dSDag-Erling Smørgrav src += 3; 57183d2307dSDag-Erling Smørgrav #endif 57283d2307dSDag-Erling Smørgrav 57383d2307dSDag-Erling Smørgrav len = strlen(src); 57483d2307dSDag-Erling Smørgrav 57583d2307dSDag-Erling Smørgrav if (len > 0) { 57683d2307dSDag-Erling Smørgrav if (((int)len - dstsize) > 0) 57783d2307dSDag-Erling Smørgrav src += ((int)len - dstsize); 57883d2307dSDag-Erling Smørgrav 57983d2307dSDag-Erling Smørgrav /* note: _don't_ change this to strlcpy */ 58083d2307dSDag-Erling Smørgrav strncpy(dst, src, (size_t)dstsize); 58183d2307dSDag-Erling Smørgrav } 58283d2307dSDag-Erling Smørgrav 58383d2307dSDag-Erling Smørgrav return dst; 58483d2307dSDag-Erling Smørgrav } 58583d2307dSDag-Erling Smørgrav 58683d2307dSDag-Erling Smørgrav /** 58783d2307dSDag-Erling Smørgrav ** utmp utility functions 58883d2307dSDag-Erling Smørgrav ** 58983d2307dSDag-Erling Smørgrav ** These functions manipulate struct utmp, taking system differences 59083d2307dSDag-Erling Smørgrav ** into account. 59183d2307dSDag-Erling Smørgrav **/ 59283d2307dSDag-Erling Smørgrav 59383d2307dSDag-Erling Smørgrav #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN) 59483d2307dSDag-Erling Smørgrav 59583d2307dSDag-Erling Smørgrav /* build the utmp structure */ 59683d2307dSDag-Erling Smørgrav void 59783d2307dSDag-Erling Smørgrav set_utmp_time(struct logininfo *li, struct utmp *ut) 59883d2307dSDag-Erling Smørgrav { 59983d2307dSDag-Erling Smørgrav # ifdef HAVE_TV_IN_UTMP 60083d2307dSDag-Erling Smørgrav ut->ut_tv.tv_sec = li->tv_sec; 60183d2307dSDag-Erling Smørgrav ut->ut_tv.tv_usec = li->tv_usec; 60283d2307dSDag-Erling Smørgrav # else 60383d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMP 60483d2307dSDag-Erling Smørgrav ut->ut_time = li->tv_sec; 60583d2307dSDag-Erling Smørgrav # endif 60683d2307dSDag-Erling Smørgrav # endif 60783d2307dSDag-Erling Smørgrav } 60883d2307dSDag-Erling Smørgrav 60983d2307dSDag-Erling Smørgrav void 61083d2307dSDag-Erling Smørgrav construct_utmp(struct logininfo *li, 61183d2307dSDag-Erling Smørgrav struct utmp *ut) 61283d2307dSDag-Erling Smørgrav { 613e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 614e73e9afaSDag-Erling Smørgrav struct sockaddr_in6 *sa6; 615e73e9afaSDag-Erling Smørgrav # endif 61683d2307dSDag-Erling Smørgrav memset(ut, '\0', sizeof(*ut)); 61783d2307dSDag-Erling Smørgrav 61883d2307dSDag-Erling Smørgrav /* First fill out fields used for both logins and logouts */ 61983d2307dSDag-Erling Smørgrav 62083d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMP 62183d2307dSDag-Erling Smørgrav line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id)); 62283d2307dSDag-Erling Smørgrav # endif 62383d2307dSDag-Erling Smørgrav 62483d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP 62583d2307dSDag-Erling Smørgrav /* This is done here to keep utmp constants out of struct logininfo */ 62683d2307dSDag-Erling Smørgrav switch (li->type) { 62783d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 62883d2307dSDag-Erling Smørgrav ut->ut_type = USER_PROCESS; 629f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 63083d2307dSDag-Erling Smørgrav cray_set_tmpdir(ut); 63183d2307dSDag-Erling Smørgrav #endif 63283d2307dSDag-Erling Smørgrav break; 63383d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 63483d2307dSDag-Erling Smørgrav ut->ut_type = DEAD_PROCESS; 635f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 63683d2307dSDag-Erling Smørgrav cray_retain_utmp(ut, li->pid); 63783d2307dSDag-Erling Smørgrav #endif 63883d2307dSDag-Erling Smørgrav break; 63983d2307dSDag-Erling Smørgrav } 64083d2307dSDag-Erling Smørgrav # endif 64183d2307dSDag-Erling Smørgrav set_utmp_time(li, ut); 64283d2307dSDag-Erling Smørgrav 64383d2307dSDag-Erling Smørgrav line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line)); 64483d2307dSDag-Erling Smørgrav 64583d2307dSDag-Erling Smørgrav # ifdef HAVE_PID_IN_UTMP 64683d2307dSDag-Erling Smørgrav ut->ut_pid = li->pid; 64783d2307dSDag-Erling Smørgrav # endif 64883d2307dSDag-Erling Smørgrav 64983d2307dSDag-Erling Smørgrav /* If we're logging out, leave all other fields blank */ 65083d2307dSDag-Erling Smørgrav if (li->type == LTYPE_LOGOUT) 65183d2307dSDag-Erling Smørgrav return; 65283d2307dSDag-Erling Smørgrav 65383d2307dSDag-Erling Smørgrav /* 65483d2307dSDag-Erling Smørgrav * These fields are only used when logging in, and are blank 65583d2307dSDag-Erling Smørgrav * for logouts. 65683d2307dSDag-Erling Smørgrav */ 65783d2307dSDag-Erling Smørgrav 65883d2307dSDag-Erling Smørgrav /* Use strncpy because we don't necessarily want null termination */ 65983d2307dSDag-Erling Smørgrav strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username)); 66083d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP 661a9f7d76bSDag-Erling Smørgrav realhostname_sa(ut->ut_host, sizeof ut->ut_host, 662a9f7d76bSDag-Erling Smørgrav &li->hostaddr.sa, li->hostaddr.sa.sa_len); 66383d2307dSDag-Erling Smørgrav # endif 66483d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMP 66583d2307dSDag-Erling Smørgrav /* this is just a 32-bit IP address */ 66683d2307dSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET) 66783d2307dSDag-Erling Smørgrav ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 66883d2307dSDag-Erling Smørgrav # endif 669e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 670e73e9afaSDag-Erling Smørgrav /* this is just a 128-bit IPv6 address */ 671e73e9afaSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET6) { 672e73e9afaSDag-Erling Smørgrav sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); 673e73e9afaSDag-Erling Smørgrav memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); 674e73e9afaSDag-Erling Smørgrav if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { 675e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; 676e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[1] = 0; 677e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[2] = 0; 678e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[3] = 0; 679e73e9afaSDag-Erling Smørgrav } 680e73e9afaSDag-Erling Smørgrav } 681e73e9afaSDag-Erling Smørgrav # endif 68283d2307dSDag-Erling Smørgrav } 68383d2307dSDag-Erling Smørgrav #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */ 68483d2307dSDag-Erling Smørgrav 68583d2307dSDag-Erling Smørgrav /** 68683d2307dSDag-Erling Smørgrav ** utmpx utility functions 68783d2307dSDag-Erling Smørgrav ** 68883d2307dSDag-Erling Smørgrav ** These functions manipulate struct utmpx, accounting for system 68983d2307dSDag-Erling Smørgrav ** variations. 69083d2307dSDag-Erling Smørgrav **/ 69183d2307dSDag-Erling Smørgrav 69283d2307dSDag-Erling Smørgrav #if defined(USE_UTMPX) || defined (USE_WTMPX) 69383d2307dSDag-Erling Smørgrav /* build the utmpx structure */ 69483d2307dSDag-Erling Smørgrav void 69583d2307dSDag-Erling Smørgrav set_utmpx_time(struct logininfo *li, struct utmpx *utx) 69683d2307dSDag-Erling Smørgrav { 69783d2307dSDag-Erling Smørgrav # ifdef HAVE_TV_IN_UTMPX 69883d2307dSDag-Erling Smørgrav utx->ut_tv.tv_sec = li->tv_sec; 69983d2307dSDag-Erling Smørgrav utx->ut_tv.tv_usec = li->tv_usec; 70083d2307dSDag-Erling Smørgrav # else /* HAVE_TV_IN_UTMPX */ 70183d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMPX 70283d2307dSDag-Erling Smørgrav utx->ut_time = li->tv_sec; 70383d2307dSDag-Erling Smørgrav # endif /* HAVE_TIME_IN_UTMPX */ 70483d2307dSDag-Erling Smørgrav # endif /* HAVE_TV_IN_UTMPX */ 70583d2307dSDag-Erling Smørgrav } 70683d2307dSDag-Erling Smørgrav 70783d2307dSDag-Erling Smørgrav void 70883d2307dSDag-Erling Smørgrav construct_utmpx(struct logininfo *li, struct utmpx *utx) 70983d2307dSDag-Erling Smørgrav { 710e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 711e73e9afaSDag-Erling Smørgrav struct sockaddr_in6 *sa6; 712e73e9afaSDag-Erling Smørgrav # endif 71383d2307dSDag-Erling Smørgrav memset(utx, '\0', sizeof(*utx)); 71483d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX 71583d2307dSDag-Erling Smørgrav line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); 71683d2307dSDag-Erling Smørgrav # endif 71783d2307dSDag-Erling Smørgrav 71883d2307dSDag-Erling Smørgrav /* this is done here to keep utmp constants out of loginrec.h */ 71983d2307dSDag-Erling Smørgrav switch (li->type) { 72083d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 72183d2307dSDag-Erling Smørgrav utx->ut_type = USER_PROCESS; 72283d2307dSDag-Erling Smørgrav break; 72383d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 72483d2307dSDag-Erling Smørgrav utx->ut_type = DEAD_PROCESS; 72583d2307dSDag-Erling Smørgrav break; 72683d2307dSDag-Erling Smørgrav } 72783d2307dSDag-Erling Smørgrav line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); 72883d2307dSDag-Erling Smørgrav set_utmpx_time(li, utx); 72983d2307dSDag-Erling Smørgrav utx->ut_pid = li->pid; 73083d2307dSDag-Erling Smørgrav /* strncpy(): Don't necessarily want null termination */ 73183d2307dSDag-Erling Smørgrav strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username)); 73283d2307dSDag-Erling Smørgrav 73383d2307dSDag-Erling Smørgrav if (li->type == LTYPE_LOGOUT) 73483d2307dSDag-Erling Smørgrav return; 73583d2307dSDag-Erling Smørgrav 73683d2307dSDag-Erling Smørgrav /* 73783d2307dSDag-Erling Smørgrav * These fields are only used when logging in, and are blank 73883d2307dSDag-Erling Smørgrav * for logouts. 73983d2307dSDag-Erling Smørgrav */ 74083d2307dSDag-Erling Smørgrav 74183d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMPX 74283d2307dSDag-Erling Smørgrav strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname)); 74383d2307dSDag-Erling Smørgrav # endif 74483d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMPX 74583d2307dSDag-Erling Smørgrav /* this is just a 32-bit IP address */ 74683d2307dSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET) 74783d2307dSDag-Erling Smørgrav utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 74883d2307dSDag-Erling Smørgrav # endif 749e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 750e73e9afaSDag-Erling Smørgrav /* this is just a 128-bit IPv6 address */ 751e73e9afaSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET6) { 752e73e9afaSDag-Erling Smørgrav sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); 753e73e9afaSDag-Erling Smørgrav memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); 754e73e9afaSDag-Erling Smørgrav if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { 755e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; 756e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[1] = 0; 757e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[2] = 0; 758e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[3] = 0; 759e73e9afaSDag-Erling Smørgrav } 760e73e9afaSDag-Erling Smørgrav } 761e73e9afaSDag-Erling Smørgrav # endif 76283d2307dSDag-Erling Smørgrav # ifdef HAVE_SYSLEN_IN_UTMPX 76383d2307dSDag-Erling Smørgrav /* ut_syslen is the length of the utx_host string */ 76483d2307dSDag-Erling Smørgrav utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host)); 76583d2307dSDag-Erling Smørgrav # endif 76683d2307dSDag-Erling Smørgrav } 76783d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX || USE_WTMPX */ 76883d2307dSDag-Erling Smørgrav 76983d2307dSDag-Erling Smørgrav /** 77083d2307dSDag-Erling Smørgrav ** Low-level utmp functions 77183d2307dSDag-Erling Smørgrav **/ 77283d2307dSDag-Erling Smørgrav 77383d2307dSDag-Erling Smørgrav /* FIXME: (ATL) utmp_write_direct needs testing */ 77483d2307dSDag-Erling Smørgrav #ifdef USE_UTMP 77583d2307dSDag-Erling Smørgrav 77683d2307dSDag-Erling Smørgrav /* if we can, use pututline() etc. */ 77783d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ 77883d2307dSDag-Erling Smørgrav defined(HAVE_PUTUTLINE) 77983d2307dSDag-Erling Smørgrav # define UTMP_USE_LIBRARY 78083d2307dSDag-Erling Smørgrav # endif 78183d2307dSDag-Erling Smørgrav 78283d2307dSDag-Erling Smørgrav 78383d2307dSDag-Erling Smørgrav /* write a utmp entry with the system's help (pututline() and pals) */ 78483d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY 78583d2307dSDag-Erling Smørgrav static int 78683d2307dSDag-Erling Smørgrav utmp_write_library(struct logininfo *li, struct utmp *ut) 78783d2307dSDag-Erling Smørgrav { 78883d2307dSDag-Erling Smørgrav setutent(); 78983d2307dSDag-Erling Smørgrav pututline(ut); 79083d2307dSDag-Erling Smørgrav 79183d2307dSDag-Erling Smørgrav # ifdef HAVE_ENDUTENT 79283d2307dSDag-Erling Smørgrav endutent(); 79383d2307dSDag-Erling Smørgrav # endif 79483d2307dSDag-Erling Smørgrav return 1; 79583d2307dSDag-Erling Smørgrav } 79683d2307dSDag-Erling Smørgrav # else /* UTMP_USE_LIBRARY */ 79783d2307dSDag-Erling Smørgrav 79883d2307dSDag-Erling Smørgrav /* write a utmp entry direct to the file */ 79983d2307dSDag-Erling Smørgrav /* This is a slightly modification of code in OpenBSD's login.c */ 80083d2307dSDag-Erling Smørgrav static int 80183d2307dSDag-Erling Smørgrav utmp_write_direct(struct logininfo *li, struct utmp *ut) 80283d2307dSDag-Erling Smørgrav { 80383d2307dSDag-Erling Smørgrav struct utmp old_ut; 80483d2307dSDag-Erling Smørgrav register int fd; 80583d2307dSDag-Erling Smørgrav int tty; 80683d2307dSDag-Erling Smørgrav 80783d2307dSDag-Erling Smørgrav /* FIXME: (ATL) ttyslot() needs local implementation */ 80883d2307dSDag-Erling Smørgrav 80983d2307dSDag-Erling Smørgrav #if defined(HAVE_GETTTYENT) 81083d2307dSDag-Erling Smørgrav register struct ttyent *ty; 81183d2307dSDag-Erling Smørgrav 81283d2307dSDag-Erling Smørgrav tty=0; 81383d2307dSDag-Erling Smørgrav 81483d2307dSDag-Erling Smørgrav setttyent(); 81583d2307dSDag-Erling Smørgrav while ((struct ttyent *)0 != (ty = getttyent())) { 81683d2307dSDag-Erling Smørgrav tty++; 81783d2307dSDag-Erling Smørgrav if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) 81883d2307dSDag-Erling Smørgrav break; 81983d2307dSDag-Erling Smørgrav } 82083d2307dSDag-Erling Smørgrav endttyent(); 82183d2307dSDag-Erling Smørgrav 82283d2307dSDag-Erling Smørgrav if((struct ttyent *)0 == ty) { 82383d2307dSDag-Erling Smørgrav log("utmp_write_entry: tty not found"); 82483d2307dSDag-Erling Smørgrav return(1); 82583d2307dSDag-Erling Smørgrav } 82683d2307dSDag-Erling Smørgrav #else /* FIXME */ 82783d2307dSDag-Erling Smørgrav 82883d2307dSDag-Erling Smørgrav tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */ 82983d2307dSDag-Erling Smørgrav 83083d2307dSDag-Erling Smørgrav #endif /* HAVE_GETTTYENT */ 83183d2307dSDag-Erling Smørgrav 83283d2307dSDag-Erling Smørgrav if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) { 83383d2307dSDag-Erling Smørgrav (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET); 83483d2307dSDag-Erling Smørgrav /* 83583d2307dSDag-Erling Smørgrav * Prevent luser from zero'ing out ut_host. 83683d2307dSDag-Erling Smørgrav * If the new ut_line is empty but the old one is not 83783d2307dSDag-Erling Smørgrav * and ut_line and ut_name match, preserve the old ut_line. 83883d2307dSDag-Erling Smørgrav */ 83983d2307dSDag-Erling Smørgrav if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && 84083d2307dSDag-Erling Smørgrav (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && 84183d2307dSDag-Erling Smørgrav (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && 84283d2307dSDag-Erling Smørgrav (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) { 84383d2307dSDag-Erling Smørgrav (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); 84483d2307dSDag-Erling Smørgrav } 84583d2307dSDag-Erling Smørgrav 84683d2307dSDag-Erling Smørgrav (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET); 84783d2307dSDag-Erling Smørgrav if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) 84883d2307dSDag-Erling Smørgrav log("utmp_write_direct: error writing %s: %s", 84983d2307dSDag-Erling Smørgrav UTMP_FILE, strerror(errno)); 85083d2307dSDag-Erling Smørgrav 85183d2307dSDag-Erling Smørgrav (void)close(fd); 85283d2307dSDag-Erling Smørgrav return 1; 85383d2307dSDag-Erling Smørgrav } else { 85483d2307dSDag-Erling Smørgrav return 0; 85583d2307dSDag-Erling Smørgrav } 85683d2307dSDag-Erling Smørgrav } 85783d2307dSDag-Erling Smørgrav # endif /* UTMP_USE_LIBRARY */ 85883d2307dSDag-Erling Smørgrav 85983d2307dSDag-Erling Smørgrav static int 86083d2307dSDag-Erling Smørgrav utmp_perform_login(struct logininfo *li) 86183d2307dSDag-Erling Smørgrav { 86283d2307dSDag-Erling Smørgrav struct utmp ut; 86383d2307dSDag-Erling Smørgrav 86483d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 86583d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY 86683d2307dSDag-Erling Smørgrav if (!utmp_write_library(li, &ut)) { 86783d2307dSDag-Erling Smørgrav log("utmp_perform_login: utmp_write_library() failed"); 86883d2307dSDag-Erling Smørgrav return 0; 86983d2307dSDag-Erling Smørgrav } 87083d2307dSDag-Erling Smørgrav # else 87183d2307dSDag-Erling Smørgrav if (!utmp_write_direct(li, &ut)) { 87283d2307dSDag-Erling Smørgrav log("utmp_perform_login: utmp_write_direct() failed"); 87383d2307dSDag-Erling Smørgrav return 0; 87483d2307dSDag-Erling Smørgrav } 87583d2307dSDag-Erling Smørgrav # endif 87683d2307dSDag-Erling Smørgrav return 1; 87783d2307dSDag-Erling Smørgrav } 87883d2307dSDag-Erling Smørgrav 87983d2307dSDag-Erling Smørgrav 88083d2307dSDag-Erling Smørgrav static int 88183d2307dSDag-Erling Smørgrav utmp_perform_logout(struct logininfo *li) 88283d2307dSDag-Erling Smørgrav { 88383d2307dSDag-Erling Smørgrav struct utmp ut; 88483d2307dSDag-Erling Smørgrav 88583d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 88683d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY 88783d2307dSDag-Erling Smørgrav if (!utmp_write_library(li, &ut)) { 88883d2307dSDag-Erling Smørgrav log("utmp_perform_logout: utmp_write_library() failed"); 88983d2307dSDag-Erling Smørgrav return 0; 89083d2307dSDag-Erling Smørgrav } 89183d2307dSDag-Erling Smørgrav # else 89283d2307dSDag-Erling Smørgrav if (!utmp_write_direct(li, &ut)) { 89383d2307dSDag-Erling Smørgrav log("utmp_perform_logout: utmp_write_direct() failed"); 89483d2307dSDag-Erling Smørgrav return 0; 89583d2307dSDag-Erling Smørgrav } 89683d2307dSDag-Erling Smørgrav # endif 89783d2307dSDag-Erling Smørgrav return 1; 89883d2307dSDag-Erling Smørgrav } 89983d2307dSDag-Erling Smørgrav 90083d2307dSDag-Erling Smørgrav 90183d2307dSDag-Erling Smørgrav int 90283d2307dSDag-Erling Smørgrav utmp_write_entry(struct logininfo *li) 90383d2307dSDag-Erling Smørgrav { 90483d2307dSDag-Erling Smørgrav switch(li->type) { 90583d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 90683d2307dSDag-Erling Smørgrav return utmp_perform_login(li); 90783d2307dSDag-Erling Smørgrav 90883d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 90983d2307dSDag-Erling Smørgrav return utmp_perform_logout(li); 91083d2307dSDag-Erling Smørgrav 91183d2307dSDag-Erling Smørgrav default: 91283d2307dSDag-Erling Smørgrav log("utmp_write_entry: invalid type field"); 91383d2307dSDag-Erling Smørgrav return 0; 91483d2307dSDag-Erling Smørgrav } 91583d2307dSDag-Erling Smørgrav } 91683d2307dSDag-Erling Smørgrav #endif /* USE_UTMP */ 91783d2307dSDag-Erling Smørgrav 91883d2307dSDag-Erling Smørgrav 91983d2307dSDag-Erling Smørgrav /** 92083d2307dSDag-Erling Smørgrav ** Low-level utmpx functions 92183d2307dSDag-Erling Smørgrav **/ 92283d2307dSDag-Erling Smørgrav 92383d2307dSDag-Erling Smørgrav /* not much point if we don't want utmpx entries */ 92483d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX 92583d2307dSDag-Erling Smørgrav 92683d2307dSDag-Erling Smørgrav /* if we have the wherewithall, use pututxline etc. */ 92783d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \ 92883d2307dSDag-Erling Smørgrav defined(HAVE_PUTUTXLINE) 92983d2307dSDag-Erling Smørgrav # define UTMPX_USE_LIBRARY 93083d2307dSDag-Erling Smørgrav # endif 93183d2307dSDag-Erling Smørgrav 93283d2307dSDag-Erling Smørgrav 93383d2307dSDag-Erling Smørgrav /* write a utmpx entry with the system's help (pututxline() and pals) */ 93483d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY 93583d2307dSDag-Erling Smørgrav static int 93683d2307dSDag-Erling Smørgrav utmpx_write_library(struct logininfo *li, struct utmpx *utx) 93783d2307dSDag-Erling Smørgrav { 93883d2307dSDag-Erling Smørgrav setutxent(); 93983d2307dSDag-Erling Smørgrav pututxline(utx); 94083d2307dSDag-Erling Smørgrav 94183d2307dSDag-Erling Smørgrav # ifdef HAVE_ENDUTXENT 94283d2307dSDag-Erling Smørgrav endutxent(); 94383d2307dSDag-Erling Smørgrav # endif 94483d2307dSDag-Erling Smørgrav return 1; 94583d2307dSDag-Erling Smørgrav } 94683d2307dSDag-Erling Smørgrav 94783d2307dSDag-Erling Smørgrav # else /* UTMPX_USE_LIBRARY */ 94883d2307dSDag-Erling Smørgrav 94983d2307dSDag-Erling Smørgrav /* write a utmp entry direct to the file */ 95083d2307dSDag-Erling Smørgrav static int 95183d2307dSDag-Erling Smørgrav utmpx_write_direct(struct logininfo *li, struct utmpx *utx) 95283d2307dSDag-Erling Smørgrav { 95383d2307dSDag-Erling Smørgrav log("utmpx_write_direct: not implemented!"); 95483d2307dSDag-Erling Smørgrav return 0; 95583d2307dSDag-Erling Smørgrav } 95683d2307dSDag-Erling Smørgrav # endif /* UTMPX_USE_LIBRARY */ 95783d2307dSDag-Erling Smørgrav 95883d2307dSDag-Erling Smørgrav static int 95983d2307dSDag-Erling Smørgrav utmpx_perform_login(struct logininfo *li) 96083d2307dSDag-Erling Smørgrav { 96183d2307dSDag-Erling Smørgrav struct utmpx utx; 96283d2307dSDag-Erling Smørgrav 96383d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 96483d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY 96583d2307dSDag-Erling Smørgrav if (!utmpx_write_library(li, &utx)) { 96683d2307dSDag-Erling Smørgrav log("utmpx_perform_login: utmp_write_library() failed"); 96783d2307dSDag-Erling Smørgrav return 0; 96883d2307dSDag-Erling Smørgrav } 96983d2307dSDag-Erling Smørgrav # else 97083d2307dSDag-Erling Smørgrav if (!utmpx_write_direct(li, &ut)) { 97183d2307dSDag-Erling Smørgrav log("utmpx_perform_login: utmp_write_direct() failed"); 97283d2307dSDag-Erling Smørgrav return 0; 97383d2307dSDag-Erling Smørgrav } 97483d2307dSDag-Erling Smørgrav # endif 97583d2307dSDag-Erling Smørgrav return 1; 97683d2307dSDag-Erling Smørgrav } 97783d2307dSDag-Erling Smørgrav 97883d2307dSDag-Erling Smørgrav 97983d2307dSDag-Erling Smørgrav static int 98083d2307dSDag-Erling Smørgrav utmpx_perform_logout(struct logininfo *li) 98183d2307dSDag-Erling Smørgrav { 98283d2307dSDag-Erling Smørgrav struct utmpx utx; 98383d2307dSDag-Erling Smørgrav 98483d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 98583d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX 98683d2307dSDag-Erling Smørgrav line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id)); 98783d2307dSDag-Erling Smørgrav # endif 98883d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX 98983d2307dSDag-Erling Smørgrav utx.ut_type = DEAD_PROCESS; 99083d2307dSDag-Erling Smørgrav # endif 99183d2307dSDag-Erling Smørgrav 99283d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY 99383d2307dSDag-Erling Smørgrav utmpx_write_library(li, &utx); 99483d2307dSDag-Erling Smørgrav # else 99583d2307dSDag-Erling Smørgrav utmpx_write_direct(li, &utx); 99683d2307dSDag-Erling Smørgrav # endif 99783d2307dSDag-Erling Smørgrav return 1; 99883d2307dSDag-Erling Smørgrav } 99983d2307dSDag-Erling Smørgrav 100083d2307dSDag-Erling Smørgrav int 100183d2307dSDag-Erling Smørgrav utmpx_write_entry(struct logininfo *li) 100283d2307dSDag-Erling Smørgrav { 100383d2307dSDag-Erling Smørgrav switch(li->type) { 100483d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 100583d2307dSDag-Erling Smørgrav return utmpx_perform_login(li); 100683d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 100783d2307dSDag-Erling Smørgrav return utmpx_perform_logout(li); 100883d2307dSDag-Erling Smørgrav default: 100983d2307dSDag-Erling Smørgrav log("utmpx_write_entry: invalid type field"); 101083d2307dSDag-Erling Smørgrav return 0; 101183d2307dSDag-Erling Smørgrav } 101283d2307dSDag-Erling Smørgrav } 101383d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX */ 101483d2307dSDag-Erling Smørgrav 101583d2307dSDag-Erling Smørgrav 101683d2307dSDag-Erling Smørgrav /** 101783d2307dSDag-Erling Smørgrav ** Low-level wtmp functions 101883d2307dSDag-Erling Smørgrav **/ 101983d2307dSDag-Erling Smørgrav 102083d2307dSDag-Erling Smørgrav #ifdef USE_WTMP 102183d2307dSDag-Erling Smørgrav 102283d2307dSDag-Erling Smørgrav /* write a wtmp entry direct to the end of the file */ 102383d2307dSDag-Erling Smørgrav /* This is a slight modification of code in OpenBSD's logwtmp.c */ 102483d2307dSDag-Erling Smørgrav static int 102583d2307dSDag-Erling Smørgrav wtmp_write(struct logininfo *li, struct utmp *ut) 102683d2307dSDag-Erling Smørgrav { 102783d2307dSDag-Erling Smørgrav struct stat buf; 102883d2307dSDag-Erling Smørgrav int fd, ret = 1; 102983d2307dSDag-Erling Smørgrav 103083d2307dSDag-Erling Smørgrav if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 103183d2307dSDag-Erling Smørgrav log("wtmp_write: problem writing %s: %s", 103283d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 103383d2307dSDag-Erling Smørgrav return 0; 103483d2307dSDag-Erling Smørgrav } 103583d2307dSDag-Erling Smørgrav if (fstat(fd, &buf) == 0) 103683d2307dSDag-Erling Smørgrav if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) { 103783d2307dSDag-Erling Smørgrav ftruncate(fd, buf.st_size); 103883d2307dSDag-Erling Smørgrav log("wtmp_write: problem writing %s: %s", 103983d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 104083d2307dSDag-Erling Smørgrav ret = 0; 104183d2307dSDag-Erling Smørgrav } 104283d2307dSDag-Erling Smørgrav (void)close(fd); 104383d2307dSDag-Erling Smørgrav return ret; 104483d2307dSDag-Erling Smørgrav } 104583d2307dSDag-Erling Smørgrav 104683d2307dSDag-Erling Smørgrav static int 104783d2307dSDag-Erling Smørgrav wtmp_perform_login(struct logininfo *li) 104883d2307dSDag-Erling Smørgrav { 104983d2307dSDag-Erling Smørgrav struct utmp ut; 105083d2307dSDag-Erling Smørgrav 105183d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 105283d2307dSDag-Erling Smørgrav return wtmp_write(li, &ut); 105383d2307dSDag-Erling Smørgrav } 105483d2307dSDag-Erling Smørgrav 105583d2307dSDag-Erling Smørgrav 105683d2307dSDag-Erling Smørgrav static int 105783d2307dSDag-Erling Smørgrav wtmp_perform_logout(struct logininfo *li) 105883d2307dSDag-Erling Smørgrav { 105983d2307dSDag-Erling Smørgrav struct utmp ut; 106083d2307dSDag-Erling Smørgrav 106183d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 106283d2307dSDag-Erling Smørgrav return wtmp_write(li, &ut); 106383d2307dSDag-Erling Smørgrav } 106483d2307dSDag-Erling Smørgrav 106583d2307dSDag-Erling Smørgrav 106683d2307dSDag-Erling Smørgrav int 106783d2307dSDag-Erling Smørgrav wtmp_write_entry(struct logininfo *li) 106883d2307dSDag-Erling Smørgrav { 106983d2307dSDag-Erling Smørgrav switch(li->type) { 107083d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 107183d2307dSDag-Erling Smørgrav return wtmp_perform_login(li); 107283d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 107383d2307dSDag-Erling Smørgrav return wtmp_perform_logout(li); 107483d2307dSDag-Erling Smørgrav default: 107583d2307dSDag-Erling Smørgrav log("wtmp_write_entry: invalid type field"); 107683d2307dSDag-Erling Smørgrav return 0; 107783d2307dSDag-Erling Smørgrav } 107883d2307dSDag-Erling Smørgrav } 107983d2307dSDag-Erling Smørgrav 108083d2307dSDag-Erling Smørgrav 108183d2307dSDag-Erling Smørgrav /* Notes on fetching login data from wtmp/wtmpx 108283d2307dSDag-Erling Smørgrav * 108383d2307dSDag-Erling Smørgrav * Logouts are usually recorded with (amongst other things) a blank 108483d2307dSDag-Erling Smørgrav * username on a given tty line. However, some systems (HP-UX is one) 108583d2307dSDag-Erling Smørgrav * leave all fields set, but change the ut_type field to DEAD_PROCESS. 108683d2307dSDag-Erling Smørgrav * 108783d2307dSDag-Erling Smørgrav * Since we're only looking for logins here, we know that the username 108883d2307dSDag-Erling Smørgrav * must be set correctly. On systems that leave it in, we check for 108983d2307dSDag-Erling Smørgrav * ut_type==USER_PROCESS (indicating a login.) 109083d2307dSDag-Erling Smørgrav * 109183d2307dSDag-Erling Smørgrav * Portability: Some systems may set something other than USER_PROCESS 109283d2307dSDag-Erling Smørgrav * to indicate a login process. I don't know of any as I write. Also, 109383d2307dSDag-Erling Smørgrav * it's possible that some systems may both leave the username in 109483d2307dSDag-Erling Smørgrav * place and not have ut_type. 109583d2307dSDag-Erling Smørgrav */ 109683d2307dSDag-Erling Smørgrav 109783d2307dSDag-Erling Smørgrav /* return true if this wtmp entry indicates a login */ 109883d2307dSDag-Erling Smørgrav static int 109983d2307dSDag-Erling Smørgrav wtmp_islogin(struct logininfo *li, struct utmp *ut) 110083d2307dSDag-Erling Smørgrav { 110183d2307dSDag-Erling Smørgrav if (strncmp(li->username, ut->ut_name, 110283d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->username, ut->ut_name)) == 0) { 110383d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP 110483d2307dSDag-Erling Smørgrav if (ut->ut_type & USER_PROCESS) 110583d2307dSDag-Erling Smørgrav return 1; 110683d2307dSDag-Erling Smørgrav # else 110783d2307dSDag-Erling Smørgrav return 1; 110883d2307dSDag-Erling Smørgrav # endif 110983d2307dSDag-Erling Smørgrav } 111083d2307dSDag-Erling Smørgrav return 0; 111183d2307dSDag-Erling Smørgrav } 111283d2307dSDag-Erling Smørgrav 111383d2307dSDag-Erling Smørgrav int 111483d2307dSDag-Erling Smørgrav wtmp_get_entry(struct logininfo *li) 111583d2307dSDag-Erling Smørgrav { 111683d2307dSDag-Erling Smørgrav struct stat st; 111783d2307dSDag-Erling Smørgrav struct utmp ut; 111883d2307dSDag-Erling Smørgrav int fd, found=0; 111983d2307dSDag-Erling Smørgrav 112083d2307dSDag-Erling Smørgrav /* Clear the time entries in our logininfo */ 112183d2307dSDag-Erling Smørgrav li->tv_sec = li->tv_usec = 0; 112283d2307dSDag-Erling Smørgrav 112383d2307dSDag-Erling Smørgrav if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { 112483d2307dSDag-Erling Smørgrav log("wtmp_get_entry: problem opening %s: %s", 112583d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 112683d2307dSDag-Erling Smørgrav return 0; 112783d2307dSDag-Erling Smørgrav } 112883d2307dSDag-Erling Smørgrav if (fstat(fd, &st) != 0) { 112983d2307dSDag-Erling Smørgrav log("wtmp_get_entry: couldn't stat %s: %s", 113083d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 113183d2307dSDag-Erling Smørgrav close(fd); 113283d2307dSDag-Erling Smørgrav return 0; 113383d2307dSDag-Erling Smørgrav } 113483d2307dSDag-Erling Smørgrav 113583d2307dSDag-Erling Smørgrav /* Seek to the start of the last struct utmp */ 113683d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { 113783d2307dSDag-Erling Smørgrav /* Looks like we've got a fresh wtmp file */ 113883d2307dSDag-Erling Smørgrav close(fd); 113983d2307dSDag-Erling Smørgrav return 0; 114083d2307dSDag-Erling Smørgrav } 114183d2307dSDag-Erling Smørgrav 114283d2307dSDag-Erling Smørgrav while (!found) { 114383d2307dSDag-Erling Smørgrav if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { 114483d2307dSDag-Erling Smørgrav log("wtmp_get_entry: read of %s failed: %s", 114583d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 114683d2307dSDag-Erling Smørgrav close (fd); 114783d2307dSDag-Erling Smørgrav return 0; 114883d2307dSDag-Erling Smørgrav } 114983d2307dSDag-Erling Smørgrav if ( wtmp_islogin(li, &ut) ) { 115083d2307dSDag-Erling Smørgrav found = 1; 115183d2307dSDag-Erling Smørgrav /* We've already checked for a time in struct 115283d2307dSDag-Erling Smørgrav * utmp, in login_getlast(). */ 115383d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMP 115483d2307dSDag-Erling Smørgrav li->tv_sec = ut.ut_time; 115583d2307dSDag-Erling Smørgrav # else 115683d2307dSDag-Erling Smørgrav # if HAVE_TV_IN_UTMP 115783d2307dSDag-Erling Smørgrav li->tv_sec = ut.ut_tv.tv_sec; 115883d2307dSDag-Erling Smørgrav # endif 115983d2307dSDag-Erling Smørgrav # endif 116083d2307dSDag-Erling Smørgrav line_fullname(li->line, ut.ut_line, 116183d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->line, ut.ut_line)); 116283d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP 116383d2307dSDag-Erling Smørgrav strlcpy(li->hostname, ut.ut_host, 116483d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->hostname, ut.ut_host)); 116583d2307dSDag-Erling Smørgrav # endif 116683d2307dSDag-Erling Smørgrav continue; 116783d2307dSDag-Erling Smørgrav } 116883d2307dSDag-Erling Smørgrav /* Seek back 2 x struct utmp */ 116983d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { 117083d2307dSDag-Erling Smørgrav /* We've found the start of the file, so quit */ 117183d2307dSDag-Erling Smørgrav close (fd); 117283d2307dSDag-Erling Smørgrav return 0; 117383d2307dSDag-Erling Smørgrav } 117483d2307dSDag-Erling Smørgrav } 117583d2307dSDag-Erling Smørgrav 117683d2307dSDag-Erling Smørgrav /* We found an entry. Tidy up and return */ 117783d2307dSDag-Erling Smørgrav close(fd); 117883d2307dSDag-Erling Smørgrav return 1; 117983d2307dSDag-Erling Smørgrav } 118083d2307dSDag-Erling Smørgrav # endif /* USE_WTMP */ 118183d2307dSDag-Erling Smørgrav 118283d2307dSDag-Erling Smørgrav 118383d2307dSDag-Erling Smørgrav /** 118483d2307dSDag-Erling Smørgrav ** Low-level wtmpx functions 118583d2307dSDag-Erling Smørgrav **/ 118683d2307dSDag-Erling Smørgrav 118783d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX 118883d2307dSDag-Erling Smørgrav /* write a wtmpx entry direct to the end of the file */ 118983d2307dSDag-Erling Smørgrav /* This is a slight modification of code in OpenBSD's logwtmp.c */ 119083d2307dSDag-Erling Smørgrav static int 119183d2307dSDag-Erling Smørgrav wtmpx_write(struct logininfo *li, struct utmpx *utx) 119283d2307dSDag-Erling Smørgrav { 119383d2307dSDag-Erling Smørgrav struct stat buf; 119483d2307dSDag-Erling Smørgrav int fd, ret = 1; 119583d2307dSDag-Erling Smørgrav 119683d2307dSDag-Erling Smørgrav if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 119783d2307dSDag-Erling Smørgrav log("wtmpx_write: problem opening %s: %s", 119883d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 119983d2307dSDag-Erling Smørgrav return 0; 120083d2307dSDag-Erling Smørgrav } 120183d2307dSDag-Erling Smørgrav 120283d2307dSDag-Erling Smørgrav if (fstat(fd, &buf) == 0) 120383d2307dSDag-Erling Smørgrav if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) { 120483d2307dSDag-Erling Smørgrav ftruncate(fd, buf.st_size); 120583d2307dSDag-Erling Smørgrav log("wtmpx_write: problem writing %s: %s", 120683d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 120783d2307dSDag-Erling Smørgrav ret = 0; 120883d2307dSDag-Erling Smørgrav } 120983d2307dSDag-Erling Smørgrav (void)close(fd); 121083d2307dSDag-Erling Smørgrav 121183d2307dSDag-Erling Smørgrav return ret; 121283d2307dSDag-Erling Smørgrav } 121383d2307dSDag-Erling Smørgrav 121483d2307dSDag-Erling Smørgrav 121583d2307dSDag-Erling Smørgrav static int 121683d2307dSDag-Erling Smørgrav wtmpx_perform_login(struct logininfo *li) 121783d2307dSDag-Erling Smørgrav { 121883d2307dSDag-Erling Smørgrav struct utmpx utx; 121983d2307dSDag-Erling Smørgrav 122083d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 122183d2307dSDag-Erling Smørgrav return wtmpx_write(li, &utx); 122283d2307dSDag-Erling Smørgrav } 122383d2307dSDag-Erling Smørgrav 122483d2307dSDag-Erling Smørgrav 122583d2307dSDag-Erling Smørgrav static int 122683d2307dSDag-Erling Smørgrav wtmpx_perform_logout(struct logininfo *li) 122783d2307dSDag-Erling Smørgrav { 122883d2307dSDag-Erling Smørgrav struct utmpx utx; 122983d2307dSDag-Erling Smørgrav 123083d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 123183d2307dSDag-Erling Smørgrav return wtmpx_write(li, &utx); 123283d2307dSDag-Erling Smørgrav } 123383d2307dSDag-Erling Smørgrav 123483d2307dSDag-Erling Smørgrav 123583d2307dSDag-Erling Smørgrav int 123683d2307dSDag-Erling Smørgrav wtmpx_write_entry(struct logininfo *li) 123783d2307dSDag-Erling Smørgrav { 123883d2307dSDag-Erling Smørgrav switch(li->type) { 123983d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 124083d2307dSDag-Erling Smørgrav return wtmpx_perform_login(li); 124183d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 124283d2307dSDag-Erling Smørgrav return wtmpx_perform_logout(li); 124383d2307dSDag-Erling Smørgrav default: 124483d2307dSDag-Erling Smørgrav log("wtmpx_write_entry: invalid type field"); 124583d2307dSDag-Erling Smørgrav return 0; 124683d2307dSDag-Erling Smørgrav } 124783d2307dSDag-Erling Smørgrav } 124883d2307dSDag-Erling Smørgrav 124983d2307dSDag-Erling Smørgrav /* Please see the notes above wtmp_islogin() for information about the 125083d2307dSDag-Erling Smørgrav next two functions */ 125183d2307dSDag-Erling Smørgrav 125283d2307dSDag-Erling Smørgrav /* Return true if this wtmpx entry indicates a login */ 125383d2307dSDag-Erling Smørgrav static int 125483d2307dSDag-Erling Smørgrav wtmpx_islogin(struct logininfo *li, struct utmpx *utx) 125583d2307dSDag-Erling Smørgrav { 125683d2307dSDag-Erling Smørgrav if ( strncmp(li->username, utx->ut_name, 125783d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) { 125883d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX 125983d2307dSDag-Erling Smørgrav if (utx->ut_type == USER_PROCESS) 126083d2307dSDag-Erling Smørgrav return 1; 126183d2307dSDag-Erling Smørgrav # else 126283d2307dSDag-Erling Smørgrav return 1; 126383d2307dSDag-Erling Smørgrav # endif 126483d2307dSDag-Erling Smørgrav } 126583d2307dSDag-Erling Smørgrav return 0; 126683d2307dSDag-Erling Smørgrav } 126783d2307dSDag-Erling Smørgrav 126883d2307dSDag-Erling Smørgrav 126983d2307dSDag-Erling Smørgrav int 127083d2307dSDag-Erling Smørgrav wtmpx_get_entry(struct logininfo *li) 127183d2307dSDag-Erling Smørgrav { 127283d2307dSDag-Erling Smørgrav struct stat st; 127383d2307dSDag-Erling Smørgrav struct utmpx utx; 127483d2307dSDag-Erling Smørgrav int fd, found=0; 127583d2307dSDag-Erling Smørgrav 127683d2307dSDag-Erling Smørgrav /* Clear the time entries */ 127783d2307dSDag-Erling Smørgrav li->tv_sec = li->tv_usec = 0; 127883d2307dSDag-Erling Smørgrav 127983d2307dSDag-Erling Smørgrav if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { 128083d2307dSDag-Erling Smørgrav log("wtmpx_get_entry: problem opening %s: %s", 128183d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 128283d2307dSDag-Erling Smørgrav return 0; 128383d2307dSDag-Erling Smørgrav } 128483d2307dSDag-Erling Smørgrav if (fstat(fd, &st) != 0) { 128583d2307dSDag-Erling Smørgrav log("wtmpx_get_entry: couldn't stat %s: %s", 1286f388f5efSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 128783d2307dSDag-Erling Smørgrav close(fd); 128883d2307dSDag-Erling Smørgrav return 0; 128983d2307dSDag-Erling Smørgrav } 129083d2307dSDag-Erling Smørgrav 129183d2307dSDag-Erling Smørgrav /* Seek to the start of the last struct utmpx */ 129283d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { 129383d2307dSDag-Erling Smørgrav /* probably a newly rotated wtmpx file */ 129483d2307dSDag-Erling Smørgrav close(fd); 129583d2307dSDag-Erling Smørgrav return 0; 129683d2307dSDag-Erling Smørgrav } 129783d2307dSDag-Erling Smørgrav 129883d2307dSDag-Erling Smørgrav while (!found) { 129983d2307dSDag-Erling Smørgrav if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { 130083d2307dSDag-Erling Smørgrav log("wtmpx_get_entry: read of %s failed: %s", 130183d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 130283d2307dSDag-Erling Smørgrav close (fd); 130383d2307dSDag-Erling Smørgrav return 0; 130483d2307dSDag-Erling Smørgrav } 130583d2307dSDag-Erling Smørgrav /* Logouts are recorded as a blank username on a particular line. 130683d2307dSDag-Erling Smørgrav * So, we just need to find the username in struct utmpx */ 130783d2307dSDag-Erling Smørgrav if ( wtmpx_islogin(li, &utx) ) { 1308f388f5efSDag-Erling Smørgrav found = 1; 130983d2307dSDag-Erling Smørgrav # ifdef HAVE_TV_IN_UTMPX 131083d2307dSDag-Erling Smørgrav li->tv_sec = utx.ut_tv.tv_sec; 131183d2307dSDag-Erling Smørgrav # else 131283d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMPX 131383d2307dSDag-Erling Smørgrav li->tv_sec = utx.ut_time; 131483d2307dSDag-Erling Smørgrav # endif 131583d2307dSDag-Erling Smørgrav # endif 131683d2307dSDag-Erling Smørgrav line_fullname(li->line, utx.ut_line, sizeof(li->line)); 131783d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMPX 131883d2307dSDag-Erling Smørgrav strlcpy(li->hostname, utx.ut_host, 131983d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->hostname, utx.ut_host)); 132083d2307dSDag-Erling Smørgrav # endif 132183d2307dSDag-Erling Smørgrav continue; 132283d2307dSDag-Erling Smørgrav } 132383d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { 132483d2307dSDag-Erling Smørgrav close (fd); 132583d2307dSDag-Erling Smørgrav return 0; 132683d2307dSDag-Erling Smørgrav } 132783d2307dSDag-Erling Smørgrav } 132883d2307dSDag-Erling Smørgrav 132983d2307dSDag-Erling Smørgrav close(fd); 133083d2307dSDag-Erling Smørgrav return 1; 133183d2307dSDag-Erling Smørgrav } 133283d2307dSDag-Erling Smørgrav #endif /* USE_WTMPX */ 133383d2307dSDag-Erling Smørgrav 133483d2307dSDag-Erling Smørgrav /** 133583d2307dSDag-Erling Smørgrav ** Low-level libutil login() functions 133683d2307dSDag-Erling Smørgrav **/ 133783d2307dSDag-Erling Smørgrav 133883d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN 133983d2307dSDag-Erling Smørgrav static int 134083d2307dSDag-Erling Smørgrav syslogin_perform_login(struct logininfo *li) 134183d2307dSDag-Erling Smørgrav { 134283d2307dSDag-Erling Smørgrav struct utmp *ut; 134383d2307dSDag-Erling Smørgrav 134483d2307dSDag-Erling Smørgrav if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) { 134583d2307dSDag-Erling Smørgrav log("syslogin_perform_login: couldn't malloc()"); 134683d2307dSDag-Erling Smørgrav return 0; 134783d2307dSDag-Erling Smørgrav } 134883d2307dSDag-Erling Smørgrav construct_utmp(li, ut); 134983d2307dSDag-Erling Smørgrav login(ut); 1350e73e9afaSDag-Erling Smørgrav free(ut); 135183d2307dSDag-Erling Smørgrav 135283d2307dSDag-Erling Smørgrav return 1; 135383d2307dSDag-Erling Smørgrav } 135483d2307dSDag-Erling Smørgrav 135583d2307dSDag-Erling Smørgrav static int 135683d2307dSDag-Erling Smørgrav syslogin_perform_logout(struct logininfo *li) 135783d2307dSDag-Erling Smørgrav { 135883d2307dSDag-Erling Smørgrav # ifdef HAVE_LOGOUT 135983d2307dSDag-Erling Smørgrav char line[8]; 136083d2307dSDag-Erling Smørgrav 136183d2307dSDag-Erling Smørgrav (void)line_stripname(line, li->line, sizeof(line)); 136283d2307dSDag-Erling Smørgrav 136383d2307dSDag-Erling Smørgrav if (!logout(line)) { 136483d2307dSDag-Erling Smørgrav log("syslogin_perform_logout: logout() returned an error"); 136583d2307dSDag-Erling Smørgrav # ifdef HAVE_LOGWTMP 136683d2307dSDag-Erling Smørgrav } else { 136783d2307dSDag-Erling Smørgrav logwtmp(line, "", ""); 136883d2307dSDag-Erling Smørgrav # endif 136983d2307dSDag-Erling Smørgrav } 137083d2307dSDag-Erling Smørgrav /* FIXME: (ATL - if the need arises) What to do if we have 137183d2307dSDag-Erling Smørgrav * login, but no logout? what if logout but no logwtmp? All 137283d2307dSDag-Erling Smørgrav * routines are in libutil so they should all be there, 137383d2307dSDag-Erling Smørgrav * but... */ 137483d2307dSDag-Erling Smørgrav # endif 137583d2307dSDag-Erling Smørgrav return 1; 137683d2307dSDag-Erling Smørgrav } 137783d2307dSDag-Erling Smørgrav 137883d2307dSDag-Erling Smørgrav int 137983d2307dSDag-Erling Smørgrav syslogin_write_entry(struct logininfo *li) 138083d2307dSDag-Erling Smørgrav { 138183d2307dSDag-Erling Smørgrav switch (li->type) { 138283d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 138383d2307dSDag-Erling Smørgrav return syslogin_perform_login(li); 138483d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 138583d2307dSDag-Erling Smørgrav return syslogin_perform_logout(li); 138683d2307dSDag-Erling Smørgrav default: 138783d2307dSDag-Erling Smørgrav log("syslogin_write_entry: Invalid type field"); 138883d2307dSDag-Erling Smørgrav return 0; 138983d2307dSDag-Erling Smørgrav } 139083d2307dSDag-Erling Smørgrav } 139183d2307dSDag-Erling Smørgrav #endif /* USE_LOGIN */ 139283d2307dSDag-Erling Smørgrav 139383d2307dSDag-Erling Smørgrav /* end of file log-syslogin.c */ 139483d2307dSDag-Erling Smørgrav 139583d2307dSDag-Erling Smørgrav /** 139683d2307dSDag-Erling Smørgrav ** Low-level lastlog functions 139783d2307dSDag-Erling Smørgrav **/ 139883d2307dSDag-Erling Smørgrav 139983d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG 140083d2307dSDag-Erling Smørgrav #define LL_FILE 1 140183d2307dSDag-Erling Smørgrav #define LL_DIR 2 140283d2307dSDag-Erling Smørgrav #define LL_OTHER 3 140383d2307dSDag-Erling Smørgrav 140483d2307dSDag-Erling Smørgrav static void 140583d2307dSDag-Erling Smørgrav lastlog_construct(struct logininfo *li, struct lastlog *last) 140683d2307dSDag-Erling Smørgrav { 140783d2307dSDag-Erling Smørgrav /* clear the structure */ 140883d2307dSDag-Erling Smørgrav memset(last, '\0', sizeof(*last)); 140983d2307dSDag-Erling Smørgrav 141083d2307dSDag-Erling Smørgrav (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); 141183d2307dSDag-Erling Smørgrav strlcpy(last->ll_host, li->hostname, 141283d2307dSDag-Erling Smørgrav MIN_SIZEOF(last->ll_host, li->hostname)); 141383d2307dSDag-Erling Smørgrav last->ll_time = li->tv_sec; 141483d2307dSDag-Erling Smørgrav } 141583d2307dSDag-Erling Smørgrav 141683d2307dSDag-Erling Smørgrav static int 141783d2307dSDag-Erling Smørgrav lastlog_filetype(char *filename) 141883d2307dSDag-Erling Smørgrav { 141983d2307dSDag-Erling Smørgrav struct stat st; 142083d2307dSDag-Erling Smørgrav 142183d2307dSDag-Erling Smørgrav if (stat(LASTLOG_FILE, &st) != 0) { 142283d2307dSDag-Erling Smørgrav log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE, 142383d2307dSDag-Erling Smørgrav strerror(errno)); 142483d2307dSDag-Erling Smørgrav return 0; 142583d2307dSDag-Erling Smørgrav } 142683d2307dSDag-Erling Smørgrav if (S_ISDIR(st.st_mode)) 142783d2307dSDag-Erling Smørgrav return LL_DIR; 142883d2307dSDag-Erling Smørgrav else if (S_ISREG(st.st_mode)) 142983d2307dSDag-Erling Smørgrav return LL_FILE; 143083d2307dSDag-Erling Smørgrav else 143183d2307dSDag-Erling Smørgrav return LL_OTHER; 143283d2307dSDag-Erling Smørgrav } 143383d2307dSDag-Erling Smørgrav 143483d2307dSDag-Erling Smørgrav 143583d2307dSDag-Erling Smørgrav /* open the file (using filemode) and seek to the login entry */ 143683d2307dSDag-Erling Smørgrav static int 143783d2307dSDag-Erling Smørgrav lastlog_openseek(struct logininfo *li, int *fd, int filemode) 143883d2307dSDag-Erling Smørgrav { 143983d2307dSDag-Erling Smørgrav off_t offset; 144083d2307dSDag-Erling Smørgrav int type; 144183d2307dSDag-Erling Smørgrav char lastlog_file[1024]; 144283d2307dSDag-Erling Smørgrav 144383d2307dSDag-Erling Smørgrav type = lastlog_filetype(LASTLOG_FILE); 144483d2307dSDag-Erling Smørgrav switch (type) { 144583d2307dSDag-Erling Smørgrav case LL_FILE: 144683d2307dSDag-Erling Smørgrav strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); 144783d2307dSDag-Erling Smørgrav break; 144883d2307dSDag-Erling Smørgrav case LL_DIR: 144983d2307dSDag-Erling Smørgrav snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", 145083d2307dSDag-Erling Smørgrav LASTLOG_FILE, li->username); 145183d2307dSDag-Erling Smørgrav break; 145283d2307dSDag-Erling Smørgrav default: 145383d2307dSDag-Erling Smørgrav log("lastlog_openseek: %.100s is not a file or directory!", 145483d2307dSDag-Erling Smørgrav LASTLOG_FILE); 145583d2307dSDag-Erling Smørgrav return 0; 145683d2307dSDag-Erling Smørgrav } 145783d2307dSDag-Erling Smørgrav 145883d2307dSDag-Erling Smørgrav *fd = open(lastlog_file, filemode); 145983d2307dSDag-Erling Smørgrav if ( *fd < 0) { 146083d2307dSDag-Erling Smørgrav debug("lastlog_openseek: Couldn't open %s: %s", 146183d2307dSDag-Erling Smørgrav lastlog_file, strerror(errno)); 146283d2307dSDag-Erling Smørgrav return 0; 146383d2307dSDag-Erling Smørgrav } 146483d2307dSDag-Erling Smørgrav 146583d2307dSDag-Erling Smørgrav if (type == LL_FILE) { 146683d2307dSDag-Erling Smørgrav /* find this uid's offset in the lastlog file */ 146783d2307dSDag-Erling Smørgrav offset = (off_t) ((long)li->uid * sizeof(struct lastlog)); 146883d2307dSDag-Erling Smørgrav 146983d2307dSDag-Erling Smørgrav if ( lseek(*fd, offset, SEEK_SET) != offset ) { 147083d2307dSDag-Erling Smørgrav log("lastlog_openseek: %s->lseek(): %s", 147183d2307dSDag-Erling Smørgrav lastlog_file, strerror(errno)); 147283d2307dSDag-Erling Smørgrav return 0; 147383d2307dSDag-Erling Smørgrav } 147483d2307dSDag-Erling Smørgrav } 147583d2307dSDag-Erling Smørgrav 147683d2307dSDag-Erling Smørgrav return 1; 147783d2307dSDag-Erling Smørgrav } 147883d2307dSDag-Erling Smørgrav 147983d2307dSDag-Erling Smørgrav static int 148083d2307dSDag-Erling Smørgrav lastlog_perform_login(struct logininfo *li) 148183d2307dSDag-Erling Smørgrav { 148283d2307dSDag-Erling Smørgrav struct lastlog last; 148383d2307dSDag-Erling Smørgrav int fd; 148483d2307dSDag-Erling Smørgrav 148583d2307dSDag-Erling Smørgrav /* create our struct lastlog */ 148683d2307dSDag-Erling Smørgrav lastlog_construct(li, &last); 148783d2307dSDag-Erling Smørgrav 148883d2307dSDag-Erling Smørgrav if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) 148983d2307dSDag-Erling Smørgrav return(0); 149083d2307dSDag-Erling Smørgrav 149183d2307dSDag-Erling Smørgrav /* write the entry */ 149283d2307dSDag-Erling Smørgrav if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) { 149383d2307dSDag-Erling Smørgrav close(fd); 149483d2307dSDag-Erling Smørgrav log("lastlog_write_filemode: Error writing to %s: %s", 149583d2307dSDag-Erling Smørgrav LASTLOG_FILE, strerror(errno)); 149683d2307dSDag-Erling Smørgrav return 0; 149783d2307dSDag-Erling Smørgrav } 149883d2307dSDag-Erling Smørgrav 149983d2307dSDag-Erling Smørgrav close(fd); 150083d2307dSDag-Erling Smørgrav return 1; 150183d2307dSDag-Erling Smørgrav } 150283d2307dSDag-Erling Smørgrav 150383d2307dSDag-Erling Smørgrav int 150483d2307dSDag-Erling Smørgrav lastlog_write_entry(struct logininfo *li) 150583d2307dSDag-Erling Smørgrav { 150683d2307dSDag-Erling Smørgrav switch(li->type) { 150783d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 150883d2307dSDag-Erling Smørgrav return lastlog_perform_login(li); 150983d2307dSDag-Erling Smørgrav default: 151083d2307dSDag-Erling Smørgrav log("lastlog_write_entry: Invalid type field"); 151183d2307dSDag-Erling Smørgrav return 0; 151283d2307dSDag-Erling Smørgrav } 151383d2307dSDag-Erling Smørgrav } 151483d2307dSDag-Erling Smørgrav 151583d2307dSDag-Erling Smørgrav static void 151683d2307dSDag-Erling Smørgrav lastlog_populate_entry(struct logininfo *li, struct lastlog *last) 151783d2307dSDag-Erling Smørgrav { 151883d2307dSDag-Erling Smørgrav line_fullname(li->line, last->ll_line, sizeof(li->line)); 151983d2307dSDag-Erling Smørgrav strlcpy(li->hostname, last->ll_host, 152083d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->hostname, last->ll_host)); 152183d2307dSDag-Erling Smørgrav li->tv_sec = last->ll_time; 152283d2307dSDag-Erling Smørgrav } 152383d2307dSDag-Erling Smørgrav 152483d2307dSDag-Erling Smørgrav int 152583d2307dSDag-Erling Smørgrav lastlog_get_entry(struct logininfo *li) 152683d2307dSDag-Erling Smørgrav { 152783d2307dSDag-Erling Smørgrav struct lastlog last; 1528e73e9afaSDag-Erling Smørgrav int fd, ret; 152983d2307dSDag-Erling Smørgrav 153083d2307dSDag-Erling Smørgrav if (!lastlog_openseek(li, &fd, O_RDONLY)) 1531e73e9afaSDag-Erling Smørgrav return (0); 153283d2307dSDag-Erling Smørgrav 1533e73e9afaSDag-Erling Smørgrav ret = atomicio(read, fd, &last, sizeof(last)); 153483d2307dSDag-Erling Smørgrav close(fd); 1535e73e9afaSDag-Erling Smørgrav 1536e73e9afaSDag-Erling Smørgrav switch (ret) { 1537e73e9afaSDag-Erling Smørgrav case 0: 1538e73e9afaSDag-Erling Smørgrav memset(&last, '\0', sizeof(last)); 1539e73e9afaSDag-Erling Smørgrav /* FALLTHRU */ 1540e73e9afaSDag-Erling Smørgrav case sizeof(last): 1541e73e9afaSDag-Erling Smørgrav lastlog_populate_entry(li, &last); 1542e73e9afaSDag-Erling Smørgrav return (1); 1543e73e9afaSDag-Erling Smørgrav case -1: 1544e73e9afaSDag-Erling Smørgrav error("%s: Error reading from %s: %s", __func__, 154583d2307dSDag-Erling Smørgrav LASTLOG_FILE, strerror(errno)); 1546e73e9afaSDag-Erling Smørgrav return (0); 1547e73e9afaSDag-Erling Smørgrav default: 1548e73e9afaSDag-Erling Smørgrav error("%s: Error reading from %s: Expecting %d, got %d", 1549e73e9afaSDag-Erling Smørgrav __func__, LASTLOG_FILE, sizeof(last), ret); 1550e73e9afaSDag-Erling Smørgrav return (0); 155183d2307dSDag-Erling Smørgrav } 155283d2307dSDag-Erling Smørgrav 1553e73e9afaSDag-Erling Smørgrav /* NOTREACHED */ 1554e73e9afaSDag-Erling Smørgrav return (0); 155583d2307dSDag-Erling Smørgrav } 155683d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */ 1557