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 * 1683d2307dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1783d2307dSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1883d2307dSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1983d2307dSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2083d2307dSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2183d2307dSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2283d2307dSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2383d2307dSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2483d2307dSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2583d2307dSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2683d2307dSDag-Erling Smørgrav */ 2783d2307dSDag-Erling Smørgrav 28aa49c926SDag-Erling Smørgrav /* 29aa49c926SDag-Erling Smørgrav * The btmp logging code is derived from login.c from util-linux and is under 30aa49c926SDag-Erling Smørgrav * the the following license: 31aa49c926SDag-Erling Smørgrav * 32aa49c926SDag-Erling Smørgrav * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. 33aa49c926SDag-Erling Smørgrav * All rights reserved. 34aa49c926SDag-Erling Smørgrav * 35aa49c926SDag-Erling Smørgrav * Redistribution and use in source and binary forms are permitted 36aa49c926SDag-Erling Smørgrav * provided that the above copyright notice and this paragraph are 37aa49c926SDag-Erling Smørgrav * duplicated in all such forms and that any documentation, 38aa49c926SDag-Erling Smørgrav * advertising materials, and other materials related to such 39aa49c926SDag-Erling Smørgrav * distribution and use acknowledge that the software was developed 40aa49c926SDag-Erling Smørgrav * by the University of California, Berkeley. The name of the 41aa49c926SDag-Erling Smørgrav * University may not be used to endorse or promote products derived 42aa49c926SDag-Erling Smørgrav * from this software without specific prior written permission. 43aa49c926SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 44aa49c926SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 45aa49c926SDag-Erling Smørgrav * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 46aa49c926SDag-Erling Smørgrav */ 47aa49c926SDag-Erling Smørgrav 48aa49c926SDag-Erling Smørgrav 4983d2307dSDag-Erling Smørgrav /** 5083d2307dSDag-Erling Smørgrav ** loginrec.c: platform-independent login recording and lastlog retrieval 5183d2307dSDag-Erling Smørgrav **/ 5283d2307dSDag-Erling Smørgrav 5383d2307dSDag-Erling Smørgrav /* 54aa49c926SDag-Erling Smørgrav * The new login code explained 55aa49c926SDag-Erling Smørgrav * ============================ 56aa49c926SDag-Erling Smørgrav * 57aa49c926SDag-Erling Smørgrav * This code attempts to provide a common interface to login recording 58aa49c926SDag-Erling Smørgrav * (utmp and friends) and last login time retrieval. 59aa49c926SDag-Erling Smørgrav * 60aa49c926SDag-Erling Smørgrav * Its primary means of achieving this is to use 'struct logininfo', a 61aa49c926SDag-Erling Smørgrav * union of all the useful fields in the various different types of 62aa49c926SDag-Erling Smørgrav * system login record structures one finds on UNIX variants. 63aa49c926SDag-Erling Smørgrav * 64aa49c926SDag-Erling Smørgrav * We depend on autoconf to define which recording methods are to be 65aa49c926SDag-Erling Smørgrav * used, and which fields are contained in the relevant data structures 66aa49c926SDag-Erling Smørgrav * on the local system. Many C preprocessor symbols affect which code 67aa49c926SDag-Erling Smørgrav * gets compiled here. 68aa49c926SDag-Erling Smørgrav * 69aa49c926SDag-Erling Smørgrav * The code is designed to make it easy to modify a particular 70aa49c926SDag-Erling Smørgrav * recording method, without affecting other methods nor requiring so 71aa49c926SDag-Erling Smørgrav * many nested conditional compilation blocks as were commonplace in 72aa49c926SDag-Erling Smørgrav * the old code. 73aa49c926SDag-Erling Smørgrav * 74aa49c926SDag-Erling Smørgrav * For login recording, we try to use the local system's libraries as 75aa49c926SDag-Erling Smørgrav * these are clearly most likely to work correctly. For utmp systems 76aa49c926SDag-Erling Smørgrav * this usually means login() and logout() or setutent() etc., probably 77aa49c926SDag-Erling Smørgrav * in libutil, along with logwtmp() etc. On these systems, we fall back 78aa49c926SDag-Erling Smørgrav * to writing the files directly if we have to, though this method 79aa49c926SDag-Erling Smørgrav * requires very thorough testing so we do not corrupt local auditing 80aa49c926SDag-Erling Smørgrav * information. These files and their access methods are very system 81aa49c926SDag-Erling Smørgrav * specific indeed. 82aa49c926SDag-Erling Smørgrav * 83aa49c926SDag-Erling Smørgrav * For utmpx systems, the corresponding library functions are 84aa49c926SDag-Erling Smørgrav * setutxent() etc. To the author's knowledge, all utmpx systems have 85aa49c926SDag-Erling Smørgrav * these library functions and so no direct write is attempted. If such 86aa49c926SDag-Erling Smørgrav * a system exists and needs support, direct analogues of the [uw]tmp 87aa49c926SDag-Erling Smørgrav * code should suffice. 88aa49c926SDag-Erling Smørgrav * 89aa49c926SDag-Erling Smørgrav * Retrieving the time of last login ('lastlog') is in some ways even 90aa49c926SDag-Erling Smørgrav * more problemmatic than login recording. Some systems provide a 91aa49c926SDag-Erling Smørgrav * simple table of all users which we seek based on uid and retrieve a 92aa49c926SDag-Erling Smørgrav * relatively standard structure. Others record the same information in 93aa49c926SDag-Erling Smørgrav * a directory with a separate file, and others don't record the 94aa49c926SDag-Erling Smørgrav * information separately at all. For systems in the latter category, 95aa49c926SDag-Erling Smørgrav * we look backwards in the wtmp or wtmpx file for the last login entry 96aa49c926SDag-Erling Smørgrav * for our user. Naturally this is slower and on busy systems could 97aa49c926SDag-Erling Smørgrav * incur a significant performance penalty. 98aa49c926SDag-Erling Smørgrav * 99aa49c926SDag-Erling Smørgrav * Calling the new code 100aa49c926SDag-Erling Smørgrav * -------------------- 101aa49c926SDag-Erling Smørgrav * 102aa49c926SDag-Erling Smørgrav * In OpenSSH all login recording and retrieval is performed in 103aa49c926SDag-Erling Smørgrav * login.c. Here you'll find working examples. Also, in the logintest.c 104aa49c926SDag-Erling Smørgrav * program there are more examples. 105aa49c926SDag-Erling Smørgrav * 106aa49c926SDag-Erling Smørgrav * Internal handler calling method 107aa49c926SDag-Erling Smørgrav * ------------------------------- 108aa49c926SDag-Erling Smørgrav * 109aa49c926SDag-Erling Smørgrav * When a call is made to login_login() or login_logout(), both 110aa49c926SDag-Erling Smørgrav * routines set a struct logininfo flag defining which action (log in, 111aa49c926SDag-Erling Smørgrav * or log out) is to be taken. They both then call login_write(), which 112aa49c926SDag-Erling Smørgrav * calls whichever of the many structure-specific handlers autoconf 113aa49c926SDag-Erling Smørgrav * selects for the local system. 114aa49c926SDag-Erling Smørgrav * 115aa49c926SDag-Erling Smørgrav * The handlers themselves handle system data structure specifics. Both 116aa49c926SDag-Erling Smørgrav * struct utmp and struct utmpx have utility functions (see 117aa49c926SDag-Erling Smørgrav * construct_utmp*()) to try to make it simpler to add extra systems 118aa49c926SDag-Erling Smørgrav * that introduce new features to either structure. 119aa49c926SDag-Erling Smørgrav * 120aa49c926SDag-Erling Smørgrav * While it may seem terribly wasteful to replicate so much similar 121aa49c926SDag-Erling Smørgrav * code for each method, experience has shown that maintaining code to 122aa49c926SDag-Erling Smørgrav * write both struct utmp and utmpx in one function, whilst maintaining 123aa49c926SDag-Erling Smørgrav * support for all systems whether they have library support or not, is 124aa49c926SDag-Erling Smørgrav * a difficult and time-consuming task. 125aa49c926SDag-Erling Smørgrav * 126aa49c926SDag-Erling Smørgrav * Lastlog support proceeds similarly. Functions login_get_lastlog() 127aa49c926SDag-Erling Smørgrav * (and its OpenSSH-tuned friend login_get_lastlog_time()) call 128aa49c926SDag-Erling Smørgrav * getlast_entry(), which tries one of three methods to find the last 129aa49c926SDag-Erling Smørgrav * login time. It uses local system lastlog support if it can, 130aa49c926SDag-Erling Smørgrav * otherwise it tries wtmp or wtmpx before giving up and returning 0, 131aa49c926SDag-Erling Smørgrav * meaning "tilt". 132aa49c926SDag-Erling Smørgrav * 133aa49c926SDag-Erling Smørgrav * Maintenance 134aa49c926SDag-Erling Smørgrav * ----------- 135aa49c926SDag-Erling Smørgrav * 136aa49c926SDag-Erling Smørgrav * In many cases it's possible to tweak autoconf to select the correct 137aa49c926SDag-Erling Smørgrav * methods for a particular platform, either by improving the detection 138aa49c926SDag-Erling Smørgrav * code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE 139aa49c926SDag-Erling Smørgrav * symbols for the platform. 140aa49c926SDag-Erling Smørgrav * 141aa49c926SDag-Erling Smørgrav * Use logintest to check which symbols are defined before modifying 142aa49c926SDag-Erling Smørgrav * configure.ac and loginrec.c. (You have to build logintest yourself 143aa49c926SDag-Erling Smørgrav * with 'make logintest' as it's not built by default.) 144aa49c926SDag-Erling Smørgrav * 145aa49c926SDag-Erling Smørgrav * Otherwise, patches to the specific method(s) are very helpful! 14683d2307dSDag-Erling Smørgrav */ 14783d2307dSDag-Erling Smørgrav 14883d2307dSDag-Erling Smørgrav #include "includes.h" 14983d2307dSDag-Erling Smørgrav 150333ee039SDag-Erling Smørgrav #include <sys/types.h> 151333ee039SDag-Erling Smørgrav #include <sys/stat.h> 152333ee039SDag-Erling Smørgrav #include <sys/socket.h> 153333ee039SDag-Erling Smørgrav 154333ee039SDag-Erling Smørgrav #include <netinet/in.h> 155333ee039SDag-Erling Smørgrav 156333ee039SDag-Erling Smørgrav #include <errno.h> 157333ee039SDag-Erling Smørgrav #include <fcntl.h> 158333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H 159333ee039SDag-Erling Smørgrav # include <paths.h> 160333ee039SDag-Erling Smørgrav #endif 161333ee039SDag-Erling Smørgrav #include <pwd.h> 162333ee039SDag-Erling Smørgrav #include <stdarg.h> 163333ee039SDag-Erling Smørgrav #include <string.h> 164d4af9e69SDag-Erling Smørgrav #include <time.h> 165333ee039SDag-Erling Smørgrav #include <unistd.h> 166333ee039SDag-Erling Smørgrav 16783d2307dSDag-Erling Smørgrav #include "xmalloc.h" 168333ee039SDag-Erling Smørgrav #include "key.h" 169333ee039SDag-Erling Smørgrav #include "hostfile.h" 170333ee039SDag-Erling Smørgrav #include "ssh.h" 17183d2307dSDag-Erling Smørgrav #include "loginrec.h" 17283d2307dSDag-Erling Smørgrav #include "log.h" 17383d2307dSDag-Erling Smørgrav #include "atomicio.h" 174aa49c926SDag-Erling Smørgrav #include "packet.h" 175aa49c926SDag-Erling Smørgrav #include "canohost.h" 176aa49c926SDag-Erling Smørgrav #include "auth.h" 177aa49c926SDag-Erling Smørgrav #include "buffer.h" 17883d2307dSDag-Erling Smørgrav 17983d2307dSDag-Erling Smørgrav #ifdef HAVE_UTIL_H 18083d2307dSDag-Erling Smørgrav # include <util.h> 18183d2307dSDag-Erling Smørgrav #endif 18283d2307dSDag-Erling Smørgrav 18383d2307dSDag-Erling Smørgrav /** 18483d2307dSDag-Erling Smørgrav ** prototypes for helper functions in this file 18583d2307dSDag-Erling Smørgrav **/ 18683d2307dSDag-Erling Smørgrav 18783d2307dSDag-Erling Smørgrav #if HAVE_UTMP_H 18883d2307dSDag-Erling Smørgrav void set_utmp_time(struct logininfo *li, struct utmp *ut); 18983d2307dSDag-Erling Smørgrav void construct_utmp(struct logininfo *li, struct utmp *ut); 19083d2307dSDag-Erling Smørgrav #endif 19183d2307dSDag-Erling Smørgrav 19283d2307dSDag-Erling Smørgrav #ifdef HAVE_UTMPX_H 19383d2307dSDag-Erling Smørgrav void set_utmpx_time(struct logininfo *li, struct utmpx *ut); 19483d2307dSDag-Erling Smørgrav void construct_utmpx(struct logininfo *li, struct utmpx *ut); 19583d2307dSDag-Erling Smørgrav #endif 19683d2307dSDag-Erling Smørgrav 19783d2307dSDag-Erling Smørgrav int utmp_write_entry(struct logininfo *li); 19883d2307dSDag-Erling Smørgrav int utmpx_write_entry(struct logininfo *li); 19983d2307dSDag-Erling Smørgrav int wtmp_write_entry(struct logininfo *li); 20083d2307dSDag-Erling Smørgrav int wtmpx_write_entry(struct logininfo *li); 20183d2307dSDag-Erling Smørgrav int lastlog_write_entry(struct logininfo *li); 20283d2307dSDag-Erling Smørgrav int syslogin_write_entry(struct logininfo *li); 20383d2307dSDag-Erling Smørgrav 20483d2307dSDag-Erling Smørgrav int getlast_entry(struct logininfo *li); 20583d2307dSDag-Erling Smørgrav int lastlog_get_entry(struct logininfo *li); 206b40cdde6SEd Schouten int utmpx_get_entry(struct logininfo *li); 20783d2307dSDag-Erling Smørgrav int wtmp_get_entry(struct logininfo *li); 20883d2307dSDag-Erling Smørgrav int wtmpx_get_entry(struct logininfo *li); 20983d2307dSDag-Erling Smørgrav 210aa49c926SDag-Erling Smørgrav extern Buffer loginmsg; 211aa49c926SDag-Erling Smørgrav 21283d2307dSDag-Erling Smørgrav /* pick the shortest string */ 21383d2307dSDag-Erling Smørgrav #define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2)) 21483d2307dSDag-Erling Smørgrav 21583d2307dSDag-Erling Smørgrav /** 21683d2307dSDag-Erling Smørgrav ** platform-independent login functions 21783d2307dSDag-Erling Smørgrav **/ 21883d2307dSDag-Erling Smørgrav 219aa49c926SDag-Erling Smørgrav /* 220aa49c926SDag-Erling Smørgrav * login_login(struct logininfo *) - Record a login 22183d2307dSDag-Erling Smørgrav * 22283d2307dSDag-Erling Smørgrav * Call with a pointer to a struct logininfo initialised with 22383d2307dSDag-Erling Smørgrav * login_init_entry() or login_alloc_entry() 22483d2307dSDag-Erling Smørgrav * 22583d2307dSDag-Erling Smørgrav * Returns: 22683d2307dSDag-Erling Smørgrav * >0 if successful 22783d2307dSDag-Erling Smørgrav * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 22883d2307dSDag-Erling Smørgrav */ 22983d2307dSDag-Erling Smørgrav int 23083d2307dSDag-Erling Smørgrav login_login(struct logininfo *li) 23183d2307dSDag-Erling Smørgrav { 23283d2307dSDag-Erling Smørgrav li->type = LTYPE_LOGIN; 233aa49c926SDag-Erling Smørgrav return (login_write(li)); 23483d2307dSDag-Erling Smørgrav } 23583d2307dSDag-Erling Smørgrav 23683d2307dSDag-Erling Smørgrav 237aa49c926SDag-Erling Smørgrav /* 238aa49c926SDag-Erling Smørgrav * login_logout(struct logininfo *) - Record a logout 23983d2307dSDag-Erling Smørgrav * 24083d2307dSDag-Erling Smørgrav * Call as with login_login() 24183d2307dSDag-Erling Smørgrav * 24283d2307dSDag-Erling Smørgrav * Returns: 24383d2307dSDag-Erling Smørgrav * >0 if successful 24483d2307dSDag-Erling Smørgrav * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 24583d2307dSDag-Erling Smørgrav */ 24683d2307dSDag-Erling Smørgrav int 24783d2307dSDag-Erling Smørgrav login_logout(struct logininfo *li) 24883d2307dSDag-Erling Smørgrav { 24983d2307dSDag-Erling Smørgrav li->type = LTYPE_LOGOUT; 250aa49c926SDag-Erling Smørgrav return (login_write(li)); 25183d2307dSDag-Erling Smørgrav } 25283d2307dSDag-Erling Smørgrav 253aa49c926SDag-Erling Smørgrav /* 254aa49c926SDag-Erling Smørgrav * login_get_lastlog_time(int) - Retrieve the last login time 25583d2307dSDag-Erling Smørgrav * 25683d2307dSDag-Erling Smørgrav * Retrieve the last login time for the given uid. Will try to use the 25783d2307dSDag-Erling Smørgrav * system lastlog facilities if they are available, but will fall back 25883d2307dSDag-Erling Smørgrav * to looking in wtmp/wtmpx if necessary 25983d2307dSDag-Erling Smørgrav * 26083d2307dSDag-Erling Smørgrav * Returns: 26183d2307dSDag-Erling Smørgrav * 0 on failure, or if user has never logged in 26283d2307dSDag-Erling Smørgrav * Time in seconds from the epoch if successful 26383d2307dSDag-Erling Smørgrav * 26483d2307dSDag-Erling Smørgrav * Useful preprocessor symbols: 26583d2307dSDag-Erling Smørgrav * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog 26683d2307dSDag-Erling Smørgrav * info 26783d2307dSDag-Erling Smørgrav * USE_LASTLOG: If set, indicates the presence of system lastlog 26883d2307dSDag-Erling Smørgrav * facilities. If this and DISABLE_LASTLOG are not set, 26983d2307dSDag-Erling Smørgrav * try to retrieve lastlog information from wtmp/wtmpx. 27083d2307dSDag-Erling Smørgrav */ 27183d2307dSDag-Erling Smørgrav unsigned int 2724a421b63SDag-Erling Smørgrav login_get_lastlog_time(const uid_t uid) 27383d2307dSDag-Erling Smørgrav { 27483d2307dSDag-Erling Smørgrav struct logininfo li; 27583d2307dSDag-Erling Smørgrav 27683d2307dSDag-Erling Smørgrav if (login_get_lastlog(&li, uid)) 277aa49c926SDag-Erling Smørgrav return (li.tv_sec); 27883d2307dSDag-Erling Smørgrav else 279aa49c926SDag-Erling Smørgrav return (0); 28083d2307dSDag-Erling Smørgrav } 28183d2307dSDag-Erling Smørgrav 282aa49c926SDag-Erling Smørgrav /* 283aa49c926SDag-Erling Smørgrav * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry 28483d2307dSDag-Erling Smørgrav * 28583d2307dSDag-Erling Smørgrav * Retrieve a logininfo structure populated (only partially) with 28683d2307dSDag-Erling Smørgrav * information from the system lastlog data, or from wtmp/wtmpx if no 28783d2307dSDag-Erling Smørgrav * system lastlog information exists. 28883d2307dSDag-Erling Smørgrav * 28983d2307dSDag-Erling Smørgrav * Note this routine must be given a pre-allocated logininfo. 29083d2307dSDag-Erling Smørgrav * 29183d2307dSDag-Erling Smørgrav * Returns: 29283d2307dSDag-Erling Smørgrav * >0: A pointer to your struct logininfo if successful 29383d2307dSDag-Erling Smørgrav * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 29483d2307dSDag-Erling Smørgrav */ 29583d2307dSDag-Erling Smørgrav struct logininfo * 2964a421b63SDag-Erling Smørgrav login_get_lastlog(struct logininfo *li, const uid_t uid) 29783d2307dSDag-Erling Smørgrav { 29883d2307dSDag-Erling Smørgrav struct passwd *pw; 29983d2307dSDag-Erling Smørgrav 30083d2307dSDag-Erling Smørgrav memset(li, '\0', sizeof(*li)); 30183d2307dSDag-Erling Smørgrav li->uid = uid; 30283d2307dSDag-Erling Smørgrav 30383d2307dSDag-Erling Smørgrav /* 30483d2307dSDag-Erling Smørgrav * If we don't have a 'real' lastlog, we need the username to 30583d2307dSDag-Erling Smørgrav * reliably search wtmp(x) for the last login (see 30683d2307dSDag-Erling Smørgrav * wtmp_get_entry().) 30783d2307dSDag-Erling Smørgrav */ 30883d2307dSDag-Erling Smørgrav pw = getpwuid(uid); 30983d2307dSDag-Erling Smørgrav if (pw == NULL) 3104a421b63SDag-Erling Smørgrav fatal("%s: Cannot find account for uid %ld", __func__, 3114a421b63SDag-Erling Smørgrav (long)uid); 31283d2307dSDag-Erling Smørgrav 31383d2307dSDag-Erling Smørgrav /* No MIN_SIZEOF here - we absolutely *must not* truncate the 314aa49c926SDag-Erling Smørgrav * username (XXX - so check for trunc!) */ 31583d2307dSDag-Erling Smørgrav strlcpy(li->username, pw->pw_name, sizeof(li->username)); 31683d2307dSDag-Erling Smørgrav 31783d2307dSDag-Erling Smørgrav if (getlast_entry(li)) 318aa49c926SDag-Erling Smørgrav return (li); 31983d2307dSDag-Erling Smørgrav else 320aa49c926SDag-Erling Smørgrav return (NULL); 32183d2307dSDag-Erling Smørgrav } 32283d2307dSDag-Erling Smørgrav 32383d2307dSDag-Erling Smørgrav 324aa49c926SDag-Erling Smørgrav /* 325aa49c926SDag-Erling Smørgrav * login_alloc_entry(int, char*, char*, char*) - Allocate and initialise 32683d2307dSDag-Erling Smørgrav * a logininfo structure 32783d2307dSDag-Erling Smørgrav * 32883d2307dSDag-Erling Smørgrav * This function creates a new struct logininfo, a data structure 32983d2307dSDag-Erling Smørgrav * meant to carry the information required to portably record login info. 33083d2307dSDag-Erling Smørgrav * 33183d2307dSDag-Erling Smørgrav * Returns a pointer to a newly created struct logininfo. If memory 33283d2307dSDag-Erling Smørgrav * allocation fails, the program halts. 33383d2307dSDag-Erling Smørgrav */ 33483d2307dSDag-Erling Smørgrav struct 3354a421b63SDag-Erling Smørgrav logininfo *login_alloc_entry(pid_t pid, const char *username, 33683d2307dSDag-Erling Smørgrav const char *hostname, const char *line) 33783d2307dSDag-Erling Smørgrav { 33883d2307dSDag-Erling Smørgrav struct logininfo *newli; 33983d2307dSDag-Erling Smørgrav 340aa49c926SDag-Erling Smørgrav newli = xmalloc(sizeof(*newli)); 341aa49c926SDag-Erling Smørgrav login_init_entry(newli, pid, username, hostname, line); 342aa49c926SDag-Erling Smørgrav return (newli); 34383d2307dSDag-Erling Smørgrav } 34483d2307dSDag-Erling Smørgrav 34583d2307dSDag-Erling Smørgrav 34683d2307dSDag-Erling Smørgrav /* login_free_entry(struct logininfo *) - free struct memory */ 34783d2307dSDag-Erling Smørgrav void 34883d2307dSDag-Erling Smørgrav login_free_entry(struct logininfo *li) 34983d2307dSDag-Erling Smørgrav { 350*e4a9863fSDag-Erling Smørgrav free(li); 35183d2307dSDag-Erling Smørgrav } 35283d2307dSDag-Erling Smørgrav 35383d2307dSDag-Erling Smørgrav 35483d2307dSDag-Erling Smørgrav /* login_init_entry(struct logininfo *, int, char*, char*, char*) 35583d2307dSDag-Erling Smørgrav * - initialise a struct logininfo 35683d2307dSDag-Erling Smørgrav * 35783d2307dSDag-Erling Smørgrav * Populates a new struct logininfo, a data structure meant to carry 35883d2307dSDag-Erling Smørgrav * the information required to portably record login info. 35983d2307dSDag-Erling Smørgrav * 36083d2307dSDag-Erling Smørgrav * Returns: 1 36183d2307dSDag-Erling Smørgrav */ 36283d2307dSDag-Erling Smørgrav int 3634a421b63SDag-Erling Smørgrav login_init_entry(struct logininfo *li, pid_t pid, const char *username, 36483d2307dSDag-Erling Smørgrav const char *hostname, const char *line) 36583d2307dSDag-Erling Smørgrav { 36683d2307dSDag-Erling Smørgrav struct passwd *pw; 36783d2307dSDag-Erling Smørgrav 36883d2307dSDag-Erling Smørgrav memset(li, 0, sizeof(*li)); 36983d2307dSDag-Erling Smørgrav 37083d2307dSDag-Erling Smørgrav li->pid = pid; 37183d2307dSDag-Erling Smørgrav 37283d2307dSDag-Erling Smørgrav /* set the line information */ 37383d2307dSDag-Erling Smørgrav if (line) 37483d2307dSDag-Erling Smørgrav line_fullname(li->line, line, sizeof(li->line)); 37583d2307dSDag-Erling Smørgrav 37683d2307dSDag-Erling Smørgrav if (username) { 37783d2307dSDag-Erling Smørgrav strlcpy(li->username, username, sizeof(li->username)); 37883d2307dSDag-Erling Smørgrav pw = getpwnam(li->username); 379aa49c926SDag-Erling Smørgrav if (pw == NULL) { 380aa49c926SDag-Erling Smørgrav fatal("%s: Cannot find user \"%s\"", __func__, 381aa49c926SDag-Erling Smørgrav li->username); 382aa49c926SDag-Erling Smørgrav } 38383d2307dSDag-Erling Smørgrav li->uid = pw->pw_uid; 38483d2307dSDag-Erling Smørgrav } 38583d2307dSDag-Erling Smørgrav 38683d2307dSDag-Erling Smørgrav if (hostname) 38783d2307dSDag-Erling Smørgrav strlcpy(li->hostname, hostname, sizeof(li->hostname)); 38883d2307dSDag-Erling Smørgrav 389aa49c926SDag-Erling Smørgrav return (1); 39083d2307dSDag-Erling Smørgrav } 39183d2307dSDag-Erling Smørgrav 392aa49c926SDag-Erling Smørgrav /* 393aa49c926SDag-Erling Smørgrav * login_set_current_time(struct logininfo *) - set the current time 39483d2307dSDag-Erling Smørgrav * 39583d2307dSDag-Erling Smørgrav * Set the current time in a logininfo structure. This function is 39683d2307dSDag-Erling Smørgrav * meant to eliminate the need to deal with system dependencies for 39783d2307dSDag-Erling Smørgrav * time handling. 39883d2307dSDag-Erling Smørgrav */ 39983d2307dSDag-Erling Smørgrav void 40083d2307dSDag-Erling Smørgrav login_set_current_time(struct logininfo *li) 40183d2307dSDag-Erling Smørgrav { 40283d2307dSDag-Erling Smørgrav struct timeval tv; 40383d2307dSDag-Erling Smørgrav 40483d2307dSDag-Erling Smørgrav gettimeofday(&tv, NULL); 40583d2307dSDag-Erling Smørgrav 40683d2307dSDag-Erling Smørgrav li->tv_sec = tv.tv_sec; 40783d2307dSDag-Erling Smørgrav li->tv_usec = tv.tv_usec; 40883d2307dSDag-Erling Smørgrav } 40983d2307dSDag-Erling Smørgrav 41083d2307dSDag-Erling Smørgrav /* copy a sockaddr_* into our logininfo */ 41183d2307dSDag-Erling Smørgrav void 41283d2307dSDag-Erling Smørgrav login_set_addr(struct logininfo *li, const struct sockaddr *sa, 41383d2307dSDag-Erling Smørgrav const unsigned int sa_size) 41483d2307dSDag-Erling Smørgrav { 41583d2307dSDag-Erling Smørgrav unsigned int bufsize = sa_size; 41683d2307dSDag-Erling Smørgrav 41783d2307dSDag-Erling Smørgrav /* make sure we don't overrun our union */ 41883d2307dSDag-Erling Smørgrav if (sizeof(li->hostaddr) < sa_size) 41983d2307dSDag-Erling Smørgrav bufsize = sizeof(li->hostaddr); 42083d2307dSDag-Erling Smørgrav 421aa49c926SDag-Erling Smørgrav memcpy(&li->hostaddr.sa, sa, bufsize); 42283d2307dSDag-Erling Smørgrav } 42383d2307dSDag-Erling Smørgrav 42483d2307dSDag-Erling Smørgrav 42583d2307dSDag-Erling Smørgrav /** 42683d2307dSDag-Erling Smørgrav ** login_write: Call low-level recording functions based on autoconf 42783d2307dSDag-Erling Smørgrav ** results 42883d2307dSDag-Erling Smørgrav **/ 42983d2307dSDag-Erling Smørgrav int 43083d2307dSDag-Erling Smørgrav login_write(struct logininfo *li) 43183d2307dSDag-Erling Smørgrav { 43283d2307dSDag-Erling Smørgrav #ifndef HAVE_CYGWIN 433aa49c926SDag-Erling Smørgrav if (geteuid() != 0) { 434cf2b5f3bSDag-Erling Smørgrav logit("Attempt to write login records by non-root user (aborting)"); 435aa49c926SDag-Erling Smørgrav return (1); 43683d2307dSDag-Erling Smørgrav } 43783d2307dSDag-Erling Smørgrav #endif 43883d2307dSDag-Erling Smørgrav 43983d2307dSDag-Erling Smørgrav /* set the timestamp */ 44083d2307dSDag-Erling Smørgrav login_set_current_time(li); 44183d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN 44283d2307dSDag-Erling Smørgrav syslogin_write_entry(li); 44383d2307dSDag-Erling Smørgrav #endif 44483d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG 445aa49c926SDag-Erling Smørgrav if (li->type == LTYPE_LOGIN) 44683d2307dSDag-Erling Smørgrav lastlog_write_entry(li); 44783d2307dSDag-Erling Smørgrav #endif 44883d2307dSDag-Erling Smørgrav #ifdef USE_UTMP 44983d2307dSDag-Erling Smørgrav utmp_write_entry(li); 45083d2307dSDag-Erling Smørgrav #endif 45183d2307dSDag-Erling Smørgrav #ifdef USE_WTMP 45283d2307dSDag-Erling Smørgrav wtmp_write_entry(li); 45383d2307dSDag-Erling Smørgrav #endif 45483d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX 45583d2307dSDag-Erling Smørgrav utmpx_write_entry(li); 45683d2307dSDag-Erling Smørgrav #endif 45783d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX 45883d2307dSDag-Erling Smørgrav wtmpx_write_entry(li); 45983d2307dSDag-Erling Smørgrav #endif 46021e764dfSDag-Erling Smørgrav #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN 46121e764dfSDag-Erling Smørgrav if (li->type == LTYPE_LOGIN && 462d4ecd108SDag-Erling Smørgrav !sys_auth_record_login(li->username,li->hostname,li->line, 463d4ecd108SDag-Erling Smørgrav &loginmsg)) 46421e764dfSDag-Erling Smørgrav logit("Writing login record failed for %s", li->username); 46521e764dfSDag-Erling Smørgrav #endif 466aa49c926SDag-Erling Smørgrav #ifdef SSH_AUDIT_EVENTS 467aa49c926SDag-Erling Smørgrav if (li->type == LTYPE_LOGIN) 4684a421b63SDag-Erling Smørgrav audit_session_open(li); 469aa49c926SDag-Erling Smørgrav else if (li->type == LTYPE_LOGOUT) 4704a421b63SDag-Erling Smørgrav audit_session_close(li); 471aa49c926SDag-Erling Smørgrav #endif 472aa49c926SDag-Erling Smørgrav return (0); 47383d2307dSDag-Erling Smørgrav } 47483d2307dSDag-Erling Smørgrav 47583d2307dSDag-Erling Smørgrav #ifdef LOGIN_NEEDS_UTMPX 47683d2307dSDag-Erling Smørgrav int 47783d2307dSDag-Erling Smørgrav login_utmp_only(struct logininfo *li) 47883d2307dSDag-Erling Smørgrav { 47983d2307dSDag-Erling Smørgrav li->type = LTYPE_LOGIN; 48083d2307dSDag-Erling Smørgrav login_set_current_time(li); 48183d2307dSDag-Erling Smørgrav # ifdef USE_UTMP 48283d2307dSDag-Erling Smørgrav utmp_write_entry(li); 48383d2307dSDag-Erling Smørgrav # endif 48483d2307dSDag-Erling Smørgrav # ifdef USE_WTMP 48583d2307dSDag-Erling Smørgrav wtmp_write_entry(li); 48683d2307dSDag-Erling Smørgrav # endif 48783d2307dSDag-Erling Smørgrav # ifdef USE_UTMPX 48883d2307dSDag-Erling Smørgrav utmpx_write_entry(li); 48983d2307dSDag-Erling Smørgrav # endif 49083d2307dSDag-Erling Smørgrav # ifdef USE_WTMPX 49183d2307dSDag-Erling Smørgrav wtmpx_write_entry(li); 49283d2307dSDag-Erling Smørgrav # endif 493aa49c926SDag-Erling Smørgrav return (0); 49483d2307dSDag-Erling Smørgrav } 49583d2307dSDag-Erling Smørgrav #endif 49683d2307dSDag-Erling Smørgrav 49783d2307dSDag-Erling Smørgrav /** 49883d2307dSDag-Erling Smørgrav ** getlast_entry: Call low-level functions to retrieve the last login 49983d2307dSDag-Erling Smørgrav ** time. 50083d2307dSDag-Erling Smørgrav **/ 50183d2307dSDag-Erling Smørgrav 50283d2307dSDag-Erling Smørgrav /* take the uid in li and return the last login time */ 50383d2307dSDag-Erling Smørgrav int 50483d2307dSDag-Erling Smørgrav getlast_entry(struct logininfo *li) 50583d2307dSDag-Erling Smørgrav { 50683d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG 50783d2307dSDag-Erling Smørgrav return(lastlog_get_entry(li)); 50883d2307dSDag-Erling Smørgrav #else /* !USE_LASTLOG */ 5098ad9b54aSDag-Erling Smørgrav #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \ 5108ad9b54aSDag-Erling Smørgrav defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER) 5118ad9b54aSDag-Erling Smørgrav return (utmpx_get_entry(li)); 5128ad9b54aSDag-Erling Smørgrav #endif 51383d2307dSDag-Erling Smørgrav 514aa49c926SDag-Erling Smørgrav #if defined(DISABLE_LASTLOG) 51583d2307dSDag-Erling Smørgrav /* On some systems we shouldn't even try to obtain last login 51683d2307dSDag-Erling Smørgrav * time, e.g. AIX */ 517aa49c926SDag-Erling Smørgrav return (0); 518aa49c926SDag-Erling Smørgrav # elif defined(USE_WTMP) && \ 519aa49c926SDag-Erling Smørgrav (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) 52083d2307dSDag-Erling Smørgrav /* retrieve last login time from utmp */ 52183d2307dSDag-Erling Smørgrav return (wtmp_get_entry(li)); 522aa49c926SDag-Erling Smørgrav # elif defined(USE_WTMPX) && \ 523aa49c926SDag-Erling Smørgrav (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) 52483d2307dSDag-Erling Smørgrav /* If wtmp isn't available, try wtmpx */ 52583d2307dSDag-Erling Smørgrav return (wtmpx_get_entry(li)); 52683d2307dSDag-Erling Smørgrav # else 52783d2307dSDag-Erling Smørgrav /* Give up: No means of retrieving last login time */ 528aa49c926SDag-Erling Smørgrav return (0); 52983d2307dSDag-Erling Smørgrav # endif /* DISABLE_LASTLOG */ 53083d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */ 53183d2307dSDag-Erling Smørgrav } 53283d2307dSDag-Erling Smørgrav 53383d2307dSDag-Erling Smørgrav 53483d2307dSDag-Erling Smørgrav 53583d2307dSDag-Erling Smørgrav /* 53683d2307dSDag-Erling Smørgrav * 'line' string utility functions 53783d2307dSDag-Erling Smørgrav * 53883d2307dSDag-Erling Smørgrav * These functions process the 'line' string into one of three forms: 53983d2307dSDag-Erling Smørgrav * 54083d2307dSDag-Erling Smørgrav * 1. The full filename (including '/dev') 54183d2307dSDag-Erling Smørgrav * 2. The stripped name (excluding '/dev') 54283d2307dSDag-Erling Smørgrav * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00 54383d2307dSDag-Erling Smørgrav * /dev/pts/1 -> ts/1 ) 54483d2307dSDag-Erling Smørgrav * 54583d2307dSDag-Erling Smørgrav * Form 3 is used on some systems to identify a .tmp.? entry when 54683d2307dSDag-Erling Smørgrav * attempting to remove it. Typically both addition and removal is 54783d2307dSDag-Erling Smørgrav * performed by one application - say, sshd - so as long as the choice 54883d2307dSDag-Erling Smørgrav * uniquely identifies a terminal it's ok. 54983d2307dSDag-Erling Smørgrav */ 55083d2307dSDag-Erling Smørgrav 55183d2307dSDag-Erling Smørgrav 552aa49c926SDag-Erling Smørgrav /* 553aa49c926SDag-Erling Smørgrav * line_fullname(): add the leading '/dev/' if it doesn't exist make 554aa49c926SDag-Erling Smørgrav * sure dst has enough space, if not just copy src (ugh) 555aa49c926SDag-Erling Smørgrav */ 55683d2307dSDag-Erling Smørgrav char * 557d4ecd108SDag-Erling Smørgrav line_fullname(char *dst, const char *src, u_int dstsize) 55883d2307dSDag-Erling Smørgrav { 55983d2307dSDag-Erling Smørgrav memset(dst, '\0', dstsize); 560aa49c926SDag-Erling Smørgrav if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) 56183d2307dSDag-Erling Smørgrav strlcpy(dst, src, dstsize); 562aa49c926SDag-Erling Smørgrav else { 56383d2307dSDag-Erling Smørgrav strlcpy(dst, "/dev/", dstsize); 56483d2307dSDag-Erling Smørgrav strlcat(dst, src, dstsize); 56583d2307dSDag-Erling Smørgrav } 566aa49c926SDag-Erling Smørgrav return (dst); 56783d2307dSDag-Erling Smørgrav } 56883d2307dSDag-Erling Smørgrav 56983d2307dSDag-Erling Smørgrav /* line_stripname(): strip the leading '/dev' if it exists, return dst */ 57083d2307dSDag-Erling Smørgrav char * 57183d2307dSDag-Erling Smørgrav line_stripname(char *dst, const char *src, int dstsize) 57283d2307dSDag-Erling Smørgrav { 57383d2307dSDag-Erling Smørgrav memset(dst, '\0', dstsize); 57483d2307dSDag-Erling Smørgrav if (strncmp(src, "/dev/", 5) == 0) 57583d2307dSDag-Erling Smørgrav strlcpy(dst, src + 5, dstsize); 57683d2307dSDag-Erling Smørgrav else 57783d2307dSDag-Erling Smørgrav strlcpy(dst, src, dstsize); 578aa49c926SDag-Erling Smørgrav return (dst); 57983d2307dSDag-Erling Smørgrav } 58083d2307dSDag-Erling Smørgrav 581aa49c926SDag-Erling Smørgrav /* 582aa49c926SDag-Erling Smørgrav * line_abbrevname(): Return the abbreviated (usually four-character) 58383d2307dSDag-Erling Smørgrav * form of the line (Just use the last <dstsize> characters of the 58483d2307dSDag-Erling Smørgrav * full name.) 58583d2307dSDag-Erling Smørgrav * 58683d2307dSDag-Erling Smørgrav * NOTE: use strncpy because we do NOT necessarily want zero 587aa49c926SDag-Erling Smørgrav * termination 588aa49c926SDag-Erling Smørgrav */ 58983d2307dSDag-Erling Smørgrav char * 59083d2307dSDag-Erling Smørgrav line_abbrevname(char *dst, const char *src, int dstsize) 59183d2307dSDag-Erling Smørgrav { 59283d2307dSDag-Erling Smørgrav size_t len; 59383d2307dSDag-Erling Smørgrav 59483d2307dSDag-Erling Smørgrav memset(dst, '\0', dstsize); 59583d2307dSDag-Erling Smørgrav 59683d2307dSDag-Erling Smørgrav /* Always skip prefix if present */ 59783d2307dSDag-Erling Smørgrav if (strncmp(src, "/dev/", 5) == 0) 59883d2307dSDag-Erling Smørgrav src += 5; 59983d2307dSDag-Erling Smørgrav 60083d2307dSDag-Erling Smørgrav #ifdef WITH_ABBREV_NO_TTY 60183d2307dSDag-Erling Smørgrav if (strncmp(src, "tty", 3) == 0) 60283d2307dSDag-Erling Smørgrav src += 3; 60383d2307dSDag-Erling Smørgrav #endif 60483d2307dSDag-Erling Smørgrav 60583d2307dSDag-Erling Smørgrav len = strlen(src); 60683d2307dSDag-Erling Smørgrav 60783d2307dSDag-Erling Smørgrav if (len > 0) { 60883d2307dSDag-Erling Smørgrav if (((int)len - dstsize) > 0) 60983d2307dSDag-Erling Smørgrav src += ((int)len - dstsize); 61083d2307dSDag-Erling Smørgrav 61183d2307dSDag-Erling Smørgrav /* note: _don't_ change this to strlcpy */ 61283d2307dSDag-Erling Smørgrav strncpy(dst, src, (size_t)dstsize); 61383d2307dSDag-Erling Smørgrav } 61483d2307dSDag-Erling Smørgrav 615aa49c926SDag-Erling Smørgrav return (dst); 61683d2307dSDag-Erling Smørgrav } 61783d2307dSDag-Erling Smørgrav 61883d2307dSDag-Erling Smørgrav /** 61983d2307dSDag-Erling Smørgrav ** utmp utility functions 62083d2307dSDag-Erling Smørgrav ** 62183d2307dSDag-Erling Smørgrav ** These functions manipulate struct utmp, taking system differences 62283d2307dSDag-Erling Smørgrav ** into account. 62383d2307dSDag-Erling Smørgrav **/ 62483d2307dSDag-Erling Smørgrav 62583d2307dSDag-Erling Smørgrav #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN) 62683d2307dSDag-Erling Smørgrav 62783d2307dSDag-Erling Smørgrav /* build the utmp structure */ 62883d2307dSDag-Erling Smørgrav void 62983d2307dSDag-Erling Smørgrav set_utmp_time(struct logininfo *li, struct utmp *ut) 63083d2307dSDag-Erling Smørgrav { 631aa49c926SDag-Erling Smørgrav # if defined(HAVE_TV_IN_UTMP) 63283d2307dSDag-Erling Smørgrav ut->ut_tv.tv_sec = li->tv_sec; 63383d2307dSDag-Erling Smørgrav ut->ut_tv.tv_usec = li->tv_usec; 634aa49c926SDag-Erling Smørgrav # elif defined(HAVE_TIME_IN_UTMP) 63583d2307dSDag-Erling Smørgrav ut->ut_time = li->tv_sec; 63683d2307dSDag-Erling Smørgrav # endif 63783d2307dSDag-Erling Smørgrav } 63883d2307dSDag-Erling Smørgrav 63983d2307dSDag-Erling Smørgrav void 64083d2307dSDag-Erling Smørgrav construct_utmp(struct logininfo *li, 64183d2307dSDag-Erling Smørgrav struct utmp *ut) 64283d2307dSDag-Erling Smørgrav { 643e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 644e73e9afaSDag-Erling Smørgrav struct sockaddr_in6 *sa6; 645e73e9afaSDag-Erling Smørgrav # endif 646aa49c926SDag-Erling Smørgrav 64783d2307dSDag-Erling Smørgrav memset(ut, '\0', sizeof(*ut)); 64883d2307dSDag-Erling Smørgrav 64983d2307dSDag-Erling Smørgrav /* First fill out fields used for both logins and logouts */ 65083d2307dSDag-Erling Smørgrav 65183d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMP 65283d2307dSDag-Erling Smørgrav line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id)); 65383d2307dSDag-Erling Smørgrav # endif 65483d2307dSDag-Erling Smørgrav 65583d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP 65683d2307dSDag-Erling Smørgrav /* This is done here to keep utmp constants out of struct logininfo */ 65783d2307dSDag-Erling Smørgrav switch (li->type) { 65883d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 65983d2307dSDag-Erling Smørgrav ut->ut_type = USER_PROCESS; 660f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 66183d2307dSDag-Erling Smørgrav cray_set_tmpdir(ut); 66283d2307dSDag-Erling Smørgrav #endif 66383d2307dSDag-Erling Smørgrav break; 66483d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 66583d2307dSDag-Erling Smørgrav ut->ut_type = DEAD_PROCESS; 666f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 66783d2307dSDag-Erling Smørgrav cray_retain_utmp(ut, li->pid); 66883d2307dSDag-Erling Smørgrav #endif 66983d2307dSDag-Erling Smørgrav break; 67083d2307dSDag-Erling Smørgrav } 67183d2307dSDag-Erling Smørgrav # endif 67283d2307dSDag-Erling Smørgrav set_utmp_time(li, ut); 67383d2307dSDag-Erling Smørgrav 67483d2307dSDag-Erling Smørgrav line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line)); 67583d2307dSDag-Erling Smørgrav 67683d2307dSDag-Erling Smørgrav # ifdef HAVE_PID_IN_UTMP 67783d2307dSDag-Erling Smørgrav ut->ut_pid = li->pid; 67883d2307dSDag-Erling Smørgrav # endif 67983d2307dSDag-Erling Smørgrav 68083d2307dSDag-Erling Smørgrav /* If we're logging out, leave all other fields blank */ 68183d2307dSDag-Erling Smørgrav if (li->type == LTYPE_LOGOUT) 68283d2307dSDag-Erling Smørgrav return; 68383d2307dSDag-Erling Smørgrav 68483d2307dSDag-Erling Smørgrav /* 68583d2307dSDag-Erling Smørgrav * These fields are only used when logging in, and are blank 68683d2307dSDag-Erling Smørgrav * for logouts. 68783d2307dSDag-Erling Smørgrav */ 68883d2307dSDag-Erling Smørgrav 68983d2307dSDag-Erling Smørgrav /* Use strncpy because we don't necessarily want null termination */ 690aa49c926SDag-Erling Smørgrav strncpy(ut->ut_name, li->username, 691aa49c926SDag-Erling Smørgrav MIN_SIZEOF(ut->ut_name, li->username)); 69283d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP 6930aeb000dSDag-Erling Smørgrav strncpy(ut->ut_host, li->hostname, 6940aeb000dSDag-Erling Smørgrav MIN_SIZEOF(ut->ut_host, li->hostname)); 69583d2307dSDag-Erling Smørgrav # endif 69683d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMP 69783d2307dSDag-Erling Smørgrav /* this is just a 32-bit IP address */ 69883d2307dSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET) 69983d2307dSDag-Erling Smørgrav ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 70083d2307dSDag-Erling Smørgrav # endif 701e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 702e73e9afaSDag-Erling Smørgrav /* this is just a 128-bit IPv6 address */ 703e73e9afaSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET6) { 704e73e9afaSDag-Erling Smørgrav sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); 705e73e9afaSDag-Erling Smørgrav memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); 706e73e9afaSDag-Erling Smørgrav if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { 707e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; 708e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[1] = 0; 709e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[2] = 0; 710e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[3] = 0; 711e73e9afaSDag-Erling Smørgrav } 712e73e9afaSDag-Erling Smørgrav } 713e73e9afaSDag-Erling Smørgrav # endif 71483d2307dSDag-Erling Smørgrav } 71583d2307dSDag-Erling Smørgrav #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */ 71683d2307dSDag-Erling Smørgrav 71783d2307dSDag-Erling Smørgrav /** 71883d2307dSDag-Erling Smørgrav ** utmpx utility functions 71983d2307dSDag-Erling Smørgrav ** 72083d2307dSDag-Erling Smørgrav ** These functions manipulate struct utmpx, accounting for system 72183d2307dSDag-Erling Smørgrav ** variations. 72283d2307dSDag-Erling Smørgrav **/ 72383d2307dSDag-Erling Smørgrav 72483d2307dSDag-Erling Smørgrav #if defined(USE_UTMPX) || defined (USE_WTMPX) 72583d2307dSDag-Erling Smørgrav /* build the utmpx structure */ 72683d2307dSDag-Erling Smørgrav void 72783d2307dSDag-Erling Smørgrav set_utmpx_time(struct logininfo *li, struct utmpx *utx) 72883d2307dSDag-Erling Smørgrav { 729aa49c926SDag-Erling Smørgrav # if defined(HAVE_TV_IN_UTMPX) 73083d2307dSDag-Erling Smørgrav utx->ut_tv.tv_sec = li->tv_sec; 73183d2307dSDag-Erling Smørgrav utx->ut_tv.tv_usec = li->tv_usec; 732aa49c926SDag-Erling Smørgrav # elif defined(HAVE_TIME_IN_UTMPX) 73383d2307dSDag-Erling Smørgrav utx->ut_time = li->tv_sec; 734aa49c926SDag-Erling Smørgrav # endif 73583d2307dSDag-Erling Smørgrav } 73683d2307dSDag-Erling Smørgrav 73783d2307dSDag-Erling Smørgrav void 73883d2307dSDag-Erling Smørgrav construct_utmpx(struct logininfo *li, struct utmpx *utx) 73983d2307dSDag-Erling Smørgrav { 740e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 741e73e9afaSDag-Erling Smørgrav struct sockaddr_in6 *sa6; 742e73e9afaSDag-Erling Smørgrav # endif 74383d2307dSDag-Erling Smørgrav memset(utx, '\0', sizeof(*utx)); 744aa49c926SDag-Erling Smørgrav 74583d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX 74683d2307dSDag-Erling Smørgrav line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); 74783d2307dSDag-Erling Smørgrav # endif 74883d2307dSDag-Erling Smørgrav 74983d2307dSDag-Erling Smørgrav /* this is done here to keep utmp constants out of loginrec.h */ 75083d2307dSDag-Erling Smørgrav switch (li->type) { 75183d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 75283d2307dSDag-Erling Smørgrav utx->ut_type = USER_PROCESS; 75383d2307dSDag-Erling Smørgrav break; 75483d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 75583d2307dSDag-Erling Smørgrav utx->ut_type = DEAD_PROCESS; 75683d2307dSDag-Erling Smørgrav break; 75783d2307dSDag-Erling Smørgrav } 75883d2307dSDag-Erling Smørgrav line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); 75983d2307dSDag-Erling Smørgrav set_utmpx_time(li, utx); 76083d2307dSDag-Erling Smørgrav utx->ut_pid = li->pid; 761aa49c926SDag-Erling Smørgrav 76283d2307dSDag-Erling Smørgrav /* strncpy(): Don't necessarily want null termination */ 763b40cdde6SEd Schouten strncpy(utx->ut_user, li->username, 764b40cdde6SEd Schouten MIN_SIZEOF(utx->ut_user, li->username)); 76583d2307dSDag-Erling Smørgrav 76683d2307dSDag-Erling Smørgrav if (li->type == LTYPE_LOGOUT) 76783d2307dSDag-Erling Smørgrav return; 76883d2307dSDag-Erling Smørgrav 76983d2307dSDag-Erling Smørgrav /* 77083d2307dSDag-Erling Smørgrav * These fields are only used when logging in, and are blank 77183d2307dSDag-Erling Smørgrav * for logouts. 77283d2307dSDag-Erling Smørgrav */ 77383d2307dSDag-Erling Smørgrav 77483d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMPX 775aa49c926SDag-Erling Smørgrav strncpy(utx->ut_host, li->hostname, 776aa49c926SDag-Erling Smørgrav MIN_SIZEOF(utx->ut_host, li->hostname)); 77783d2307dSDag-Erling Smørgrav # endif 77883d2307dSDag-Erling Smørgrav # ifdef HAVE_ADDR_IN_UTMPX 77983d2307dSDag-Erling Smørgrav /* this is just a 32-bit IP address */ 78083d2307dSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET) 78183d2307dSDag-Erling Smørgrav utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 78283d2307dSDag-Erling Smørgrav # endif 783e73e9afaSDag-Erling Smørgrav # ifdef HAVE_ADDR_V6_IN_UTMP 784e73e9afaSDag-Erling Smørgrav /* this is just a 128-bit IPv6 address */ 785e73e9afaSDag-Erling Smørgrav if (li->hostaddr.sa.sa_family == AF_INET6) { 786e73e9afaSDag-Erling Smørgrav sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); 787e73e9afaSDag-Erling Smørgrav memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); 788e73e9afaSDag-Erling Smørgrav if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { 789e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; 790e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[1] = 0; 791e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[2] = 0; 792e73e9afaSDag-Erling Smørgrav ut->ut_addr_v6[3] = 0; 793e73e9afaSDag-Erling Smørgrav } 794e73e9afaSDag-Erling Smørgrav } 795e73e9afaSDag-Erling Smørgrav # endif 79683d2307dSDag-Erling Smørgrav # ifdef HAVE_SYSLEN_IN_UTMPX 79783d2307dSDag-Erling Smørgrav /* ut_syslen is the length of the utx_host string */ 79883d2307dSDag-Erling Smørgrav utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host)); 79983d2307dSDag-Erling Smørgrav # endif 80083d2307dSDag-Erling Smørgrav } 80183d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX || USE_WTMPX */ 80283d2307dSDag-Erling Smørgrav 80383d2307dSDag-Erling Smørgrav /** 80483d2307dSDag-Erling Smørgrav ** Low-level utmp functions 80583d2307dSDag-Erling Smørgrav **/ 80683d2307dSDag-Erling Smørgrav 80783d2307dSDag-Erling Smørgrav /* FIXME: (ATL) utmp_write_direct needs testing */ 80883d2307dSDag-Erling Smørgrav #ifdef USE_UTMP 80983d2307dSDag-Erling Smørgrav 81083d2307dSDag-Erling Smørgrav /* if we can, use pututline() etc. */ 81183d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ 81283d2307dSDag-Erling Smørgrav defined(HAVE_PUTUTLINE) 81383d2307dSDag-Erling Smørgrav # define UTMP_USE_LIBRARY 81483d2307dSDag-Erling Smørgrav # endif 81583d2307dSDag-Erling Smørgrav 81683d2307dSDag-Erling Smørgrav 81783d2307dSDag-Erling Smørgrav /* write a utmp entry with the system's help (pututline() and pals) */ 81883d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY 81983d2307dSDag-Erling Smørgrav static int 82083d2307dSDag-Erling Smørgrav utmp_write_library(struct logininfo *li, struct utmp *ut) 82183d2307dSDag-Erling Smørgrav { 82283d2307dSDag-Erling Smørgrav setutent(); 82383d2307dSDag-Erling Smørgrav pututline(ut); 82483d2307dSDag-Erling Smørgrav # ifdef HAVE_ENDUTENT 82583d2307dSDag-Erling Smørgrav endutent(); 82683d2307dSDag-Erling Smørgrav # endif 827aa49c926SDag-Erling Smørgrav return (1); 82883d2307dSDag-Erling Smørgrav } 82983d2307dSDag-Erling Smørgrav # else /* UTMP_USE_LIBRARY */ 83083d2307dSDag-Erling Smørgrav 831aa49c926SDag-Erling Smørgrav /* 832aa49c926SDag-Erling Smørgrav * Write a utmp entry direct to the file 833aa49c926SDag-Erling Smørgrav * This is a slightly modification of code in OpenBSD's login.c 834aa49c926SDag-Erling Smørgrav */ 83583d2307dSDag-Erling Smørgrav static int 83683d2307dSDag-Erling Smørgrav utmp_write_direct(struct logininfo *li, struct utmp *ut) 83783d2307dSDag-Erling Smørgrav { 83883d2307dSDag-Erling Smørgrav struct utmp old_ut; 83983d2307dSDag-Erling Smørgrav register int fd; 84083d2307dSDag-Erling Smørgrav int tty; 84183d2307dSDag-Erling Smørgrav 84283d2307dSDag-Erling Smørgrav /* FIXME: (ATL) ttyslot() needs local implementation */ 84383d2307dSDag-Erling Smørgrav 84483d2307dSDag-Erling Smørgrav #if defined(HAVE_GETTTYENT) 845aa49c926SDag-Erling Smørgrav struct ttyent *ty; 84683d2307dSDag-Erling Smørgrav 84783d2307dSDag-Erling Smørgrav tty=0; 84883d2307dSDag-Erling Smørgrav setttyent(); 849aa49c926SDag-Erling Smørgrav while (NULL != (ty = getttyent())) { 85083d2307dSDag-Erling Smørgrav tty++; 85183d2307dSDag-Erling Smørgrav if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) 85283d2307dSDag-Erling Smørgrav break; 85383d2307dSDag-Erling Smørgrav } 85483d2307dSDag-Erling Smørgrav endttyent(); 85583d2307dSDag-Erling Smørgrav 856aa49c926SDag-Erling Smørgrav if (NULL == ty) { 85721e764dfSDag-Erling Smørgrav logit("%s: tty not found", __func__); 85821e764dfSDag-Erling Smørgrav return (0); 85983d2307dSDag-Erling Smørgrav } 86083d2307dSDag-Erling Smørgrav #else /* FIXME */ 86183d2307dSDag-Erling Smørgrav 86283d2307dSDag-Erling Smørgrav tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */ 86383d2307dSDag-Erling Smørgrav 86483d2307dSDag-Erling Smørgrav #endif /* HAVE_GETTTYENT */ 86583d2307dSDag-Erling Smørgrav 86683d2307dSDag-Erling Smørgrav if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) { 86721e764dfSDag-Erling Smørgrav off_t pos, ret; 86821e764dfSDag-Erling Smørgrav 86921e764dfSDag-Erling Smørgrav pos = (off_t)tty * sizeof(struct utmp); 87021e764dfSDag-Erling Smørgrav if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { 871aa49c926SDag-Erling Smørgrav logit("%s: lseek: %s", __func__, strerror(errno)); 8724a421b63SDag-Erling Smørgrav close(fd); 87321e764dfSDag-Erling Smørgrav return (0); 87421e764dfSDag-Erling Smørgrav } 87521e764dfSDag-Erling Smørgrav if (ret != pos) { 876aa49c926SDag-Erling Smørgrav logit("%s: Couldn't seek to tty %d slot in %s", 877aa49c926SDag-Erling Smørgrav __func__, tty, UTMP_FILE); 8784a421b63SDag-Erling Smørgrav close(fd); 87921e764dfSDag-Erling Smørgrav return (0); 88021e764dfSDag-Erling Smørgrav } 88183d2307dSDag-Erling Smørgrav /* 88283d2307dSDag-Erling Smørgrav * Prevent luser from zero'ing out ut_host. 88383d2307dSDag-Erling Smørgrav * If the new ut_line is empty but the old one is not 88483d2307dSDag-Erling Smørgrav * and ut_line and ut_name match, preserve the old ut_line. 88583d2307dSDag-Erling Smørgrav */ 88683d2307dSDag-Erling Smørgrav if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && 88783d2307dSDag-Erling Smørgrav (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && 88883d2307dSDag-Erling Smørgrav (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && 889aa49c926SDag-Erling Smørgrav (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) 890aa49c926SDag-Erling Smørgrav memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); 89183d2307dSDag-Erling Smørgrav 89221e764dfSDag-Erling Smørgrav if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { 893aa49c926SDag-Erling Smørgrav logit("%s: lseek: %s", __func__, strerror(errno)); 8944a421b63SDag-Erling Smørgrav close(fd); 89521e764dfSDag-Erling Smørgrav return (0); 89621e764dfSDag-Erling Smørgrav } 89721e764dfSDag-Erling Smørgrav if (ret != pos) { 898aa49c926SDag-Erling Smørgrav logit("%s: Couldn't seek to tty %d slot in %s", 89921e764dfSDag-Erling Smørgrav __func__, tty, UTMP_FILE); 9004a421b63SDag-Erling Smørgrav close(fd); 90121e764dfSDag-Erling Smørgrav return (0); 90221e764dfSDag-Erling Smørgrav } 903aa49c926SDag-Erling Smørgrav if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { 90421e764dfSDag-Erling Smørgrav logit("%s: error writing %s: %s", __func__, 90583d2307dSDag-Erling Smørgrav UTMP_FILE, strerror(errno)); 9064a421b63SDag-Erling Smørgrav close(fd); 9074a421b63SDag-Erling Smørgrav return (0); 908aa49c926SDag-Erling Smørgrav } 90983d2307dSDag-Erling Smørgrav 910aa49c926SDag-Erling Smørgrav close(fd); 911aa49c926SDag-Erling Smørgrav return (1); 91283d2307dSDag-Erling Smørgrav } else { 913aa49c926SDag-Erling Smørgrav return (0); 91483d2307dSDag-Erling Smørgrav } 91583d2307dSDag-Erling Smørgrav } 91683d2307dSDag-Erling Smørgrav # endif /* UTMP_USE_LIBRARY */ 91783d2307dSDag-Erling Smørgrav 91883d2307dSDag-Erling Smørgrav static int 91983d2307dSDag-Erling Smørgrav utmp_perform_login(struct logininfo *li) 92083d2307dSDag-Erling Smørgrav { 92183d2307dSDag-Erling Smørgrav struct utmp ut; 92283d2307dSDag-Erling Smørgrav 92383d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 92483d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY 92583d2307dSDag-Erling Smørgrav if (!utmp_write_library(li, &ut)) { 926aa49c926SDag-Erling Smørgrav logit("%s: utmp_write_library() failed", __func__); 927aa49c926SDag-Erling Smørgrav return (0); 92883d2307dSDag-Erling Smørgrav } 92983d2307dSDag-Erling Smørgrav # else 93083d2307dSDag-Erling Smørgrav if (!utmp_write_direct(li, &ut)) { 931aa49c926SDag-Erling Smørgrav logit("%s: utmp_write_direct() failed", __func__); 932aa49c926SDag-Erling Smørgrav return (0); 93383d2307dSDag-Erling Smørgrav } 93483d2307dSDag-Erling Smørgrav # endif 935aa49c926SDag-Erling Smørgrav return (1); 93683d2307dSDag-Erling Smørgrav } 93783d2307dSDag-Erling Smørgrav 93883d2307dSDag-Erling Smørgrav 93983d2307dSDag-Erling Smørgrav static int 94083d2307dSDag-Erling Smørgrav utmp_perform_logout(struct logininfo *li) 94183d2307dSDag-Erling Smørgrav { 94283d2307dSDag-Erling Smørgrav struct utmp ut; 94383d2307dSDag-Erling Smørgrav 94483d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 94583d2307dSDag-Erling Smørgrav # ifdef UTMP_USE_LIBRARY 94683d2307dSDag-Erling Smørgrav if (!utmp_write_library(li, &ut)) { 947aa49c926SDag-Erling Smørgrav logit("%s: utmp_write_library() failed", __func__); 948aa49c926SDag-Erling Smørgrav return (0); 94983d2307dSDag-Erling Smørgrav } 95083d2307dSDag-Erling Smørgrav # else 95183d2307dSDag-Erling Smørgrav if (!utmp_write_direct(li, &ut)) { 952aa49c926SDag-Erling Smørgrav logit("%s: utmp_write_direct() failed", __func__); 953aa49c926SDag-Erling Smørgrav return (0); 95483d2307dSDag-Erling Smørgrav } 95583d2307dSDag-Erling Smørgrav # endif 956aa49c926SDag-Erling Smørgrav return (1); 95783d2307dSDag-Erling Smørgrav } 95883d2307dSDag-Erling Smørgrav 95983d2307dSDag-Erling Smørgrav 96083d2307dSDag-Erling Smørgrav int 96183d2307dSDag-Erling Smørgrav utmp_write_entry(struct logininfo *li) 96283d2307dSDag-Erling Smørgrav { 96383d2307dSDag-Erling Smørgrav switch(li->type) { 96483d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 965aa49c926SDag-Erling Smørgrav return (utmp_perform_login(li)); 96683d2307dSDag-Erling Smørgrav 96783d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 968aa49c926SDag-Erling Smørgrav return (utmp_perform_logout(li)); 96983d2307dSDag-Erling Smørgrav 97083d2307dSDag-Erling Smørgrav default: 971aa49c926SDag-Erling Smørgrav logit("%s: invalid type field", __func__); 972aa49c926SDag-Erling Smørgrav return (0); 97383d2307dSDag-Erling Smørgrav } 97483d2307dSDag-Erling Smørgrav } 97583d2307dSDag-Erling Smørgrav #endif /* USE_UTMP */ 97683d2307dSDag-Erling Smørgrav 97783d2307dSDag-Erling Smørgrav 97883d2307dSDag-Erling Smørgrav /** 97983d2307dSDag-Erling Smørgrav ** Low-level utmpx functions 98083d2307dSDag-Erling Smørgrav **/ 98183d2307dSDag-Erling Smørgrav 98283d2307dSDag-Erling Smørgrav /* not much point if we don't want utmpx entries */ 98383d2307dSDag-Erling Smørgrav #ifdef USE_UTMPX 98483d2307dSDag-Erling Smørgrav 98583d2307dSDag-Erling Smørgrav /* if we have the wherewithall, use pututxline etc. */ 98683d2307dSDag-Erling Smørgrav # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \ 98783d2307dSDag-Erling Smørgrav defined(HAVE_PUTUTXLINE) 98883d2307dSDag-Erling Smørgrav # define UTMPX_USE_LIBRARY 98983d2307dSDag-Erling Smørgrav # endif 99083d2307dSDag-Erling Smørgrav 99183d2307dSDag-Erling Smørgrav 99283d2307dSDag-Erling Smørgrav /* write a utmpx entry with the system's help (pututxline() and pals) */ 99383d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY 99483d2307dSDag-Erling Smørgrav static int 99583d2307dSDag-Erling Smørgrav utmpx_write_library(struct logininfo *li, struct utmpx *utx) 99683d2307dSDag-Erling Smørgrav { 99783d2307dSDag-Erling Smørgrav setutxent(); 99883d2307dSDag-Erling Smørgrav pututxline(utx); 99983d2307dSDag-Erling Smørgrav 100083d2307dSDag-Erling Smørgrav # ifdef HAVE_ENDUTXENT 100183d2307dSDag-Erling Smørgrav endutxent(); 100283d2307dSDag-Erling Smørgrav # endif 1003aa49c926SDag-Erling Smørgrav return (1); 100483d2307dSDag-Erling Smørgrav } 100583d2307dSDag-Erling Smørgrav 100683d2307dSDag-Erling Smørgrav # else /* UTMPX_USE_LIBRARY */ 100783d2307dSDag-Erling Smørgrav 100883d2307dSDag-Erling Smørgrav /* write a utmp entry direct to the file */ 100983d2307dSDag-Erling Smørgrav static int 101083d2307dSDag-Erling Smørgrav utmpx_write_direct(struct logininfo *li, struct utmpx *utx) 101183d2307dSDag-Erling Smørgrav { 1012aa49c926SDag-Erling Smørgrav logit("%s: not implemented!", __func__); 1013aa49c926SDag-Erling Smørgrav return (0); 101483d2307dSDag-Erling Smørgrav } 101583d2307dSDag-Erling Smørgrav # endif /* UTMPX_USE_LIBRARY */ 101683d2307dSDag-Erling Smørgrav 101783d2307dSDag-Erling Smørgrav static int 101883d2307dSDag-Erling Smørgrav utmpx_perform_login(struct logininfo *li) 101983d2307dSDag-Erling Smørgrav { 102083d2307dSDag-Erling Smørgrav struct utmpx utx; 102183d2307dSDag-Erling Smørgrav 102283d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 102383d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY 102483d2307dSDag-Erling Smørgrav if (!utmpx_write_library(li, &utx)) { 1025aa49c926SDag-Erling Smørgrav logit("%s: utmp_write_library() failed", __func__); 1026aa49c926SDag-Erling Smørgrav return (0); 102783d2307dSDag-Erling Smørgrav } 102883d2307dSDag-Erling Smørgrav # else 102983d2307dSDag-Erling Smørgrav if (!utmpx_write_direct(li, &ut)) { 1030aa49c926SDag-Erling Smørgrav logit("%s: utmp_write_direct() failed", __func__); 1031aa49c926SDag-Erling Smørgrav return (0); 103283d2307dSDag-Erling Smørgrav } 103383d2307dSDag-Erling Smørgrav # endif 1034aa49c926SDag-Erling Smørgrav return (1); 103583d2307dSDag-Erling Smørgrav } 103683d2307dSDag-Erling Smørgrav 103783d2307dSDag-Erling Smørgrav 103883d2307dSDag-Erling Smørgrav static int 103983d2307dSDag-Erling Smørgrav utmpx_perform_logout(struct logininfo *li) 104083d2307dSDag-Erling Smørgrav { 104183d2307dSDag-Erling Smørgrav struct utmpx utx; 104283d2307dSDag-Erling Smørgrav 104383d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 104483d2307dSDag-Erling Smørgrav # ifdef HAVE_ID_IN_UTMPX 104583d2307dSDag-Erling Smørgrav line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id)); 104683d2307dSDag-Erling Smørgrav # endif 104783d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX 104883d2307dSDag-Erling Smørgrav utx.ut_type = DEAD_PROCESS; 104983d2307dSDag-Erling Smørgrav # endif 105083d2307dSDag-Erling Smørgrav 105183d2307dSDag-Erling Smørgrav # ifdef UTMPX_USE_LIBRARY 105283d2307dSDag-Erling Smørgrav utmpx_write_library(li, &utx); 105383d2307dSDag-Erling Smørgrav # else 105483d2307dSDag-Erling Smørgrav utmpx_write_direct(li, &utx); 105583d2307dSDag-Erling Smørgrav # endif 1056aa49c926SDag-Erling Smørgrav return (1); 105783d2307dSDag-Erling Smørgrav } 105883d2307dSDag-Erling Smørgrav 105983d2307dSDag-Erling Smørgrav int 106083d2307dSDag-Erling Smørgrav utmpx_write_entry(struct logininfo *li) 106183d2307dSDag-Erling Smørgrav { 106283d2307dSDag-Erling Smørgrav switch(li->type) { 106383d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 1064aa49c926SDag-Erling Smørgrav return (utmpx_perform_login(li)); 106583d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 1066aa49c926SDag-Erling Smørgrav return (utmpx_perform_logout(li)); 106783d2307dSDag-Erling Smørgrav default: 1068aa49c926SDag-Erling Smørgrav logit("%s: invalid type field", __func__); 1069aa49c926SDag-Erling Smørgrav return (0); 107083d2307dSDag-Erling Smørgrav } 107183d2307dSDag-Erling Smørgrav } 107283d2307dSDag-Erling Smørgrav #endif /* USE_UTMPX */ 107383d2307dSDag-Erling Smørgrav 107483d2307dSDag-Erling Smørgrav 107583d2307dSDag-Erling Smørgrav /** 107683d2307dSDag-Erling Smørgrav ** Low-level wtmp functions 107783d2307dSDag-Erling Smørgrav **/ 107883d2307dSDag-Erling Smørgrav 107983d2307dSDag-Erling Smørgrav #ifdef USE_WTMP 108083d2307dSDag-Erling Smørgrav 1081aa49c926SDag-Erling Smørgrav /* 1082aa49c926SDag-Erling Smørgrav * Write a wtmp entry direct to the end of the file 1083aa49c926SDag-Erling Smørgrav * This is a slight modification of code in OpenBSD's logwtmp.c 1084aa49c926SDag-Erling Smørgrav */ 108583d2307dSDag-Erling Smørgrav static int 108683d2307dSDag-Erling Smørgrav wtmp_write(struct logininfo *li, struct utmp *ut) 108783d2307dSDag-Erling Smørgrav { 108883d2307dSDag-Erling Smørgrav struct stat buf; 108983d2307dSDag-Erling Smørgrav int fd, ret = 1; 109083d2307dSDag-Erling Smørgrav 109183d2307dSDag-Erling Smørgrav if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 1092aa49c926SDag-Erling Smørgrav logit("%s: problem writing %s: %s", __func__, 109383d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 1094aa49c926SDag-Erling Smørgrav return (0); 109583d2307dSDag-Erling Smørgrav } 109683d2307dSDag-Erling Smørgrav if (fstat(fd, &buf) == 0) 1097cf2b5f3bSDag-Erling Smørgrav if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { 109883d2307dSDag-Erling Smørgrav ftruncate(fd, buf.st_size); 1099aa49c926SDag-Erling Smørgrav logit("%s: problem writing %s: %s", __func__, 110083d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 110183d2307dSDag-Erling Smørgrav ret = 0; 110283d2307dSDag-Erling Smørgrav } 1103aa49c926SDag-Erling Smørgrav close(fd); 1104aa49c926SDag-Erling Smørgrav return (ret); 110583d2307dSDag-Erling Smørgrav } 110683d2307dSDag-Erling Smørgrav 110783d2307dSDag-Erling Smørgrav static int 110883d2307dSDag-Erling Smørgrav wtmp_perform_login(struct logininfo *li) 110983d2307dSDag-Erling Smørgrav { 111083d2307dSDag-Erling Smørgrav struct utmp ut; 111183d2307dSDag-Erling Smørgrav 111283d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 1113aa49c926SDag-Erling Smørgrav return (wtmp_write(li, &ut)); 111483d2307dSDag-Erling Smørgrav } 111583d2307dSDag-Erling Smørgrav 111683d2307dSDag-Erling Smørgrav 111783d2307dSDag-Erling Smørgrav static int 111883d2307dSDag-Erling Smørgrav wtmp_perform_logout(struct logininfo *li) 111983d2307dSDag-Erling Smørgrav { 112083d2307dSDag-Erling Smørgrav struct utmp ut; 112183d2307dSDag-Erling Smørgrav 112283d2307dSDag-Erling Smørgrav construct_utmp(li, &ut); 1123aa49c926SDag-Erling Smørgrav return (wtmp_write(li, &ut)); 112483d2307dSDag-Erling Smørgrav } 112583d2307dSDag-Erling Smørgrav 112683d2307dSDag-Erling Smørgrav 112783d2307dSDag-Erling Smørgrav int 112883d2307dSDag-Erling Smørgrav wtmp_write_entry(struct logininfo *li) 112983d2307dSDag-Erling Smørgrav { 113083d2307dSDag-Erling Smørgrav switch(li->type) { 113183d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 1132aa49c926SDag-Erling Smørgrav return (wtmp_perform_login(li)); 113383d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 1134aa49c926SDag-Erling Smørgrav return (wtmp_perform_logout(li)); 113583d2307dSDag-Erling Smørgrav default: 1136aa49c926SDag-Erling Smørgrav logit("%s: invalid type field", __func__); 1137aa49c926SDag-Erling Smørgrav return (0); 113883d2307dSDag-Erling Smørgrav } 113983d2307dSDag-Erling Smørgrav } 114083d2307dSDag-Erling Smørgrav 114183d2307dSDag-Erling Smørgrav 1142aa49c926SDag-Erling Smørgrav /* 1143aa49c926SDag-Erling Smørgrav * Notes on fetching login data from wtmp/wtmpx 114483d2307dSDag-Erling Smørgrav * 114583d2307dSDag-Erling Smørgrav * Logouts are usually recorded with (amongst other things) a blank 114683d2307dSDag-Erling Smørgrav * username on a given tty line. However, some systems (HP-UX is one) 114783d2307dSDag-Erling Smørgrav * leave all fields set, but change the ut_type field to DEAD_PROCESS. 114883d2307dSDag-Erling Smørgrav * 114983d2307dSDag-Erling Smørgrav * Since we're only looking for logins here, we know that the username 115083d2307dSDag-Erling Smørgrav * must be set correctly. On systems that leave it in, we check for 115183d2307dSDag-Erling Smørgrav * ut_type==USER_PROCESS (indicating a login.) 115283d2307dSDag-Erling Smørgrav * 115383d2307dSDag-Erling Smørgrav * Portability: Some systems may set something other than USER_PROCESS 115483d2307dSDag-Erling Smørgrav * to indicate a login process. I don't know of any as I write. Also, 115583d2307dSDag-Erling Smørgrav * it's possible that some systems may both leave the username in 115683d2307dSDag-Erling Smørgrav * place and not have ut_type. 115783d2307dSDag-Erling Smørgrav */ 115883d2307dSDag-Erling Smørgrav 115983d2307dSDag-Erling Smørgrav /* return true if this wtmp entry indicates a login */ 116083d2307dSDag-Erling Smørgrav static int 116183d2307dSDag-Erling Smørgrav wtmp_islogin(struct logininfo *li, struct utmp *ut) 116283d2307dSDag-Erling Smørgrav { 116383d2307dSDag-Erling Smørgrav if (strncmp(li->username, ut->ut_name, 116483d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->username, ut->ut_name)) == 0) { 116583d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMP 116683d2307dSDag-Erling Smørgrav if (ut->ut_type & USER_PROCESS) 1167aa49c926SDag-Erling Smørgrav return (1); 116883d2307dSDag-Erling Smørgrav # else 1169aa49c926SDag-Erling Smørgrav return (1); 117083d2307dSDag-Erling Smørgrav # endif 117183d2307dSDag-Erling Smørgrav } 1172aa49c926SDag-Erling Smørgrav return (0); 117383d2307dSDag-Erling Smørgrav } 117483d2307dSDag-Erling Smørgrav 117583d2307dSDag-Erling Smørgrav int 117683d2307dSDag-Erling Smørgrav wtmp_get_entry(struct logininfo *li) 117783d2307dSDag-Erling Smørgrav { 117883d2307dSDag-Erling Smørgrav struct stat st; 117983d2307dSDag-Erling Smørgrav struct utmp ut; 118083d2307dSDag-Erling Smørgrav int fd, found = 0; 118183d2307dSDag-Erling Smørgrav 118283d2307dSDag-Erling Smørgrav /* Clear the time entries in our logininfo */ 118383d2307dSDag-Erling Smørgrav li->tv_sec = li->tv_usec = 0; 118483d2307dSDag-Erling Smørgrav 118583d2307dSDag-Erling Smørgrav if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { 1186aa49c926SDag-Erling Smørgrav logit("%s: problem opening %s: %s", __func__, 118783d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 1188aa49c926SDag-Erling Smørgrav return (0); 118983d2307dSDag-Erling Smørgrav } 119083d2307dSDag-Erling Smørgrav if (fstat(fd, &st) != 0) { 1191aa49c926SDag-Erling Smørgrav logit("%s: couldn't stat %s: %s", __func__, 119283d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 119383d2307dSDag-Erling Smørgrav close(fd); 1194aa49c926SDag-Erling Smørgrav return (0); 119583d2307dSDag-Erling Smørgrav } 119683d2307dSDag-Erling Smørgrav 119783d2307dSDag-Erling Smørgrav /* Seek to the start of the last struct utmp */ 119883d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { 119983d2307dSDag-Erling Smørgrav /* Looks like we've got a fresh wtmp file */ 120083d2307dSDag-Erling Smørgrav close(fd); 1201aa49c926SDag-Erling Smørgrav return (0); 120283d2307dSDag-Erling Smørgrav } 120383d2307dSDag-Erling Smørgrav 120483d2307dSDag-Erling Smørgrav while (!found) { 120583d2307dSDag-Erling Smørgrav if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { 1206aa49c926SDag-Erling Smørgrav logit("%s: read of %s failed: %s", __func__, 120783d2307dSDag-Erling Smørgrav WTMP_FILE, strerror(errno)); 120883d2307dSDag-Erling Smørgrav close (fd); 1209aa49c926SDag-Erling Smørgrav return (0); 121083d2307dSDag-Erling Smørgrav } 121183d2307dSDag-Erling Smørgrav if (wtmp_islogin(li, &ut) ) { 121283d2307dSDag-Erling Smørgrav found = 1; 1213aa49c926SDag-Erling Smørgrav /* 1214aa49c926SDag-Erling Smørgrav * We've already checked for a time in struct 1215aa49c926SDag-Erling Smørgrav * utmp, in login_getlast() 1216aa49c926SDag-Erling Smørgrav */ 121783d2307dSDag-Erling Smørgrav # ifdef HAVE_TIME_IN_UTMP 121883d2307dSDag-Erling Smørgrav li->tv_sec = ut.ut_time; 121983d2307dSDag-Erling Smørgrav # else 122083d2307dSDag-Erling Smørgrav # if HAVE_TV_IN_UTMP 122183d2307dSDag-Erling Smørgrav li->tv_sec = ut.ut_tv.tv_sec; 122283d2307dSDag-Erling Smørgrav # endif 122383d2307dSDag-Erling Smørgrav # endif 122483d2307dSDag-Erling Smørgrav line_fullname(li->line, ut.ut_line, 122583d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->line, ut.ut_line)); 122683d2307dSDag-Erling Smørgrav # ifdef HAVE_HOST_IN_UTMP 122783d2307dSDag-Erling Smørgrav strlcpy(li->hostname, ut.ut_host, 122883d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->hostname, ut.ut_host)); 122983d2307dSDag-Erling Smørgrav # endif 123083d2307dSDag-Erling Smørgrav continue; 123183d2307dSDag-Erling Smørgrav } 123283d2307dSDag-Erling Smørgrav /* Seek back 2 x struct utmp */ 123383d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { 123483d2307dSDag-Erling Smørgrav /* We've found the start of the file, so quit */ 123583d2307dSDag-Erling Smørgrav close(fd); 1236aa49c926SDag-Erling Smørgrav return (0); 123783d2307dSDag-Erling Smørgrav } 123883d2307dSDag-Erling Smørgrav } 123983d2307dSDag-Erling Smørgrav 124083d2307dSDag-Erling Smørgrav /* We found an entry. Tidy up and return */ 124183d2307dSDag-Erling Smørgrav close(fd); 1242aa49c926SDag-Erling Smørgrav return (1); 124383d2307dSDag-Erling Smørgrav } 124483d2307dSDag-Erling Smørgrav # endif /* USE_WTMP */ 124583d2307dSDag-Erling Smørgrav 124683d2307dSDag-Erling Smørgrav 124783d2307dSDag-Erling Smørgrav /** 124883d2307dSDag-Erling Smørgrav ** Low-level wtmpx functions 124983d2307dSDag-Erling Smørgrav **/ 125083d2307dSDag-Erling Smørgrav 125183d2307dSDag-Erling Smørgrav #ifdef USE_WTMPX 1252aa49c926SDag-Erling Smørgrav /* 1253aa49c926SDag-Erling Smørgrav * Write a wtmpx entry direct to the end of the file 1254aa49c926SDag-Erling Smørgrav * This is a slight modification of code in OpenBSD's logwtmp.c 1255aa49c926SDag-Erling Smørgrav */ 125683d2307dSDag-Erling Smørgrav static int 125783d2307dSDag-Erling Smørgrav wtmpx_write(struct logininfo *li, struct utmpx *utx) 125883d2307dSDag-Erling Smørgrav { 12591ec0d754SDag-Erling Smørgrav #ifndef HAVE_UPDWTMPX 126083d2307dSDag-Erling Smørgrav struct stat buf; 126183d2307dSDag-Erling Smørgrav int fd, ret = 1; 126283d2307dSDag-Erling Smørgrav 126383d2307dSDag-Erling Smørgrav if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 1264aa49c926SDag-Erling Smørgrav logit("%s: problem opening %s: %s", __func__, 126583d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 1266aa49c926SDag-Erling Smørgrav return (0); 126783d2307dSDag-Erling Smørgrav } 126883d2307dSDag-Erling Smørgrav 126983d2307dSDag-Erling Smørgrav if (fstat(fd, &buf) == 0) 1270cf2b5f3bSDag-Erling Smørgrav if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) { 127183d2307dSDag-Erling Smørgrav ftruncate(fd, buf.st_size); 1272aa49c926SDag-Erling Smørgrav logit("%s: problem writing %s: %s", __func__, 127383d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 127483d2307dSDag-Erling Smørgrav ret = 0; 127583d2307dSDag-Erling Smørgrav } 1276aa49c926SDag-Erling Smørgrav close(fd); 127783d2307dSDag-Erling Smørgrav 1278aa49c926SDag-Erling Smørgrav return (ret); 12791ec0d754SDag-Erling Smørgrav #else 12801ec0d754SDag-Erling Smørgrav updwtmpx(WTMPX_FILE, utx); 1281aa49c926SDag-Erling Smørgrav return (1); 12821ec0d754SDag-Erling Smørgrav #endif 128383d2307dSDag-Erling Smørgrav } 128483d2307dSDag-Erling Smørgrav 128583d2307dSDag-Erling Smørgrav 128683d2307dSDag-Erling Smørgrav static int 128783d2307dSDag-Erling Smørgrav wtmpx_perform_login(struct logininfo *li) 128883d2307dSDag-Erling Smørgrav { 128983d2307dSDag-Erling Smørgrav struct utmpx utx; 129083d2307dSDag-Erling Smørgrav 129183d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 1292aa49c926SDag-Erling Smørgrav return (wtmpx_write(li, &utx)); 129383d2307dSDag-Erling Smørgrav } 129483d2307dSDag-Erling Smørgrav 129583d2307dSDag-Erling Smørgrav 129683d2307dSDag-Erling Smørgrav static int 129783d2307dSDag-Erling Smørgrav wtmpx_perform_logout(struct logininfo *li) 129883d2307dSDag-Erling Smørgrav { 129983d2307dSDag-Erling Smørgrav struct utmpx utx; 130083d2307dSDag-Erling Smørgrav 130183d2307dSDag-Erling Smørgrav construct_utmpx(li, &utx); 1302aa49c926SDag-Erling Smørgrav return (wtmpx_write(li, &utx)); 130383d2307dSDag-Erling Smørgrav } 130483d2307dSDag-Erling Smørgrav 130583d2307dSDag-Erling Smørgrav 130683d2307dSDag-Erling Smørgrav int 130783d2307dSDag-Erling Smørgrav wtmpx_write_entry(struct logininfo *li) 130883d2307dSDag-Erling Smørgrav { 130983d2307dSDag-Erling Smørgrav switch(li->type) { 131083d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 1311aa49c926SDag-Erling Smørgrav return (wtmpx_perform_login(li)); 131283d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 1313aa49c926SDag-Erling Smørgrav return (wtmpx_perform_logout(li)); 131483d2307dSDag-Erling Smørgrav default: 1315aa49c926SDag-Erling Smørgrav logit("%s: invalid type field", __func__); 1316aa49c926SDag-Erling Smørgrav return (0); 131783d2307dSDag-Erling Smørgrav } 131883d2307dSDag-Erling Smørgrav } 131983d2307dSDag-Erling Smørgrav 132083d2307dSDag-Erling Smørgrav /* Please see the notes above wtmp_islogin() for information about the 132183d2307dSDag-Erling Smørgrav next two functions */ 132283d2307dSDag-Erling Smørgrav 132383d2307dSDag-Erling Smørgrav /* Return true if this wtmpx entry indicates a login */ 132483d2307dSDag-Erling Smørgrav static int 132583d2307dSDag-Erling Smørgrav wtmpx_islogin(struct logininfo *li, struct utmpx *utx) 132683d2307dSDag-Erling Smørgrav { 1327b15c8340SDag-Erling Smørgrav if (strncmp(li->username, utx->ut_user, 1328b15c8340SDag-Erling Smørgrav MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) { 132983d2307dSDag-Erling Smørgrav # ifdef HAVE_TYPE_IN_UTMPX 133083d2307dSDag-Erling Smørgrav if (utx->ut_type == USER_PROCESS) 1331aa49c926SDag-Erling Smørgrav return (1); 133283d2307dSDag-Erling Smørgrav # else 1333aa49c926SDag-Erling Smørgrav return (1); 133483d2307dSDag-Erling Smørgrav # endif 133583d2307dSDag-Erling Smørgrav } 1336aa49c926SDag-Erling Smørgrav return (0); 133783d2307dSDag-Erling Smørgrav } 133883d2307dSDag-Erling Smørgrav 133983d2307dSDag-Erling Smørgrav 134083d2307dSDag-Erling Smørgrav int 134183d2307dSDag-Erling Smørgrav wtmpx_get_entry(struct logininfo *li) 134283d2307dSDag-Erling Smørgrav { 134383d2307dSDag-Erling Smørgrav struct stat st; 134483d2307dSDag-Erling Smørgrav struct utmpx utx; 134583d2307dSDag-Erling Smørgrav int fd, found=0; 134683d2307dSDag-Erling Smørgrav 134783d2307dSDag-Erling Smørgrav /* Clear the time entries */ 134883d2307dSDag-Erling Smørgrav li->tv_sec = li->tv_usec = 0; 134983d2307dSDag-Erling Smørgrav 135083d2307dSDag-Erling Smørgrav if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { 1351aa49c926SDag-Erling Smørgrav logit("%s: problem opening %s: %s", __func__, 135283d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 1353aa49c926SDag-Erling Smørgrav return (0); 135483d2307dSDag-Erling Smørgrav } 135583d2307dSDag-Erling Smørgrav if (fstat(fd, &st) != 0) { 1356aa49c926SDag-Erling Smørgrav logit("%s: couldn't stat %s: %s", __func__, 1357f388f5efSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 135883d2307dSDag-Erling Smørgrav close(fd); 1359aa49c926SDag-Erling Smørgrav return (0); 136083d2307dSDag-Erling Smørgrav } 136183d2307dSDag-Erling Smørgrav 136283d2307dSDag-Erling Smørgrav /* Seek to the start of the last struct utmpx */ 136383d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { 136483d2307dSDag-Erling Smørgrav /* probably a newly rotated wtmpx file */ 136583d2307dSDag-Erling Smørgrav close(fd); 1366aa49c926SDag-Erling Smørgrav return (0); 136783d2307dSDag-Erling Smørgrav } 136883d2307dSDag-Erling Smørgrav 136983d2307dSDag-Erling Smørgrav while (!found) { 137083d2307dSDag-Erling Smørgrav if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { 1371aa49c926SDag-Erling Smørgrav logit("%s: read of %s failed: %s", __func__, 137283d2307dSDag-Erling Smørgrav WTMPX_FILE, strerror(errno)); 137383d2307dSDag-Erling Smørgrav close (fd); 1374aa49c926SDag-Erling Smørgrav return (0); 137583d2307dSDag-Erling Smørgrav } 1376aa49c926SDag-Erling Smørgrav /* 1377aa49c926SDag-Erling Smørgrav * Logouts are recorded as a blank username on a particular 1378aa49c926SDag-Erling Smørgrav * line. So, we just need to find the username in struct utmpx 1379aa49c926SDag-Erling Smørgrav */ 138083d2307dSDag-Erling Smørgrav if (wtmpx_islogin(li, &utx)) { 1381f388f5efSDag-Erling Smørgrav found = 1; 1382aa49c926SDag-Erling Smørgrav # if defined(HAVE_TV_IN_UTMPX) 138383d2307dSDag-Erling Smørgrav li->tv_sec = utx.ut_tv.tv_sec; 1384aa49c926SDag-Erling Smørgrav # elif defined(HAVE_TIME_IN_UTMPX) 138583d2307dSDag-Erling Smørgrav li->tv_sec = utx.ut_time; 138683d2307dSDag-Erling Smørgrav # endif 138783d2307dSDag-Erling Smørgrav line_fullname(li->line, utx.ut_line, sizeof(li->line)); 1388aa49c926SDag-Erling Smørgrav # if defined(HAVE_HOST_IN_UTMPX) 138983d2307dSDag-Erling Smørgrav strlcpy(li->hostname, utx.ut_host, 139083d2307dSDag-Erling Smørgrav MIN_SIZEOF(li->hostname, utx.ut_host)); 139183d2307dSDag-Erling Smørgrav # endif 139283d2307dSDag-Erling Smørgrav continue; 139383d2307dSDag-Erling Smørgrav } 139483d2307dSDag-Erling Smørgrav if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { 139583d2307dSDag-Erling Smørgrav close(fd); 1396aa49c926SDag-Erling Smørgrav return (0); 139783d2307dSDag-Erling Smørgrav } 139883d2307dSDag-Erling Smørgrav } 139983d2307dSDag-Erling Smørgrav 140083d2307dSDag-Erling Smørgrav close(fd); 1401aa49c926SDag-Erling Smørgrav return (1); 140283d2307dSDag-Erling Smørgrav } 140383d2307dSDag-Erling Smørgrav #endif /* USE_WTMPX */ 140483d2307dSDag-Erling Smørgrav 140583d2307dSDag-Erling Smørgrav /** 140683d2307dSDag-Erling Smørgrav ** Low-level libutil login() functions 140783d2307dSDag-Erling Smørgrav **/ 140883d2307dSDag-Erling Smørgrav 140983d2307dSDag-Erling Smørgrav #ifdef USE_LOGIN 141083d2307dSDag-Erling Smørgrav static int 141183d2307dSDag-Erling Smørgrav syslogin_perform_login(struct logininfo *li) 141283d2307dSDag-Erling Smørgrav { 141383d2307dSDag-Erling Smørgrav struct utmp *ut; 141483d2307dSDag-Erling Smørgrav 1415aa49c926SDag-Erling Smørgrav ut = xmalloc(sizeof(*ut)); 141683d2307dSDag-Erling Smørgrav construct_utmp(li, ut); 141783d2307dSDag-Erling Smørgrav login(ut); 1418e73e9afaSDag-Erling Smørgrav free(ut); 141983d2307dSDag-Erling Smørgrav 1420aa49c926SDag-Erling Smørgrav return (1); 142183d2307dSDag-Erling Smørgrav } 142283d2307dSDag-Erling Smørgrav 142383d2307dSDag-Erling Smørgrav static int 142483d2307dSDag-Erling Smørgrav syslogin_perform_logout(struct logininfo *li) 142583d2307dSDag-Erling Smørgrav { 142683d2307dSDag-Erling Smørgrav # ifdef HAVE_LOGOUT 14275962c0e9SDag-Erling Smørgrav char line[UT_LINESIZE]; 142883d2307dSDag-Erling Smørgrav 142983d2307dSDag-Erling Smørgrav (void)line_stripname(line, li->line, sizeof(line)); 143083d2307dSDag-Erling Smørgrav 1431aa49c926SDag-Erling Smørgrav if (!logout(line)) 1432aa49c926SDag-Erling Smørgrav logit("%s: logout() returned an error", __func__); 143383d2307dSDag-Erling Smørgrav # ifdef HAVE_LOGWTMP 1434aa49c926SDag-Erling Smørgrav else 143583d2307dSDag-Erling Smørgrav logwtmp(line, "", ""); 143683d2307dSDag-Erling Smørgrav # endif 143783d2307dSDag-Erling Smørgrav /* FIXME: (ATL - if the need arises) What to do if we have 143883d2307dSDag-Erling Smørgrav * login, but no logout? what if logout but no logwtmp? All 143983d2307dSDag-Erling Smørgrav * routines are in libutil so they should all be there, 144083d2307dSDag-Erling Smørgrav * but... */ 144183d2307dSDag-Erling Smørgrav # endif 1442aa49c926SDag-Erling Smørgrav return (1); 144383d2307dSDag-Erling Smørgrav } 144483d2307dSDag-Erling Smørgrav 144583d2307dSDag-Erling Smørgrav int 144683d2307dSDag-Erling Smørgrav syslogin_write_entry(struct logininfo *li) 144783d2307dSDag-Erling Smørgrav { 144883d2307dSDag-Erling Smørgrav switch (li->type) { 144983d2307dSDag-Erling Smørgrav case LTYPE_LOGIN: 1450aa49c926SDag-Erling Smørgrav return (syslogin_perform_login(li)); 145183d2307dSDag-Erling Smørgrav case LTYPE_LOGOUT: 1452aa49c926SDag-Erling Smørgrav return (syslogin_perform_logout(li)); 145383d2307dSDag-Erling Smørgrav default: 1454aa49c926SDag-Erling Smørgrav logit("%s: Invalid type field", __func__); 1455aa49c926SDag-Erling Smørgrav return (0); 145683d2307dSDag-Erling Smørgrav } 145783d2307dSDag-Erling Smørgrav } 145883d2307dSDag-Erling Smørgrav #endif /* USE_LOGIN */ 145983d2307dSDag-Erling Smørgrav 146083d2307dSDag-Erling Smørgrav /* end of file log-syslogin.c */ 146183d2307dSDag-Erling Smørgrav 146283d2307dSDag-Erling Smørgrav /** 146383d2307dSDag-Erling Smørgrav ** Low-level lastlog functions 146483d2307dSDag-Erling Smørgrav **/ 146583d2307dSDag-Erling Smørgrav 146683d2307dSDag-Erling Smørgrav #ifdef USE_LASTLOG 146783d2307dSDag-Erling Smørgrav 1468cce7d346SDag-Erling Smørgrav #if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME) 1469cce7d346SDag-Erling Smørgrav /* open the file (using filemode) and seek to the login entry */ 147083d2307dSDag-Erling Smørgrav static int 1471cce7d346SDag-Erling Smørgrav lastlog_openseek(struct logininfo *li, int *fd, int filemode) 147283d2307dSDag-Erling Smørgrav { 1473cce7d346SDag-Erling Smørgrav off_t offset; 1474cce7d346SDag-Erling Smørgrav char lastlog_file[1024]; 147583d2307dSDag-Erling Smørgrav struct stat st; 147683d2307dSDag-Erling Smørgrav 147783d2307dSDag-Erling Smørgrav if (stat(LASTLOG_FILE, &st) != 0) { 1478aa49c926SDag-Erling Smørgrav logit("%s: Couldn't stat %s: %s", __func__, 1479aa49c926SDag-Erling Smørgrav LASTLOG_FILE, strerror(errno)); 1480aa49c926SDag-Erling Smørgrav return (0); 148183d2307dSDag-Erling Smørgrav } 1482cce7d346SDag-Erling Smørgrav if (S_ISDIR(st.st_mode)) { 148383d2307dSDag-Erling Smørgrav snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", 148483d2307dSDag-Erling Smørgrav LASTLOG_FILE, li->username); 1485cce7d346SDag-Erling Smørgrav } else if (S_ISREG(st.st_mode)) { 1486cce7d346SDag-Erling Smørgrav strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); 1487cce7d346SDag-Erling Smørgrav } else { 1488aa49c926SDag-Erling Smørgrav logit("%s: %.100s is not a file or directory!", __func__, 148983d2307dSDag-Erling Smørgrav LASTLOG_FILE); 1490aa49c926SDag-Erling Smørgrav return (0); 149183d2307dSDag-Erling Smørgrav } 149283d2307dSDag-Erling Smørgrav 1493cf2b5f3bSDag-Erling Smørgrav *fd = open(lastlog_file, filemode, 0600); 149483d2307dSDag-Erling Smørgrav if (*fd < 0) { 1495aa49c926SDag-Erling Smørgrav debug("%s: Couldn't open %s: %s", __func__, 149683d2307dSDag-Erling Smørgrav lastlog_file, strerror(errno)); 1497aa49c926SDag-Erling Smørgrav return (0); 149883d2307dSDag-Erling Smørgrav } 149983d2307dSDag-Erling Smørgrav 1500cce7d346SDag-Erling Smørgrav if (S_ISREG(st.st_mode)) { 150183d2307dSDag-Erling Smørgrav /* find this uid's offset in the lastlog file */ 15024a421b63SDag-Erling Smørgrav offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog)); 150383d2307dSDag-Erling Smørgrav 150483d2307dSDag-Erling Smørgrav if (lseek(*fd, offset, SEEK_SET) != offset) { 1505aa49c926SDag-Erling Smørgrav logit("%s: %s->lseek(): %s", __func__, 150683d2307dSDag-Erling Smørgrav lastlog_file, strerror(errno)); 15074a421b63SDag-Erling Smørgrav close(*fd); 1508aa49c926SDag-Erling Smørgrav return (0); 150983d2307dSDag-Erling Smørgrav } 151083d2307dSDag-Erling Smørgrav } 151183d2307dSDag-Erling Smørgrav 1512aa49c926SDag-Erling Smørgrav return (1); 151383d2307dSDag-Erling Smørgrav } 1514cce7d346SDag-Erling Smørgrav #endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */ 151583d2307dSDag-Erling Smørgrav 1516cce7d346SDag-Erling Smørgrav #ifdef LASTLOG_WRITE_PUTUTXLINE 1517cce7d346SDag-Erling Smørgrav int 1518cce7d346SDag-Erling Smørgrav lastlog_write_entry(struct logininfo *li) 1519cce7d346SDag-Erling Smørgrav { 1520cce7d346SDag-Erling Smørgrav switch(li->type) { 1521cce7d346SDag-Erling Smørgrav case LTYPE_LOGIN: 1522cce7d346SDag-Erling Smørgrav return 1; /* lastlog written by pututxline */ 1523cce7d346SDag-Erling Smørgrav default: 1524cce7d346SDag-Erling Smørgrav logit("lastlog_write_entry: Invalid type field"); 1525cce7d346SDag-Erling Smørgrav return 0; 1526cce7d346SDag-Erling Smørgrav } 1527cce7d346SDag-Erling Smørgrav } 1528cce7d346SDag-Erling Smørgrav #else /* LASTLOG_WRITE_PUTUTXLINE */ 1529cce7d346SDag-Erling Smørgrav int 1530cce7d346SDag-Erling Smørgrav lastlog_write_entry(struct logininfo *li) 153183d2307dSDag-Erling Smørgrav { 153283d2307dSDag-Erling Smørgrav struct lastlog last; 153383d2307dSDag-Erling Smørgrav int fd; 153483d2307dSDag-Erling Smørgrav 1535cce7d346SDag-Erling Smørgrav switch(li->type) { 1536cce7d346SDag-Erling Smørgrav case LTYPE_LOGIN: 153783d2307dSDag-Erling Smørgrav /* create our struct lastlog */ 1538cce7d346SDag-Erling Smørgrav memset(&last, '\0', sizeof(last)); 1539cce7d346SDag-Erling Smørgrav line_stripname(last.ll_line, li->line, sizeof(last.ll_line)); 1540cce7d346SDag-Erling Smørgrav strlcpy(last.ll_host, li->hostname, 1541cce7d346SDag-Erling Smørgrav MIN_SIZEOF(last.ll_host, li->hostname)); 1542cce7d346SDag-Erling Smørgrav last.ll_time = li->tv_sec; 154383d2307dSDag-Erling Smørgrav 154483d2307dSDag-Erling Smørgrav if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) 154583d2307dSDag-Erling Smørgrav return (0); 154683d2307dSDag-Erling Smørgrav 154783d2307dSDag-Erling Smørgrav /* write the entry */ 1548cf2b5f3bSDag-Erling Smørgrav if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) { 154983d2307dSDag-Erling Smørgrav close(fd); 1550aa49c926SDag-Erling Smørgrav logit("%s: Error writing to %s: %s", __func__, 155183d2307dSDag-Erling Smørgrav LASTLOG_FILE, strerror(errno)); 1552aa49c926SDag-Erling Smørgrav return (0); 155383d2307dSDag-Erling Smørgrav } 155483d2307dSDag-Erling Smørgrav 155583d2307dSDag-Erling Smørgrav close(fd); 1556aa49c926SDag-Erling Smørgrav return (1); 155783d2307dSDag-Erling Smørgrav default: 1558aa49c926SDag-Erling Smørgrav logit("%s: Invalid type field", __func__); 1559aa49c926SDag-Erling Smørgrav return (0); 156083d2307dSDag-Erling Smørgrav } 156183d2307dSDag-Erling Smørgrav } 1562cce7d346SDag-Erling Smørgrav #endif /* LASTLOG_WRITE_PUTUTXLINE */ 156383d2307dSDag-Erling Smørgrav 1564cce7d346SDag-Erling Smørgrav #ifdef HAVE_GETLASTLOGXBYNAME 1565cce7d346SDag-Erling Smørgrav int 1566cce7d346SDag-Erling Smørgrav lastlog_get_entry(struct logininfo *li) 156783d2307dSDag-Erling Smørgrav { 1568cce7d346SDag-Erling Smørgrav struct lastlogx l, *ll; 156983d2307dSDag-Erling Smørgrav 1570cce7d346SDag-Erling Smørgrav if ((ll = getlastlogxbyname(li->username, &l)) == NULL) { 1571cce7d346SDag-Erling Smørgrav memset(&l, '\0', sizeof(l)); 1572cce7d346SDag-Erling Smørgrav ll = &l; 1573cce7d346SDag-Erling Smørgrav } 1574cce7d346SDag-Erling Smørgrav line_fullname(li->line, ll->ll_line, sizeof(li->line)); 1575cce7d346SDag-Erling Smørgrav strlcpy(li->hostname, ll->ll_host, 1576cce7d346SDag-Erling Smørgrav MIN_SIZEOF(li->hostname, ll->ll_host)); 1577cce7d346SDag-Erling Smørgrav li->tv_sec = ll->ll_tv.tv_sec; 1578cce7d346SDag-Erling Smørgrav li->tv_usec = ll->ll_tv.tv_usec; 1579cce7d346SDag-Erling Smørgrav return (1); 1580cce7d346SDag-Erling Smørgrav } 1581cce7d346SDag-Erling Smørgrav #else /* HAVE_GETLASTLOGXBYNAME */ 158283d2307dSDag-Erling Smørgrav int 158383d2307dSDag-Erling Smørgrav lastlog_get_entry(struct logininfo *li) 158483d2307dSDag-Erling Smørgrav { 158583d2307dSDag-Erling Smørgrav struct lastlog last; 1586e73e9afaSDag-Erling Smørgrav int fd, ret; 158783d2307dSDag-Erling Smørgrav 158883d2307dSDag-Erling Smørgrav if (!lastlog_openseek(li, &fd, O_RDONLY)) 1589e73e9afaSDag-Erling Smørgrav return (0); 159083d2307dSDag-Erling Smørgrav 1591e73e9afaSDag-Erling Smørgrav ret = atomicio(read, fd, &last, sizeof(last)); 159283d2307dSDag-Erling Smørgrav close(fd); 1593e73e9afaSDag-Erling Smørgrav 1594e73e9afaSDag-Erling Smørgrav switch (ret) { 1595e73e9afaSDag-Erling Smørgrav case 0: 1596e73e9afaSDag-Erling Smørgrav memset(&last, '\0', sizeof(last)); 1597e73e9afaSDag-Erling Smørgrav /* FALLTHRU */ 1598e73e9afaSDag-Erling Smørgrav case sizeof(last): 1599cce7d346SDag-Erling Smørgrav line_fullname(li->line, last.ll_line, sizeof(li->line)); 1600cce7d346SDag-Erling Smørgrav strlcpy(li->hostname, last.ll_host, 1601cce7d346SDag-Erling Smørgrav MIN_SIZEOF(li->hostname, last.ll_host)); 1602cce7d346SDag-Erling Smørgrav li->tv_sec = last.ll_time; 1603e73e9afaSDag-Erling Smørgrav return (1); 1604e73e9afaSDag-Erling Smørgrav case -1: 1605e73e9afaSDag-Erling Smørgrav error("%s: Error reading from %s: %s", __func__, 160683d2307dSDag-Erling Smørgrav LASTLOG_FILE, strerror(errno)); 1607e73e9afaSDag-Erling Smørgrav return (0); 1608e73e9afaSDag-Erling Smørgrav default: 1609e73e9afaSDag-Erling Smørgrav error("%s: Error reading from %s: Expecting %d, got %d", 1610b74df5b2SDag-Erling Smørgrav __func__, LASTLOG_FILE, (int)sizeof(last), ret); 1611e73e9afaSDag-Erling Smørgrav return (0); 161283d2307dSDag-Erling Smørgrav } 161383d2307dSDag-Erling Smørgrav 1614e73e9afaSDag-Erling Smørgrav /* NOTREACHED */ 1615e73e9afaSDag-Erling Smørgrav return (0); 161683d2307dSDag-Erling Smørgrav } 1617cce7d346SDag-Erling Smørgrav #endif /* HAVE_GETLASTLOGXBYNAME */ 161883d2307dSDag-Erling Smørgrav #endif /* USE_LASTLOG */ 1619aa49c926SDag-Erling Smørgrav 16208ad9b54aSDag-Erling Smørgrav #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \ 16218ad9b54aSDag-Erling Smørgrav defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER) 1622b40cdde6SEd Schouten int 1623b40cdde6SEd Schouten utmpx_get_entry(struct logininfo *li) 1624b40cdde6SEd Schouten { 1625b40cdde6SEd Schouten struct utmpx *utx; 1626b40cdde6SEd Schouten 1627b40cdde6SEd Schouten if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0) 1628b40cdde6SEd Schouten return (0); 1629b40cdde6SEd Schouten utx = getutxuser(li->username); 1630b40cdde6SEd Schouten if (utx == NULL) { 1631b40cdde6SEd Schouten endutxent(); 1632b40cdde6SEd Schouten return (0); 1633b40cdde6SEd Schouten } 1634b40cdde6SEd Schouten 1635b40cdde6SEd Schouten line_fullname(li->line, utx->ut_line, 1636b40cdde6SEd Schouten MIN_SIZEOF(li->line, utx->ut_line)); 1637b40cdde6SEd Schouten strlcpy(li->hostname, utx->ut_host, 1638b40cdde6SEd Schouten MIN_SIZEOF(li->hostname, utx->ut_host)); 1639b40cdde6SEd Schouten li->tv_sec = utx->ut_tv.tv_sec; 1640b40cdde6SEd Schouten li->tv_usec = utx->ut_tv.tv_usec; 1641b40cdde6SEd Schouten endutxent(); 1642b40cdde6SEd Schouten return (1); 1643b40cdde6SEd Schouten } 16448ad9b54aSDag-Erling Smørgrav #endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */ 1645b40cdde6SEd Schouten 1646aa49c926SDag-Erling Smørgrav #ifdef USE_BTMP 1647aa49c926SDag-Erling Smørgrav /* 1648aa49c926SDag-Erling Smørgrav * Logs failed login attempts in _PATH_BTMP if that exists. 1649aa49c926SDag-Erling Smørgrav * The most common login failure is to give password instead of username. 1650aa49c926SDag-Erling Smørgrav * So the _PATH_BTMP file checked for the correct permission, so that 1651aa49c926SDag-Erling Smørgrav * only root can read it. 1652aa49c926SDag-Erling Smørgrav */ 1653aa49c926SDag-Erling Smørgrav 1654aa49c926SDag-Erling Smørgrav void 1655aa49c926SDag-Erling Smørgrav record_failed_login(const char *username, const char *hostname, 1656aa49c926SDag-Erling Smørgrav const char *ttyn) 1657aa49c926SDag-Erling Smørgrav { 1658aa49c926SDag-Erling Smørgrav int fd; 1659aa49c926SDag-Erling Smørgrav struct utmp ut; 1660aa49c926SDag-Erling Smørgrav struct sockaddr_storage from; 1661b74df5b2SDag-Erling Smørgrav socklen_t fromlen = sizeof(from); 1662aa49c926SDag-Erling Smørgrav struct sockaddr_in *a4; 1663aa49c926SDag-Erling Smørgrav struct sockaddr_in6 *a6; 1664aa49c926SDag-Erling Smørgrav time_t t; 1665aa49c926SDag-Erling Smørgrav struct stat fst; 1666aa49c926SDag-Erling Smørgrav 1667aa49c926SDag-Erling Smørgrav if (geteuid() != 0) 1668aa49c926SDag-Erling Smørgrav return; 1669aa49c926SDag-Erling Smørgrav if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) { 1670aa49c926SDag-Erling Smørgrav debug("Unable to open the btmp file %s: %s", _PATH_BTMP, 1671aa49c926SDag-Erling Smørgrav strerror(errno)); 1672aa49c926SDag-Erling Smørgrav return; 1673aa49c926SDag-Erling Smørgrav } 1674aa49c926SDag-Erling Smørgrav if (fstat(fd, &fst) < 0) { 1675aa49c926SDag-Erling Smørgrav logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP, 1676aa49c926SDag-Erling Smørgrav strerror(errno)); 1677aa49c926SDag-Erling Smørgrav goto out; 1678aa49c926SDag-Erling Smørgrav } 16794a421b63SDag-Erling Smørgrav if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){ 1680aa49c926SDag-Erling Smørgrav logit("Excess permission or bad ownership on file %s", 1681aa49c926SDag-Erling Smørgrav _PATH_BTMP); 1682aa49c926SDag-Erling Smørgrav goto out; 1683aa49c926SDag-Erling Smørgrav } 1684aa49c926SDag-Erling Smørgrav 1685aa49c926SDag-Erling Smørgrav memset(&ut, 0, sizeof(ut)); 1686aa49c926SDag-Erling Smørgrav /* strncpy because we don't necessarily want nul termination */ 1687aa49c926SDag-Erling Smørgrav strncpy(ut.ut_user, username, sizeof(ut.ut_user)); 1688aa49c926SDag-Erling Smørgrav strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); 1689aa49c926SDag-Erling Smørgrav 1690aa49c926SDag-Erling Smørgrav time(&t); 1691aa49c926SDag-Erling Smørgrav ut.ut_time = t; /* ut_time is not always a time_t */ 1692aa49c926SDag-Erling Smørgrav ut.ut_type = LOGIN_PROCESS; 1693aa49c926SDag-Erling Smørgrav ut.ut_pid = getpid(); 1694aa49c926SDag-Erling Smørgrav 1695aa49c926SDag-Erling Smørgrav /* strncpy because we don't necessarily want nul termination */ 1696aa49c926SDag-Erling Smørgrav strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); 1697aa49c926SDag-Erling Smørgrav 1698aa49c926SDag-Erling Smørgrav if (packet_connection_is_on_socket() && 1699aa49c926SDag-Erling Smørgrav getpeername(packet_get_connection_in(), 1700aa49c926SDag-Erling Smørgrav (struct sockaddr *)&from, &fromlen) == 0) { 1701aa49c926SDag-Erling Smørgrav ipv64_normalise_mapped(&from, &fromlen); 1702aa49c926SDag-Erling Smørgrav if (from.ss_family == AF_INET) { 1703aa49c926SDag-Erling Smørgrav a4 = (struct sockaddr_in *)&from; 1704aa49c926SDag-Erling Smørgrav memcpy(&ut.ut_addr, &(a4->sin_addr), 1705aa49c926SDag-Erling Smørgrav MIN_SIZEOF(ut.ut_addr, a4->sin_addr)); 1706aa49c926SDag-Erling Smørgrav } 1707aa49c926SDag-Erling Smørgrav #ifdef HAVE_ADDR_V6_IN_UTMP 1708aa49c926SDag-Erling Smørgrav if (from.ss_family == AF_INET6) { 1709aa49c926SDag-Erling Smørgrav a6 = (struct sockaddr_in6 *)&from; 1710aa49c926SDag-Erling Smørgrav memcpy(&ut.ut_addr_v6, &(a6->sin6_addr), 1711aa49c926SDag-Erling Smørgrav MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr)); 1712aa49c926SDag-Erling Smørgrav } 1713aa49c926SDag-Erling Smørgrav #endif 1714aa49c926SDag-Erling Smørgrav } 1715aa49c926SDag-Erling Smørgrav 1716aa49c926SDag-Erling Smørgrav if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut)) 1717aa49c926SDag-Erling Smørgrav error("Failed to write to %s: %s", _PATH_BTMP, 1718aa49c926SDag-Erling Smørgrav strerror(errno)); 1719aa49c926SDag-Erling Smørgrav 1720aa49c926SDag-Erling Smørgrav out: 1721aa49c926SDag-Erling Smørgrav close(fd); 1722aa49c926SDag-Erling Smørgrav } 1723aa49c926SDag-Erling Smørgrav #endif /* USE_BTMP */ 1724