1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate /* 6*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000 Andre Lucas. All rights reserved. 7*7c478bd9Sstevel@tonic-gate * Portions copyright (c) 1998 Todd C. Miller 8*7c478bd9Sstevel@tonic-gate * Portions copyright (c) 1996 Jason Downs 9*7c478bd9Sstevel@tonic-gate * Portions copyright (c) 1996 Theo de Raadt 10*7c478bd9Sstevel@tonic-gate * 11*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 12*7c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 13*7c478bd9Sstevel@tonic-gate * are met: 14*7c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 15*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 16*7c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 17*7c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 18*7c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 19*7c478bd9Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 20*7c478bd9Sstevel@tonic-gate * must display the following acknowledgement: 21*7c478bd9Sstevel@tonic-gate * This product includes software developed by Markus Friedl. 22*7c478bd9Sstevel@tonic-gate * 4. The name of the author may not be used to endorse or promote products 23*7c478bd9Sstevel@tonic-gate * derived from this software without specific prior written permission. 24*7c478bd9Sstevel@tonic-gate * 25*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26*7c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27*7c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28*7c478bd9Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29*7c478bd9Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30*7c478bd9Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31*7c478bd9Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32*7c478bd9Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33*7c478bd9Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34*7c478bd9Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35*7c478bd9Sstevel@tonic-gate */ 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate /** 38*7c478bd9Sstevel@tonic-gate ** loginrec.c: platform-independent login recording and lastlog retrieval 39*7c478bd9Sstevel@tonic-gate **/ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate /* 42*7c478bd9Sstevel@tonic-gate The new login code explained 43*7c478bd9Sstevel@tonic-gate ============================ 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate This code attempts to provide a common interface to login recording 46*7c478bd9Sstevel@tonic-gate (utmp and friends) and last login time retrieval. 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate Its primary means of achieving this is to use 'struct logininfo', a 49*7c478bd9Sstevel@tonic-gate union of all the useful fields in the various different types of 50*7c478bd9Sstevel@tonic-gate system login record structures one finds on UNIX variants. 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate We depend on autoconf to define which recording methods are to be 53*7c478bd9Sstevel@tonic-gate used, and which fields are contained in the relevant data structures 54*7c478bd9Sstevel@tonic-gate on the local system. Many C preprocessor symbols affect which code 55*7c478bd9Sstevel@tonic-gate gets compiled here. 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate The code is designed to make it easy to modify a particular 58*7c478bd9Sstevel@tonic-gate recording method, without affecting other methods nor requiring so 59*7c478bd9Sstevel@tonic-gate many nested conditional compilation blocks as were commonplace in 60*7c478bd9Sstevel@tonic-gate the old code. 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate For login recording, we try to use the local system's libraries as 63*7c478bd9Sstevel@tonic-gate these are clearly most likely to work correctly. For utmp systems 64*7c478bd9Sstevel@tonic-gate this usually means login() and logout() or setutent() etc., probably 65*7c478bd9Sstevel@tonic-gate in libutil, along with logwtmp() etc. On these systems, we fall back 66*7c478bd9Sstevel@tonic-gate to writing the files directly if we have to, though this method 67*7c478bd9Sstevel@tonic-gate requires very thorough testing so we do not corrupt local auditing 68*7c478bd9Sstevel@tonic-gate information. These files and their access methods are very system 69*7c478bd9Sstevel@tonic-gate specific indeed. 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate For utmpx systems, the corresponding library functions are 72*7c478bd9Sstevel@tonic-gate setutxent() etc. To the author's knowledge, all utmpx systems have 73*7c478bd9Sstevel@tonic-gate these library functions and so no direct write is attempted. If such 74*7c478bd9Sstevel@tonic-gate a system exists and needs support, direct analogues of the [uw]tmp 75*7c478bd9Sstevel@tonic-gate code should suffice. 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate Retrieving the time of last login ('lastlog') is in some ways even 78*7c478bd9Sstevel@tonic-gate more problemmatic than login recording. Some systems provide a 79*7c478bd9Sstevel@tonic-gate simple table of all users which we seek based on uid and retrieve a 80*7c478bd9Sstevel@tonic-gate relatively standard structure. Others record the same information in 81*7c478bd9Sstevel@tonic-gate a directory with a separate file, and others don't record the 82*7c478bd9Sstevel@tonic-gate information separately at all. For systems in the latter category, 83*7c478bd9Sstevel@tonic-gate we look backwards in the wtmp or wtmpx file for the last login entry 84*7c478bd9Sstevel@tonic-gate for our user. Naturally this is slower and on busy systems could 85*7c478bd9Sstevel@tonic-gate incur a significant performance penalty. 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate Calling the new code 88*7c478bd9Sstevel@tonic-gate -------------------- 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate In OpenSSH all login recording and retrieval is performed in 91*7c478bd9Sstevel@tonic-gate login.c. Here you'll find working examples. Also, in the logintest.c 92*7c478bd9Sstevel@tonic-gate program there are more examples. 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate Internal handler calling method 95*7c478bd9Sstevel@tonic-gate ------------------------------- 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate When a call is made to login_login() or login_logout(), both 98*7c478bd9Sstevel@tonic-gate routines set a struct logininfo flag defining which action (log in, 99*7c478bd9Sstevel@tonic-gate or log out) is to be taken. They both then call login_write(), which 100*7c478bd9Sstevel@tonic-gate calls whichever of the many structure-specific handlers autoconf 101*7c478bd9Sstevel@tonic-gate selects for the local system. 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate The handlers themselves handle system data structure specifics. Both 104*7c478bd9Sstevel@tonic-gate struct utmp and struct utmpx have utility functions (see 105*7c478bd9Sstevel@tonic-gate construct_utmp*()) to try to make it simpler to add extra systems 106*7c478bd9Sstevel@tonic-gate that introduce new features to either structure. 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate While it may seem terribly wasteful to replicate so much similar 109*7c478bd9Sstevel@tonic-gate code for each method, experience has shown that maintaining code to 110*7c478bd9Sstevel@tonic-gate write both struct utmp and utmpx in one function, whilst maintaining 111*7c478bd9Sstevel@tonic-gate support for all systems whether they have library support or not, is 112*7c478bd9Sstevel@tonic-gate a difficult and time-consuming task. 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate Lastlog support proceeds similarly. Functions login_get_lastlog() 115*7c478bd9Sstevel@tonic-gate (and its OpenSSH-tuned friend login_get_lastlog_time()) call 116*7c478bd9Sstevel@tonic-gate getlast_entry(), which tries one of three methods to find the last 117*7c478bd9Sstevel@tonic-gate login time. It uses local system lastlog support if it can, 118*7c478bd9Sstevel@tonic-gate otherwise it tries wtmp or wtmpx before giving up and returning 0, 119*7c478bd9Sstevel@tonic-gate meaning "tilt". 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate Maintenance 122*7c478bd9Sstevel@tonic-gate ----------- 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate In many cases it's possible to tweak autoconf to select the correct 125*7c478bd9Sstevel@tonic-gate methods for a particular platform, either by improving the detection 126*7c478bd9Sstevel@tonic-gate code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE 127*7c478bd9Sstevel@tonic-gate symbols for the platform. 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate Use logintest to check which symbols are defined before modifying 130*7c478bd9Sstevel@tonic-gate configure.ac and loginrec.c. (You have to build logintest yourself 131*7c478bd9Sstevel@tonic-gate with 'make logintest' as it's not built by default.) 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate Otherwise, patches to the specific method(s) are very helpful! 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /** 138*7c478bd9Sstevel@tonic-gate ** TODO: 139*7c478bd9Sstevel@tonic-gate ** homegrown ttyslot() 140*7c478bd9Sstevel@tonic-gate ** test, test, test 141*7c478bd9Sstevel@tonic-gate ** 142*7c478bd9Sstevel@tonic-gate ** Platform status: 143*7c478bd9Sstevel@tonic-gate ** ---------------- 144*7c478bd9Sstevel@tonic-gate ** 145*7c478bd9Sstevel@tonic-gate ** Known good: 146*7c478bd9Sstevel@tonic-gate ** Linux (Redhat 6.2, Debian) 147*7c478bd9Sstevel@tonic-gate ** Solaris 148*7c478bd9Sstevel@tonic-gate ** HP-UX 10.20 (gcc only) 149*7c478bd9Sstevel@tonic-gate ** IRIX 150*7c478bd9Sstevel@tonic-gate ** NeXT - M68k/HPPA/Sparc (4.2/3.3) 151*7c478bd9Sstevel@tonic-gate ** 152*7c478bd9Sstevel@tonic-gate ** Testing required: Please send reports! 153*7c478bd9Sstevel@tonic-gate ** NetBSD 154*7c478bd9Sstevel@tonic-gate ** HP-UX 11 155*7c478bd9Sstevel@tonic-gate ** AIX 156*7c478bd9Sstevel@tonic-gate ** 157*7c478bd9Sstevel@tonic-gate ** Platforms with known problems: 158*7c478bd9Sstevel@tonic-gate ** Some variants of Slackware Linux 159*7c478bd9Sstevel@tonic-gate ** 160*7c478bd9Sstevel@tonic-gate **/ 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate #include "includes.h" 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate #include "ssh.h" 165*7c478bd9Sstevel@tonic-gate #include "xmalloc.h" 166*7c478bd9Sstevel@tonic-gate #include "loginrec.h" 167*7c478bd9Sstevel@tonic-gate #include "log.h" 168*7c478bd9Sstevel@tonic-gate #include "atomicio.h" 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate RCSID("$Id: loginrec.c,v 1.44 2002/09/26 00:38:49 tim Exp $"); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UTIL_H 175*7c478bd9Sstevel@tonic-gate # include <util.h> 176*7c478bd9Sstevel@tonic-gate #endif 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate #ifdef HAVE_LIBUTIL_H 179*7c478bd9Sstevel@tonic-gate # include <libutil.h> 180*7c478bd9Sstevel@tonic-gate #endif 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate /** 183*7c478bd9Sstevel@tonic-gate ** prototypes for helper functions in this file 184*7c478bd9Sstevel@tonic-gate **/ 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate #if HAVE_UTMP_H 187*7c478bd9Sstevel@tonic-gate void set_utmp_time(struct logininfo *li, struct utmp *ut); 188*7c478bd9Sstevel@tonic-gate void construct_utmp(struct logininfo *li, struct utmp *ut); 189*7c478bd9Sstevel@tonic-gate #endif 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate #ifdef HAVE_UTMPX_H 192*7c478bd9Sstevel@tonic-gate void set_utmpx_time(struct logininfo *li, struct utmpx *ut); 193*7c478bd9Sstevel@tonic-gate void construct_utmpx(struct logininfo *li, struct utmpx *ut); 194*7c478bd9Sstevel@tonic-gate #endif 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate int utmp_write_entry(struct logininfo *li); 197*7c478bd9Sstevel@tonic-gate int utmpx_write_entry(struct logininfo *li); 198*7c478bd9Sstevel@tonic-gate int wtmp_write_entry(struct logininfo *li); 199*7c478bd9Sstevel@tonic-gate int wtmpx_write_entry(struct logininfo *li); 200*7c478bd9Sstevel@tonic-gate int lastlog_write_entry(struct logininfo *li); 201*7c478bd9Sstevel@tonic-gate int syslogin_write_entry(struct logininfo *li); 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate int getlast_entry(struct logininfo *li); 204*7c478bd9Sstevel@tonic-gate int lastlog_get_entry(struct logininfo *li); 205*7c478bd9Sstevel@tonic-gate int wtmp_get_entry(struct logininfo *li); 206*7c478bd9Sstevel@tonic-gate int wtmpx_get_entry(struct logininfo *li); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* pick the shortest string */ 209*7c478bd9Sstevel@tonic-gate #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) ) 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate /** 212*7c478bd9Sstevel@tonic-gate ** platform-independent login functions 213*7c478bd9Sstevel@tonic-gate **/ 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate /* login_login(struct logininfo *) -Record a login 216*7c478bd9Sstevel@tonic-gate * 217*7c478bd9Sstevel@tonic-gate * Call with a pointer to a struct logininfo initialised with 218*7c478bd9Sstevel@tonic-gate * login_init_entry() or login_alloc_entry() 219*7c478bd9Sstevel@tonic-gate * 220*7c478bd9Sstevel@tonic-gate * Returns: 221*7c478bd9Sstevel@tonic-gate * >0 if successful 222*7c478bd9Sstevel@tonic-gate * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate int 225*7c478bd9Sstevel@tonic-gate login_login (struct logininfo *li) 226*7c478bd9Sstevel@tonic-gate { 227*7c478bd9Sstevel@tonic-gate li->type = LTYPE_LOGIN; 228*7c478bd9Sstevel@tonic-gate return login_write(li); 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* login_logout(struct logininfo *) - Record a logout 233*7c478bd9Sstevel@tonic-gate * 234*7c478bd9Sstevel@tonic-gate * Call as with login_login() 235*7c478bd9Sstevel@tonic-gate * 236*7c478bd9Sstevel@tonic-gate * Returns: 237*7c478bd9Sstevel@tonic-gate * >0 if successful 238*7c478bd9Sstevel@tonic-gate * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 239*7c478bd9Sstevel@tonic-gate */ 240*7c478bd9Sstevel@tonic-gate int 241*7c478bd9Sstevel@tonic-gate login_logout(struct logininfo *li) 242*7c478bd9Sstevel@tonic-gate { 243*7c478bd9Sstevel@tonic-gate li->type = LTYPE_LOGOUT; 244*7c478bd9Sstevel@tonic-gate return login_write(li); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* login_get_lastlog_time(int) - Retrieve the last login time 248*7c478bd9Sstevel@tonic-gate * 249*7c478bd9Sstevel@tonic-gate * Retrieve the last login time for the given uid. Will try to use the 250*7c478bd9Sstevel@tonic-gate * system lastlog facilities if they are available, but will fall back 251*7c478bd9Sstevel@tonic-gate * to looking in wtmp/wtmpx if necessary 252*7c478bd9Sstevel@tonic-gate * 253*7c478bd9Sstevel@tonic-gate * Returns: 254*7c478bd9Sstevel@tonic-gate * 0 on failure, or if user has never logged in 255*7c478bd9Sstevel@tonic-gate * Time in seconds from the epoch if successful 256*7c478bd9Sstevel@tonic-gate * 257*7c478bd9Sstevel@tonic-gate * Useful preprocessor symbols: 258*7c478bd9Sstevel@tonic-gate * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog 259*7c478bd9Sstevel@tonic-gate * info 260*7c478bd9Sstevel@tonic-gate * USE_LASTLOG: If set, indicates the presence of system lastlog 261*7c478bd9Sstevel@tonic-gate * facilities. If this and DISABLE_LASTLOG are not set, 262*7c478bd9Sstevel@tonic-gate * try to retrieve lastlog information from wtmp/wtmpx. 263*7c478bd9Sstevel@tonic-gate */ 264*7c478bd9Sstevel@tonic-gate #if 0 265*7c478bd9Sstevel@tonic-gate unsigned int 266*7c478bd9Sstevel@tonic-gate login_get_lastlog_time(const int uid) 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate struct logininfo li; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate if (login_get_lastlog(&li, uid)) 271*7c478bd9Sstevel@tonic-gate return li.tv_sec; 272*7c478bd9Sstevel@tonic-gate else 273*7c478bd9Sstevel@tonic-gate return 0; 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate #endif 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate /* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry 278*7c478bd9Sstevel@tonic-gate * 279*7c478bd9Sstevel@tonic-gate * Retrieve a logininfo structure populated (only partially) with 280*7c478bd9Sstevel@tonic-gate * information from the system lastlog data, or from wtmp/wtmpx if no 281*7c478bd9Sstevel@tonic-gate * system lastlog information exists. 282*7c478bd9Sstevel@tonic-gate * 283*7c478bd9Sstevel@tonic-gate * Note this routine must be given a pre-allocated logininfo. 284*7c478bd9Sstevel@tonic-gate * 285*7c478bd9Sstevel@tonic-gate * Returns: 286*7c478bd9Sstevel@tonic-gate * >0: A pointer to your struct logininfo if successful 287*7c478bd9Sstevel@tonic-gate * 0 on failure (will use OpenSSH's logging facilities for diagnostics) 288*7c478bd9Sstevel@tonic-gate * 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate struct logininfo * 291*7c478bd9Sstevel@tonic-gate login_get_lastlog(struct logininfo *li, const int uid) 292*7c478bd9Sstevel@tonic-gate { 293*7c478bd9Sstevel@tonic-gate struct passwd *pw; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate (void) memset(li, '\0', sizeof(*li)); 296*7c478bd9Sstevel@tonic-gate li->uid = uid; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * If we don't have a 'real' lastlog, we need the username to 300*7c478bd9Sstevel@tonic-gate * reliably search wtmp(x) for the last login (see 301*7c478bd9Sstevel@tonic-gate * wtmp_get_entry().) 302*7c478bd9Sstevel@tonic-gate */ 303*7c478bd9Sstevel@tonic-gate pw = getpwuid(uid); 304*7c478bd9Sstevel@tonic-gate if (pw == NULL) 305*7c478bd9Sstevel@tonic-gate fatal("login_get_lastlog: Cannot find account for uid %i", uid); 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate /* No MIN_SIZEOF here - we absolutely *must not* truncate the 308*7c478bd9Sstevel@tonic-gate * username */ 309*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->username, pw->pw_name, sizeof(li->username)); 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate if (getlast_entry(li)) 312*7c478bd9Sstevel@tonic-gate return li; 313*7c478bd9Sstevel@tonic-gate else 314*7c478bd9Sstevel@tonic-gate return NULL; 315*7c478bd9Sstevel@tonic-gate } 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate /* login_alloc_entry() - Allocate and initialise a logininfo 319*7c478bd9Sstevel@tonic-gate * structure 320*7c478bd9Sstevel@tonic-gate * 321*7c478bd9Sstevel@tonic-gate * This function creates a new struct logininfo, a data structure 322*7c478bd9Sstevel@tonic-gate * meant to carry the information required to portably record login info. 323*7c478bd9Sstevel@tonic-gate * 324*7c478bd9Sstevel@tonic-gate * Returns a pointer to a newly created struct logininfo. If memory 325*7c478bd9Sstevel@tonic-gate * allocation fails, the program halts. 326*7c478bd9Sstevel@tonic-gate */ 327*7c478bd9Sstevel@tonic-gate struct 328*7c478bd9Sstevel@tonic-gate logininfo *login_alloc_entry(int pid, const char *username, 329*7c478bd9Sstevel@tonic-gate const char *hostname, const char *line, 330*7c478bd9Sstevel@tonic-gate const char *progname) 331*7c478bd9Sstevel@tonic-gate { 332*7c478bd9Sstevel@tonic-gate struct logininfo *newli; 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate newli = (struct logininfo *) xmalloc (sizeof(*newli)); 335*7c478bd9Sstevel@tonic-gate (void)login_init_entry(newli, pid, username, hostname, line, progname); 336*7c478bd9Sstevel@tonic-gate return newli; 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate /* login_free_entry(struct logininfo *) - free struct memory */ 341*7c478bd9Sstevel@tonic-gate void 342*7c478bd9Sstevel@tonic-gate login_free_entry(struct logininfo *li) 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate xfree(li); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate 348*7c478bd9Sstevel@tonic-gate /* login_init_entry() 349*7c478bd9Sstevel@tonic-gate * - initialise a struct logininfo 350*7c478bd9Sstevel@tonic-gate * 351*7c478bd9Sstevel@tonic-gate * Populates a new struct logininfo, a data structure meant to carry 352*7c478bd9Sstevel@tonic-gate * the information required to portably record login info. 353*7c478bd9Sstevel@tonic-gate * 354*7c478bd9Sstevel@tonic-gate * Returns: 1 355*7c478bd9Sstevel@tonic-gate */ 356*7c478bd9Sstevel@tonic-gate int 357*7c478bd9Sstevel@tonic-gate login_init_entry(struct logininfo *li, int pid, const char *username, 358*7c478bd9Sstevel@tonic-gate const char *hostname, const char *line, const char *progname) 359*7c478bd9Sstevel@tonic-gate { 360*7c478bd9Sstevel@tonic-gate struct passwd *pw; 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate (void) memset(li, 0, sizeof(*li)); 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate li->pid = pid; 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate /* set the line information */ 367*7c478bd9Sstevel@tonic-gate if (line) 368*7c478bd9Sstevel@tonic-gate (void) line_fullname(li->line, line, sizeof(li->line)); 369*7c478bd9Sstevel@tonic-gate else 370*7c478bd9Sstevel@tonic-gate li->line_null = 1; 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (progname) 373*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->progname, progname, sizeof(li->progname)); 374*7c478bd9Sstevel@tonic-gate else 375*7c478bd9Sstevel@tonic-gate li->progname_null = 1; 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate if (username) { 378*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->username, username, sizeof(li->username)); 379*7c478bd9Sstevel@tonic-gate pw = getpwnam(li->username); 380*7c478bd9Sstevel@tonic-gate if (pw == NULL) 381*7c478bd9Sstevel@tonic-gate fatal("login_init_entry: Cannot find user \"%s\"", li->username); 382*7c478bd9Sstevel@tonic-gate li->uid = pw->pw_uid; 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate if (hostname) 386*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->hostname, hostname, sizeof(li->hostname)); 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate return 1; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* login_set_current_time(struct logininfo *) - set the current time 392*7c478bd9Sstevel@tonic-gate * 393*7c478bd9Sstevel@tonic-gate * Set the current time in a logininfo structure. This function is 394*7c478bd9Sstevel@tonic-gate * meant to eliminate the need to deal with system dependencies for 395*7c478bd9Sstevel@tonic-gate * time handling. 396*7c478bd9Sstevel@tonic-gate */ 397*7c478bd9Sstevel@tonic-gate void 398*7c478bd9Sstevel@tonic-gate login_set_current_time(struct logininfo *li) 399*7c478bd9Sstevel@tonic-gate { 400*7c478bd9Sstevel@tonic-gate struct timeval tv; 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tv, NULL); 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate li->tv_sec = tv.tv_sec; 405*7c478bd9Sstevel@tonic-gate li->tv_usec = tv.tv_usec; 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* copy a sockaddr_* into our logininfo */ 409*7c478bd9Sstevel@tonic-gate void 410*7c478bd9Sstevel@tonic-gate login_set_addr(struct logininfo *li, const struct sockaddr *sa, 411*7c478bd9Sstevel@tonic-gate const unsigned int sa_size) 412*7c478bd9Sstevel@tonic-gate { 413*7c478bd9Sstevel@tonic-gate unsigned int bufsize = sa_size; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate /* make sure we don't overrun our union */ 416*7c478bd9Sstevel@tonic-gate if (sizeof(li->hostaddr) < sa_size) 417*7c478bd9Sstevel@tonic-gate bufsize = sizeof(li->hostaddr); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate (void) memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize); 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate /** 424*7c478bd9Sstevel@tonic-gate ** login_write: Call low-level recording functions based on autoconf 425*7c478bd9Sstevel@tonic-gate ** results 426*7c478bd9Sstevel@tonic-gate **/ 427*7c478bd9Sstevel@tonic-gate int 428*7c478bd9Sstevel@tonic-gate login_write (struct logininfo *li) 429*7c478bd9Sstevel@tonic-gate { 430*7c478bd9Sstevel@tonic-gate #ifndef HAVE_CYGWIN 431*7c478bd9Sstevel@tonic-gate if ((int)geteuid() != 0) { 432*7c478bd9Sstevel@tonic-gate log("Attempt to write login records by non-root user (aborting)"); 433*7c478bd9Sstevel@tonic-gate return 1; 434*7c478bd9Sstevel@tonic-gate } 435*7c478bd9Sstevel@tonic-gate #endif 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate /* set the timestamp */ 438*7c478bd9Sstevel@tonic-gate login_set_current_time(li); 439*7c478bd9Sstevel@tonic-gate #ifdef USE_LOGIN 440*7c478bd9Sstevel@tonic-gate syslogin_write_entry(li); 441*7c478bd9Sstevel@tonic-gate #endif 442*7c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG 443*7c478bd9Sstevel@tonic-gate if (li->type == LTYPE_LOGIN) { 444*7c478bd9Sstevel@tonic-gate (void) lastlog_write_entry(li); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate #endif 447*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMP 448*7c478bd9Sstevel@tonic-gate utmp_write_entry(li); 449*7c478bd9Sstevel@tonic-gate #endif 450*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMP 451*7c478bd9Sstevel@tonic-gate wtmp_write_entry(li); 452*7c478bd9Sstevel@tonic-gate #endif 453*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMPX 454*7c478bd9Sstevel@tonic-gate (void) utmpx_write_entry(li); 455*7c478bd9Sstevel@tonic-gate #endif 456*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMPX 457*7c478bd9Sstevel@tonic-gate (void) wtmpx_write_entry(li); 458*7c478bd9Sstevel@tonic-gate #endif 459*7c478bd9Sstevel@tonic-gate return 0; 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate #ifdef LOGIN_NEEDS_UTMPX 463*7c478bd9Sstevel@tonic-gate int 464*7c478bd9Sstevel@tonic-gate login_utmp_only(struct logininfo *li) 465*7c478bd9Sstevel@tonic-gate { 466*7c478bd9Sstevel@tonic-gate li->type = LTYPE_LOGIN; 467*7c478bd9Sstevel@tonic-gate login_set_current_time(li); 468*7c478bd9Sstevel@tonic-gate # ifdef USE_UTMP 469*7c478bd9Sstevel@tonic-gate utmp_write_entry(li); 470*7c478bd9Sstevel@tonic-gate # endif 471*7c478bd9Sstevel@tonic-gate # ifdef USE_WTMP 472*7c478bd9Sstevel@tonic-gate wtmp_write_entry(li); 473*7c478bd9Sstevel@tonic-gate # endif 474*7c478bd9Sstevel@tonic-gate # ifdef USE_UTMPX 475*7c478bd9Sstevel@tonic-gate (void) utmpx_write_entry(li); 476*7c478bd9Sstevel@tonic-gate # endif 477*7c478bd9Sstevel@tonic-gate # ifdef USE_WTMPX 478*7c478bd9Sstevel@tonic-gate (void) wtmpx_write_entry(li); 479*7c478bd9Sstevel@tonic-gate # endif 480*7c478bd9Sstevel@tonic-gate return 0; 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate #endif 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate /** 485*7c478bd9Sstevel@tonic-gate ** getlast_entry: Call low-level functions to retrieve the last login 486*7c478bd9Sstevel@tonic-gate ** time. 487*7c478bd9Sstevel@tonic-gate **/ 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate /* take the uid in li and return the last login time */ 490*7c478bd9Sstevel@tonic-gate int 491*7c478bd9Sstevel@tonic-gate getlast_entry(struct logininfo *li) 492*7c478bd9Sstevel@tonic-gate { 493*7c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG 494*7c478bd9Sstevel@tonic-gate return(lastlog_get_entry(li)); 495*7c478bd9Sstevel@tonic-gate #else /* !USE_LASTLOG */ 496*7c478bd9Sstevel@tonic-gate 497*7c478bd9Sstevel@tonic-gate #ifdef DISABLE_LASTLOG 498*7c478bd9Sstevel@tonic-gate /* On some systems we shouldn't even try to obtain last login 499*7c478bd9Sstevel@tonic-gate * time, e.g. AIX */ 500*7c478bd9Sstevel@tonic-gate return 0; 501*7c478bd9Sstevel@tonic-gate # else /* DISABLE_LASTLOG */ 502*7c478bd9Sstevel@tonic-gate /* Try to retrieve the last login time from wtmp */ 503*7c478bd9Sstevel@tonic-gate # if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) 504*7c478bd9Sstevel@tonic-gate /* retrieve last login time from utmp */ 505*7c478bd9Sstevel@tonic-gate return (wtmp_get_entry(li)); 506*7c478bd9Sstevel@tonic-gate # else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */ 507*7c478bd9Sstevel@tonic-gate /* If wtmp isn't available, try wtmpx */ 508*7c478bd9Sstevel@tonic-gate # if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) 509*7c478bd9Sstevel@tonic-gate /* retrieve last login time from utmpx */ 510*7c478bd9Sstevel@tonic-gate return (wtmpx_get_entry(li)); 511*7c478bd9Sstevel@tonic-gate # else 512*7c478bd9Sstevel@tonic-gate /* Give up: No means of retrieving last login time */ 513*7c478bd9Sstevel@tonic-gate return 0; 514*7c478bd9Sstevel@tonic-gate # endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */ 515*7c478bd9Sstevel@tonic-gate # endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */ 516*7c478bd9Sstevel@tonic-gate # endif /* DISABLE_LASTLOG */ 517*7c478bd9Sstevel@tonic-gate #endif /* USE_LASTLOG */ 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate /* 523*7c478bd9Sstevel@tonic-gate * 'line' string utility functions 524*7c478bd9Sstevel@tonic-gate * 525*7c478bd9Sstevel@tonic-gate * These functions process the 'line' string into one of three forms: 526*7c478bd9Sstevel@tonic-gate * 527*7c478bd9Sstevel@tonic-gate * 1. The full filename (including '/dev') 528*7c478bd9Sstevel@tonic-gate * 2. The stripped name (excluding '/dev') 529*7c478bd9Sstevel@tonic-gate * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00 530*7c478bd9Sstevel@tonic-gate * /dev/pts/1 -> ts/1 ) 531*7c478bd9Sstevel@tonic-gate * 532*7c478bd9Sstevel@tonic-gate * Form 3 is used on some systems to identify a .tmp.? entry when 533*7c478bd9Sstevel@tonic-gate * attempting to remove it. Typically both addition and removal is 534*7c478bd9Sstevel@tonic-gate * performed by one application - say, sshd - so as long as the choice 535*7c478bd9Sstevel@tonic-gate * uniquely identifies a terminal it's ok. 536*7c478bd9Sstevel@tonic-gate */ 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate /* line_fullname(): add the leading '/dev/' if it doesn't exist make 540*7c478bd9Sstevel@tonic-gate * sure dst has enough space, if not just copy src (ugh) */ 541*7c478bd9Sstevel@tonic-gate char * 542*7c478bd9Sstevel@tonic-gate line_fullname(char *dst, const char *src, int dstsize) 543*7c478bd9Sstevel@tonic-gate { 544*7c478bd9Sstevel@tonic-gate (void) memset(dst, '\0', dstsize); 545*7c478bd9Sstevel@tonic-gate /* "sshd" is special, like "ftp" */ 546*7c478bd9Sstevel@tonic-gate if (strcmp(src, "sshd") || 547*7c478bd9Sstevel@tonic-gate ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))) { 548*7c478bd9Sstevel@tonic-gate (void) strlcpy(dst, src, dstsize); 549*7c478bd9Sstevel@tonic-gate } else { 550*7c478bd9Sstevel@tonic-gate (void) strlcpy(dst, "/dev/", dstsize); 551*7c478bd9Sstevel@tonic-gate (void) strlcat(dst, src, dstsize); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate return dst; 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate /* line_stripname(): strip the leading '/dev' if it exists, return dst */ 557*7c478bd9Sstevel@tonic-gate char * 558*7c478bd9Sstevel@tonic-gate line_stripname(char *dst, const char *src, int dstsize) 559*7c478bd9Sstevel@tonic-gate { 560*7c478bd9Sstevel@tonic-gate (void) memset(dst, '\0', dstsize); 561*7c478bd9Sstevel@tonic-gate if (strncmp(src, "/dev/", 5) == 0) 562*7c478bd9Sstevel@tonic-gate (void) strlcpy(dst, src + 5, dstsize); 563*7c478bd9Sstevel@tonic-gate else 564*7c478bd9Sstevel@tonic-gate (void) strlcpy(dst, src, dstsize); 565*7c478bd9Sstevel@tonic-gate return dst; 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate /* line_abbrevname(): Return the abbreviated (usually four-character) 569*7c478bd9Sstevel@tonic-gate * form of the line (Just use the last <dstsize> characters of the 570*7c478bd9Sstevel@tonic-gate * full name.) 571*7c478bd9Sstevel@tonic-gate * 572*7c478bd9Sstevel@tonic-gate * NOTE: use strncpy because we do NOT necessarily want zero 573*7c478bd9Sstevel@tonic-gate * termination */ 574*7c478bd9Sstevel@tonic-gate char * 575*7c478bd9Sstevel@tonic-gate line_abbrevname(char *dst, const char *src, int dstsize) 576*7c478bd9Sstevel@tonic-gate { 577*7c478bd9Sstevel@tonic-gate size_t len; 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate (void) memset(dst, '\0', dstsize); 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate /* Always skip prefix if present */ 582*7c478bd9Sstevel@tonic-gate if (strncmp(src, "/dev/", 5) == 0) 583*7c478bd9Sstevel@tonic-gate src += 5; 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate #ifdef WITH_ABBREV_NO_TTY 586*7c478bd9Sstevel@tonic-gate if (strncmp(src, "tty", 3) == 0) 587*7c478bd9Sstevel@tonic-gate src += 3; 588*7c478bd9Sstevel@tonic-gate #endif 589*7c478bd9Sstevel@tonic-gate 590*7c478bd9Sstevel@tonic-gate len = strlen(src); 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate if (len > 0) { 593*7c478bd9Sstevel@tonic-gate if (((int)len - dstsize) > 0) 594*7c478bd9Sstevel@tonic-gate src += ((int)len - dstsize); 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate /* note: _don't_ change this to strlcpy */ 597*7c478bd9Sstevel@tonic-gate (void) strncpy(dst, src, (size_t)dstsize); 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate return dst; 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /** 604*7c478bd9Sstevel@tonic-gate ** utmp utility functions 605*7c478bd9Sstevel@tonic-gate ** 606*7c478bd9Sstevel@tonic-gate ** These functions manipulate struct utmp, taking system differences 607*7c478bd9Sstevel@tonic-gate ** into account. 608*7c478bd9Sstevel@tonic-gate **/ 609*7c478bd9Sstevel@tonic-gate 610*7c478bd9Sstevel@tonic-gate #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN) 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* build the utmp structure */ 613*7c478bd9Sstevel@tonic-gate void 614*7c478bd9Sstevel@tonic-gate set_utmp_time(struct logininfo *li, struct utmp *ut) 615*7c478bd9Sstevel@tonic-gate { 616*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMP 617*7c478bd9Sstevel@tonic-gate ut->ut_tv.tv_sec = li->tv_sec; 618*7c478bd9Sstevel@tonic-gate ut->ut_tv.tv_usec = li->tv_usec; 619*7c478bd9Sstevel@tonic-gate # else 620*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TIME_IN_UTMP 621*7c478bd9Sstevel@tonic-gate ut->ut_time = li->tv_sec; 622*7c478bd9Sstevel@tonic-gate # endif 623*7c478bd9Sstevel@tonic-gate # endif 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate void 627*7c478bd9Sstevel@tonic-gate construct_utmp(struct logininfo *li, 628*7c478bd9Sstevel@tonic-gate struct utmp *ut) 629*7c478bd9Sstevel@tonic-gate { 630*7c478bd9Sstevel@tonic-gate (void) memset(ut, '\0', sizeof(*ut)); 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* First fill out fields used for both logins and logouts */ 633*7c478bd9Sstevel@tonic-gate 634*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMP 635*7c478bd9Sstevel@tonic-gate (void) line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id)); 636*7c478bd9Sstevel@tonic-gate # endif 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMP 639*7c478bd9Sstevel@tonic-gate /* This is done here to keep utmp constants out of struct logininfo */ 640*7c478bd9Sstevel@tonic-gate switch (li->type) { 641*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 642*7c478bd9Sstevel@tonic-gate ut->ut_type = USER_PROCESS; 643*7c478bd9Sstevel@tonic-gate #ifdef _UNICOS 644*7c478bd9Sstevel@tonic-gate cray_set_tmpdir(ut); 645*7c478bd9Sstevel@tonic-gate #endif 646*7c478bd9Sstevel@tonic-gate break; 647*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 648*7c478bd9Sstevel@tonic-gate ut->ut_type = DEAD_PROCESS; 649*7c478bd9Sstevel@tonic-gate #ifdef _UNICOS 650*7c478bd9Sstevel@tonic-gate cray_retain_utmp(ut, li->pid); 651*7c478bd9Sstevel@tonic-gate #endif 652*7c478bd9Sstevel@tonic-gate break; 653*7c478bd9Sstevel@tonic-gate } 654*7c478bd9Sstevel@tonic-gate # endif 655*7c478bd9Sstevel@tonic-gate set_utmp_time(li, ut); 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate (void) line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line)); 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate # ifdef HAVE_PID_IN_UTMP 660*7c478bd9Sstevel@tonic-gate ut->ut_pid = li->pid; 661*7c478bd9Sstevel@tonic-gate # endif 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate /* If we're logging out, leave all other fields blank */ 664*7c478bd9Sstevel@tonic-gate if (li->type == LTYPE_LOGOUT) 665*7c478bd9Sstevel@tonic-gate return; 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate /* 668*7c478bd9Sstevel@tonic-gate * These fields are only used when logging in, and are blank 669*7c478bd9Sstevel@tonic-gate * for logouts. 670*7c478bd9Sstevel@tonic-gate */ 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate /* Use strncpy because we don't necessarily want null termination */ 673*7c478bd9Sstevel@tonic-gate (void) strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username)); 674*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMP 675*7c478bd9Sstevel@tonic-gate (void) strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname)); 676*7c478bd9Sstevel@tonic-gate # endif 677*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ADDR_IN_UTMP 678*7c478bd9Sstevel@tonic-gate /* this is just a 32-bit IP address */ 679*7c478bd9Sstevel@tonic-gate if (li->hostaddr.sa.sa_family == AF_INET) 680*7c478bd9Sstevel@tonic-gate ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 681*7c478bd9Sstevel@tonic-gate # endif 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */ 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /** 686*7c478bd9Sstevel@tonic-gate ** utmpx utility functions 687*7c478bd9Sstevel@tonic-gate ** 688*7c478bd9Sstevel@tonic-gate ** These functions manipulate struct utmpx, accounting for system 689*7c478bd9Sstevel@tonic-gate ** variations. 690*7c478bd9Sstevel@tonic-gate **/ 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate #if defined(USE_UTMPX) || defined (USE_WTMPX) 693*7c478bd9Sstevel@tonic-gate /* build the utmpx structure */ 694*7c478bd9Sstevel@tonic-gate void 695*7c478bd9Sstevel@tonic-gate set_utmpx_time(struct logininfo *li, struct utmpx *utx) 696*7c478bd9Sstevel@tonic-gate { 697*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMPX 698*7c478bd9Sstevel@tonic-gate utx->ut_tv.tv_sec = li->tv_sec; 699*7c478bd9Sstevel@tonic-gate utx->ut_tv.tv_usec = li->tv_usec; 700*7c478bd9Sstevel@tonic-gate # else /* HAVE_TV_IN_UTMPX */ 701*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TIME_IN_UTMPX 702*7c478bd9Sstevel@tonic-gate utx->ut_time = li->tv_sec; 703*7c478bd9Sstevel@tonic-gate # endif /* HAVE_TIME_IN_UTMPX */ 704*7c478bd9Sstevel@tonic-gate # endif /* HAVE_TV_IN_UTMPX */ 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate void 708*7c478bd9Sstevel@tonic-gate construct_utmpx(struct logininfo *li, struct utmpx *utx) 709*7c478bd9Sstevel@tonic-gate { 710*7c478bd9Sstevel@tonic-gate (void) memset(utx, '\0', sizeof(*utx)); 711*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMPX 712*7c478bd9Sstevel@tonic-gate (void) line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); 713*7c478bd9Sstevel@tonic-gate # endif 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate /* this is done here to keep utmp constants out of loginrec.h */ 716*7c478bd9Sstevel@tonic-gate switch (li->type) { 717*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 718*7c478bd9Sstevel@tonic-gate utx->ut_type = USER_PROCESS; 719*7c478bd9Sstevel@tonic-gate break; 720*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 721*7c478bd9Sstevel@tonic-gate utx->ut_type = DEAD_PROCESS; 722*7c478bd9Sstevel@tonic-gate break; 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate if (!li->line_null) 725*7c478bd9Sstevel@tonic-gate (void) line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); 726*7c478bd9Sstevel@tonic-gate else if (!li->progname_null) 727*7c478bd9Sstevel@tonic-gate (void) line_stripname(utx->ut_line, li->progname, sizeof(utx->ut_line)); 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate set_utmpx_time(li, utx); 730*7c478bd9Sstevel@tonic-gate utx->ut_pid = li->pid; 731*7c478bd9Sstevel@tonic-gate /* strncpy(): Don't necessarily want null termination */ 732*7c478bd9Sstevel@tonic-gate (void) strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username)); 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate if (li->type == LTYPE_LOGOUT) 735*7c478bd9Sstevel@tonic-gate return; 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate /* 738*7c478bd9Sstevel@tonic-gate * These fields are only used when logging in, and are blank 739*7c478bd9Sstevel@tonic-gate * for logouts. 740*7c478bd9Sstevel@tonic-gate */ 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMPX 743*7c478bd9Sstevel@tonic-gate (void) strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname)); 744*7c478bd9Sstevel@tonic-gate # endif 745*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ADDR_IN_UTMPX 746*7c478bd9Sstevel@tonic-gate /* this is just a 32-bit IP address */ 747*7c478bd9Sstevel@tonic-gate if (li->hostaddr.sa.sa_family == AF_INET) 748*7c478bd9Sstevel@tonic-gate utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; 749*7c478bd9Sstevel@tonic-gate # endif 750*7c478bd9Sstevel@tonic-gate # ifdef HAVE_SYSLEN_IN_UTMPX 751*7c478bd9Sstevel@tonic-gate /* ut_syslen is the length of the utx_host string */ 752*7c478bd9Sstevel@tonic-gate utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host)); 753*7c478bd9Sstevel@tonic-gate # endif 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMPX || USE_WTMPX */ 756*7c478bd9Sstevel@tonic-gate 757*7c478bd9Sstevel@tonic-gate /** 758*7c478bd9Sstevel@tonic-gate ** Low-level utmp functions 759*7c478bd9Sstevel@tonic-gate **/ 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate /* FIXME: (ATL) utmp_write_direct needs testing */ 762*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMP 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate /* if we can, use pututline() etc. */ 765*7c478bd9Sstevel@tonic-gate # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ 766*7c478bd9Sstevel@tonic-gate defined(HAVE_PUTUTLINE) 767*7c478bd9Sstevel@tonic-gate # define UTMP_USE_LIBRARY 768*7c478bd9Sstevel@tonic-gate # endif 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate /* write a utmp entry with the system's help (pututline() and pals) */ 772*7c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY 773*7c478bd9Sstevel@tonic-gate static int 774*7c478bd9Sstevel@tonic-gate utmp_write_library(struct logininfo *li, struct utmp *ut) 775*7c478bd9Sstevel@tonic-gate { 776*7c478bd9Sstevel@tonic-gate setutent(); 777*7c478bd9Sstevel@tonic-gate pututline(ut); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ENDUTENT 780*7c478bd9Sstevel@tonic-gate endutent(); 781*7c478bd9Sstevel@tonic-gate # endif 782*7c478bd9Sstevel@tonic-gate return 1; 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate # else /* UTMP_USE_LIBRARY */ 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate /* write a utmp entry direct to the file */ 787*7c478bd9Sstevel@tonic-gate /* This is a slightly modification of code in OpenBSD's login.c */ 788*7c478bd9Sstevel@tonic-gate static int 789*7c478bd9Sstevel@tonic-gate utmp_write_direct(struct logininfo *li, struct utmp *ut) 790*7c478bd9Sstevel@tonic-gate { 791*7c478bd9Sstevel@tonic-gate struct utmp old_ut; 792*7c478bd9Sstevel@tonic-gate register int fd; 793*7c478bd9Sstevel@tonic-gate int tty; 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate /* FIXME: (ATL) ttyslot() needs local implementation */ 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate #if defined(HAVE_GETTTYENT) 798*7c478bd9Sstevel@tonic-gate register struct ttyent *ty; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate tty=0; 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate setttyent(); 803*7c478bd9Sstevel@tonic-gate while ((struct ttyent *)0 != (ty = getttyent())) { 804*7c478bd9Sstevel@tonic-gate tty++; 805*7c478bd9Sstevel@tonic-gate if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) 806*7c478bd9Sstevel@tonic-gate break; 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate endttyent(); 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate if((struct ttyent *)0 == ty) { 811*7c478bd9Sstevel@tonic-gate log("utmp_write_entry: tty not found"); 812*7c478bd9Sstevel@tonic-gate return(1); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate #else /* FIXME */ 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */ 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate #endif /* HAVE_GETTTYENT */ 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) { 821*7c478bd9Sstevel@tonic-gate (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET); 822*7c478bd9Sstevel@tonic-gate /* 823*7c478bd9Sstevel@tonic-gate * Prevent luser from zero'ing out ut_host. 824*7c478bd9Sstevel@tonic-gate * If the new ut_line is empty but the old one is not 825*7c478bd9Sstevel@tonic-gate * and ut_line and ut_name match, preserve the old ut_line. 826*7c478bd9Sstevel@tonic-gate */ 827*7c478bd9Sstevel@tonic-gate if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && 828*7c478bd9Sstevel@tonic-gate (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && 829*7c478bd9Sstevel@tonic-gate (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && 830*7c478bd9Sstevel@tonic-gate (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) { 831*7c478bd9Sstevel@tonic-gate (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate 834*7c478bd9Sstevel@tonic-gate (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET); 835*7c478bd9Sstevel@tonic-gate if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) 836*7c478bd9Sstevel@tonic-gate log("utmp_write_direct: error writing %s: %s", 837*7c478bd9Sstevel@tonic-gate UTMP_FILE, strerror(errno)); 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate (void)close(fd); 840*7c478bd9Sstevel@tonic-gate return 1; 841*7c478bd9Sstevel@tonic-gate } else { 842*7c478bd9Sstevel@tonic-gate return 0; 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate # endif /* UTMP_USE_LIBRARY */ 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate static int 848*7c478bd9Sstevel@tonic-gate utmp_perform_login(struct logininfo *li) 849*7c478bd9Sstevel@tonic-gate { 850*7c478bd9Sstevel@tonic-gate struct utmp ut; 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate construct_utmp(li, &ut); 853*7c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY 854*7c478bd9Sstevel@tonic-gate if (!utmp_write_library(li, &ut)) { 855*7c478bd9Sstevel@tonic-gate log("utmp_perform_login: utmp_write_library() failed"); 856*7c478bd9Sstevel@tonic-gate return 0; 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate # else 859*7c478bd9Sstevel@tonic-gate if (!utmp_write_direct(li, &ut)) { 860*7c478bd9Sstevel@tonic-gate log("utmp_perform_login: utmp_write_direct() failed"); 861*7c478bd9Sstevel@tonic-gate return 0; 862*7c478bd9Sstevel@tonic-gate } 863*7c478bd9Sstevel@tonic-gate # endif 864*7c478bd9Sstevel@tonic-gate return 1; 865*7c478bd9Sstevel@tonic-gate } 866*7c478bd9Sstevel@tonic-gate 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate static int 869*7c478bd9Sstevel@tonic-gate utmp_perform_logout(struct logininfo *li) 870*7c478bd9Sstevel@tonic-gate { 871*7c478bd9Sstevel@tonic-gate struct utmp ut; 872*7c478bd9Sstevel@tonic-gate 873*7c478bd9Sstevel@tonic-gate construct_utmp(li, &ut); 874*7c478bd9Sstevel@tonic-gate # ifdef UTMP_USE_LIBRARY 875*7c478bd9Sstevel@tonic-gate if (!utmp_write_library(li, &ut)) { 876*7c478bd9Sstevel@tonic-gate log("utmp_perform_logout: utmp_write_library() failed"); 877*7c478bd9Sstevel@tonic-gate return 0; 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate # else 880*7c478bd9Sstevel@tonic-gate if (!utmp_write_direct(li, &ut)) { 881*7c478bd9Sstevel@tonic-gate log("utmp_perform_logout: utmp_write_direct() failed"); 882*7c478bd9Sstevel@tonic-gate return 0; 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate # endif 885*7c478bd9Sstevel@tonic-gate return 1; 886*7c478bd9Sstevel@tonic-gate } 887*7c478bd9Sstevel@tonic-gate 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate int 890*7c478bd9Sstevel@tonic-gate utmp_write_entry(struct logininfo *li) 891*7c478bd9Sstevel@tonic-gate { 892*7c478bd9Sstevel@tonic-gate if (li->line_null) { 893*7c478bd9Sstevel@tonic-gate debug3("not writing utmp entry"); 894*7c478bd9Sstevel@tonic-gate return 1; 895*7c478bd9Sstevel@tonic-gate } 896*7c478bd9Sstevel@tonic-gate debug3("writing utmp entry"); 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate switch(li->type) { 899*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 900*7c478bd9Sstevel@tonic-gate return utmp_perform_login(li); 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 903*7c478bd9Sstevel@tonic-gate return utmp_perform_logout(li); 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate default: 906*7c478bd9Sstevel@tonic-gate log("utmp_write_entry: invalid type field"); 907*7c478bd9Sstevel@tonic-gate return 0; 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMP */ 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate /** 914*7c478bd9Sstevel@tonic-gate ** Low-level utmpx functions 915*7c478bd9Sstevel@tonic-gate **/ 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate /* not much point if we don't want utmpx entries */ 918*7c478bd9Sstevel@tonic-gate #ifdef USE_UTMPX 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate /* if we have the wherewithall, use pututxline etc. */ 921*7c478bd9Sstevel@tonic-gate # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \ 922*7c478bd9Sstevel@tonic-gate defined(HAVE_PUTUTXLINE) 923*7c478bd9Sstevel@tonic-gate # define UTMPX_USE_LIBRARY 924*7c478bd9Sstevel@tonic-gate # endif 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate /* write a utmpx entry with the system's help (pututxline() and pals) */ 928*7c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY 929*7c478bd9Sstevel@tonic-gate static int 930*7c478bd9Sstevel@tonic-gate utmpx_write_library(struct logininfo *li, struct utmpx *utx) 931*7c478bd9Sstevel@tonic-gate { 932*7c478bd9Sstevel@tonic-gate setutxent(); 933*7c478bd9Sstevel@tonic-gate (void) pututxline(utx); 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ENDUTXENT 936*7c478bd9Sstevel@tonic-gate endutxent(); 937*7c478bd9Sstevel@tonic-gate # endif 938*7c478bd9Sstevel@tonic-gate return 1; 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate # else /* UTMPX_USE_LIBRARY */ 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate /* write a utmp entry direct to the file */ 944*7c478bd9Sstevel@tonic-gate static int 945*7c478bd9Sstevel@tonic-gate utmpx_write_direct(struct logininfo *li, struct utmpx *utx) 946*7c478bd9Sstevel@tonic-gate { 947*7c478bd9Sstevel@tonic-gate log("utmpx_write_direct: not implemented!"); 948*7c478bd9Sstevel@tonic-gate return 0; 949*7c478bd9Sstevel@tonic-gate } 950*7c478bd9Sstevel@tonic-gate # endif /* UTMPX_USE_LIBRARY */ 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate static int 953*7c478bd9Sstevel@tonic-gate utmpx_perform_login(struct logininfo *li) 954*7c478bd9Sstevel@tonic-gate { 955*7c478bd9Sstevel@tonic-gate struct utmpx utx; 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate construct_utmpx(li, &utx); 958*7c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY 959*7c478bd9Sstevel@tonic-gate if (!utmpx_write_library(li, &utx)) { 960*7c478bd9Sstevel@tonic-gate log("tmpx_perform_login: utmp_write_library() failed"); 961*7c478bd9Sstevel@tonic-gate return 0; 962*7c478bd9Sstevel@tonic-gate } 963*7c478bd9Sstevel@tonic-gate # else 964*7c478bd9Sstevel@tonic-gate if (!utmpx_write_direct(li, &ut)) { 965*7c478bd9Sstevel@tonic-gate log("utmpx_perform_login: utmp_write_direct() failed"); 966*7c478bd9Sstevel@tonic-gate return 0; 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate # endif 969*7c478bd9Sstevel@tonic-gate return 1; 970*7c478bd9Sstevel@tonic-gate } 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate 973*7c478bd9Sstevel@tonic-gate static int 974*7c478bd9Sstevel@tonic-gate utmpx_perform_logout(struct logininfo *li) 975*7c478bd9Sstevel@tonic-gate { 976*7c478bd9Sstevel@tonic-gate struct utmpx utx; 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate construct_utmpx(li, &utx); 979*7c478bd9Sstevel@tonic-gate # ifdef HAVE_ID_IN_UTMPX 980*7c478bd9Sstevel@tonic-gate (void) line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id)); 981*7c478bd9Sstevel@tonic-gate # endif 982*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMPX 983*7c478bd9Sstevel@tonic-gate utx.ut_type = DEAD_PROCESS; 984*7c478bd9Sstevel@tonic-gate # endif 985*7c478bd9Sstevel@tonic-gate 986*7c478bd9Sstevel@tonic-gate # ifdef UTMPX_USE_LIBRARY 987*7c478bd9Sstevel@tonic-gate (void) utmpx_write_library(li, &utx); 988*7c478bd9Sstevel@tonic-gate # else 989*7c478bd9Sstevel@tonic-gate utmpx_write_direct(li, &utx); 990*7c478bd9Sstevel@tonic-gate # endif 991*7c478bd9Sstevel@tonic-gate return 1; 992*7c478bd9Sstevel@tonic-gate } 993*7c478bd9Sstevel@tonic-gate 994*7c478bd9Sstevel@tonic-gate int 995*7c478bd9Sstevel@tonic-gate utmpx_write_entry(struct logininfo *li) 996*7c478bd9Sstevel@tonic-gate { 997*7c478bd9Sstevel@tonic-gate if (li->line_null) { 998*7c478bd9Sstevel@tonic-gate debug3("not writing utmpx entry"); 999*7c478bd9Sstevel@tonic-gate return 1; 1000*7c478bd9Sstevel@tonic-gate } 1001*7c478bd9Sstevel@tonic-gate debug3("writing utmpx entry"); 1002*7c478bd9Sstevel@tonic-gate 1003*7c478bd9Sstevel@tonic-gate switch(li->type) { 1004*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 1005*7c478bd9Sstevel@tonic-gate return utmpx_perform_login(li); 1006*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 1007*7c478bd9Sstevel@tonic-gate return utmpx_perform_logout(li); 1008*7c478bd9Sstevel@tonic-gate default: 1009*7c478bd9Sstevel@tonic-gate log("utmpx_write_entry: invalid type field"); 1010*7c478bd9Sstevel@tonic-gate return 0; 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate #endif /* USE_UTMPX */ 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate /** 1017*7c478bd9Sstevel@tonic-gate ** Low-level wtmp functions 1018*7c478bd9Sstevel@tonic-gate **/ 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMP 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate /* write a wtmp entry direct to the end of the file */ 1023*7c478bd9Sstevel@tonic-gate /* This is a slight modification of code in OpenBSD's logwtmp.c */ 1024*7c478bd9Sstevel@tonic-gate static int 1025*7c478bd9Sstevel@tonic-gate wtmp_write(struct logininfo *li, struct utmp *ut) 1026*7c478bd9Sstevel@tonic-gate { 1027*7c478bd9Sstevel@tonic-gate struct stat buf; 1028*7c478bd9Sstevel@tonic-gate int fd, ret = 1; 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 1031*7c478bd9Sstevel@tonic-gate log("wtmp_write: problem writing %s: %s", 1032*7c478bd9Sstevel@tonic-gate WTMP_FILE, strerror(errno)); 1033*7c478bd9Sstevel@tonic-gate return 0; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate if (fstat(fd, &buf) == 0) 1036*7c478bd9Sstevel@tonic-gate if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) { 1037*7c478bd9Sstevel@tonic-gate (void) ftruncate(fd, buf.st_size); 1038*7c478bd9Sstevel@tonic-gate log("wtmp_write: problem writing %s: %s", 1039*7c478bd9Sstevel@tonic-gate WTMP_FILE, strerror(errno)); 1040*7c478bd9Sstevel@tonic-gate ret = 0; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate (void)close(fd); 1043*7c478bd9Sstevel@tonic-gate return ret; 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate static int 1047*7c478bd9Sstevel@tonic-gate wtmp_perform_login(struct logininfo *li) 1048*7c478bd9Sstevel@tonic-gate { 1049*7c478bd9Sstevel@tonic-gate struct utmp ut; 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate construct_utmp(li, &ut); 1052*7c478bd9Sstevel@tonic-gate return wtmp_write(li, &ut); 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate static int 1057*7c478bd9Sstevel@tonic-gate wtmp_perform_logout(struct logininfo *li) 1058*7c478bd9Sstevel@tonic-gate { 1059*7c478bd9Sstevel@tonic-gate struct utmp ut; 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate construct_utmp(li, &ut); 1062*7c478bd9Sstevel@tonic-gate return wtmp_write(li, &ut); 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate int 1067*7c478bd9Sstevel@tonic-gate wtmp_write_entry(struct logininfo *li) 1068*7c478bd9Sstevel@tonic-gate { 1069*7c478bd9Sstevel@tonic-gate switch(li->type) { 1070*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 1071*7c478bd9Sstevel@tonic-gate return wtmp_perform_login(li); 1072*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 1073*7c478bd9Sstevel@tonic-gate return wtmp_perform_logout(li); 1074*7c478bd9Sstevel@tonic-gate default: 1075*7c478bd9Sstevel@tonic-gate log("wtmp_write_entry: invalid type field"); 1076*7c478bd9Sstevel@tonic-gate return 0; 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate 1081*7c478bd9Sstevel@tonic-gate /* Notes on fetching login data from wtmp/wtmpx 1082*7c478bd9Sstevel@tonic-gate * 1083*7c478bd9Sstevel@tonic-gate * Logouts are usually recorded with (amongst other things) a blank 1084*7c478bd9Sstevel@tonic-gate * username on a given tty line. However, some systems (HP-UX is one) 1085*7c478bd9Sstevel@tonic-gate * leave all fields set, but change the ut_type field to DEAD_PROCESS. 1086*7c478bd9Sstevel@tonic-gate * 1087*7c478bd9Sstevel@tonic-gate * Since we're only looking for logins here, we know that the username 1088*7c478bd9Sstevel@tonic-gate * must be set correctly. On systems that leave it in, we check for 1089*7c478bd9Sstevel@tonic-gate * ut_type==USER_PROCESS (indicating a login.) 1090*7c478bd9Sstevel@tonic-gate * 1091*7c478bd9Sstevel@tonic-gate * Portability: Some systems may set something other than USER_PROCESS 1092*7c478bd9Sstevel@tonic-gate * to indicate a login process. I don't know of any as I write. Also, 1093*7c478bd9Sstevel@tonic-gate * it's possible that some systems may both leave the username in 1094*7c478bd9Sstevel@tonic-gate * place and not have ut_type. 1095*7c478bd9Sstevel@tonic-gate */ 1096*7c478bd9Sstevel@tonic-gate 1097*7c478bd9Sstevel@tonic-gate /* return true if this wtmp entry indicates a login */ 1098*7c478bd9Sstevel@tonic-gate static int 1099*7c478bd9Sstevel@tonic-gate wtmp_islogin(struct logininfo *li, struct utmp *ut) 1100*7c478bd9Sstevel@tonic-gate { 1101*7c478bd9Sstevel@tonic-gate if (strncmp(li->username, ut->ut_name, 1102*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(li->username, ut->ut_name)) == 0) { 1103*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMP 1104*7c478bd9Sstevel@tonic-gate if (ut->ut_type & USER_PROCESS) 1105*7c478bd9Sstevel@tonic-gate return 1; 1106*7c478bd9Sstevel@tonic-gate # else 1107*7c478bd9Sstevel@tonic-gate return 1; 1108*7c478bd9Sstevel@tonic-gate # endif 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate return 0; 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate int 1114*7c478bd9Sstevel@tonic-gate wtmp_get_entry(struct logininfo *li) 1115*7c478bd9Sstevel@tonic-gate { 1116*7c478bd9Sstevel@tonic-gate struct stat st; 1117*7c478bd9Sstevel@tonic-gate struct utmp ut; 1118*7c478bd9Sstevel@tonic-gate int fd, found=0; 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate /* Clear the time entries in our logininfo */ 1121*7c478bd9Sstevel@tonic-gate li->tv_sec = li->tv_usec = 0; 1122*7c478bd9Sstevel@tonic-gate 1123*7c478bd9Sstevel@tonic-gate if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { 1124*7c478bd9Sstevel@tonic-gate log("wtmp_get_entry: problem opening %s: %s", 1125*7c478bd9Sstevel@tonic-gate WTMP_FILE, strerror(errno)); 1126*7c478bd9Sstevel@tonic-gate return 0; 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate if (fstat(fd, &st) != 0) { 1129*7c478bd9Sstevel@tonic-gate log("wtmp_get_entry: couldn't stat %s: %s", 1130*7c478bd9Sstevel@tonic-gate WTMP_FILE, strerror(errno)); 1131*7c478bd9Sstevel@tonic-gate (void) close(fd); 1132*7c478bd9Sstevel@tonic-gate return 0; 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate /* Seek to the start of the last struct utmp */ 1136*7c478bd9Sstevel@tonic-gate if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { 1137*7c478bd9Sstevel@tonic-gate /* Looks like we've got a fresh wtmp file */ 1138*7c478bd9Sstevel@tonic-gate (void) close(fd); 1139*7c478bd9Sstevel@tonic-gate return 0; 1140*7c478bd9Sstevel@tonic-gate } 1141*7c478bd9Sstevel@tonic-gate 1142*7c478bd9Sstevel@tonic-gate while (!found) { 1143*7c478bd9Sstevel@tonic-gate if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { 1144*7c478bd9Sstevel@tonic-gate log("wtmp_get_entry: read of %s failed: %s", 1145*7c478bd9Sstevel@tonic-gate WTMP_FILE, strerror(errno)); 1146*7c478bd9Sstevel@tonic-gate (void) close (fd); 1147*7c478bd9Sstevel@tonic-gate return 0; 1148*7c478bd9Sstevel@tonic-gate } 1149*7c478bd9Sstevel@tonic-gate if ( wtmp_islogin(li, &ut) ) { 1150*7c478bd9Sstevel@tonic-gate found = 1; 1151*7c478bd9Sstevel@tonic-gate /* We've already checked for a time in struct 1152*7c478bd9Sstevel@tonic-gate * utmp, in login_getlast(). */ 1153*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TIME_IN_UTMP 1154*7c478bd9Sstevel@tonic-gate li->tv_sec = ut.ut_time; 1155*7c478bd9Sstevel@tonic-gate # else 1156*7c478bd9Sstevel@tonic-gate # if HAVE_TV_IN_UTMP 1157*7c478bd9Sstevel@tonic-gate li->tv_sec = ut.ut_tv.tv_sec; 1158*7c478bd9Sstevel@tonic-gate # endif 1159*7c478bd9Sstevel@tonic-gate # endif 1160*7c478bd9Sstevel@tonic-gate (void) line_fullname(li->line, ut.ut_line, 1161*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(li->line, ut.ut_line)); 1162*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMP 1163*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->hostname, ut.ut_host, 1164*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(li->hostname, ut.ut_host)); 1165*7c478bd9Sstevel@tonic-gate # endif 1166*7c478bd9Sstevel@tonic-gate continue; 1167*7c478bd9Sstevel@tonic-gate } 1168*7c478bd9Sstevel@tonic-gate /* Seek back 2 x struct utmp */ 1169*7c478bd9Sstevel@tonic-gate if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { 1170*7c478bd9Sstevel@tonic-gate /* We've found the start of the file, so quit */ 1171*7c478bd9Sstevel@tonic-gate (void) close (fd); 1172*7c478bd9Sstevel@tonic-gate return 0; 1173*7c478bd9Sstevel@tonic-gate } 1174*7c478bd9Sstevel@tonic-gate } 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate /* We found an entry. Tidy up and return */ 1177*7c478bd9Sstevel@tonic-gate (void) close(fd); 1178*7c478bd9Sstevel@tonic-gate return 1; 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate # endif /* USE_WTMP */ 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate 1183*7c478bd9Sstevel@tonic-gate /** 1184*7c478bd9Sstevel@tonic-gate ** Low-level wtmpx functions 1185*7c478bd9Sstevel@tonic-gate **/ 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate #ifdef USE_WTMPX 1188*7c478bd9Sstevel@tonic-gate /* write a wtmpx entry direct to the end of the file */ 1189*7c478bd9Sstevel@tonic-gate /* This is a slight modification of code in OpenBSD's logwtmp.c */ 1190*7c478bd9Sstevel@tonic-gate static int 1191*7c478bd9Sstevel@tonic-gate wtmpx_write(struct logininfo *li, struct utmpx *utx) 1192*7c478bd9Sstevel@tonic-gate { 1193*7c478bd9Sstevel@tonic-gate struct stat buf; 1194*7c478bd9Sstevel@tonic-gate int fd, ret = 1; 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { 1197*7c478bd9Sstevel@tonic-gate log("wtmpx_write: problem opening %s: %s", 1198*7c478bd9Sstevel@tonic-gate WTMPX_FILE, strerror(errno)); 1199*7c478bd9Sstevel@tonic-gate return 0; 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate if (fstat(fd, &buf) == 0) 1203*7c478bd9Sstevel@tonic-gate if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) { 1204*7c478bd9Sstevel@tonic-gate (void) ftruncate(fd, buf.st_size); 1205*7c478bd9Sstevel@tonic-gate log("wtmpx_write: problem writing %s: %s", 1206*7c478bd9Sstevel@tonic-gate WTMPX_FILE, strerror(errno)); 1207*7c478bd9Sstevel@tonic-gate ret = 0; 1208*7c478bd9Sstevel@tonic-gate } 1209*7c478bd9Sstevel@tonic-gate (void)close(fd); 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate return ret; 1212*7c478bd9Sstevel@tonic-gate } 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate static int 1216*7c478bd9Sstevel@tonic-gate wtmpx_perform_login(struct logininfo *li) 1217*7c478bd9Sstevel@tonic-gate { 1218*7c478bd9Sstevel@tonic-gate struct utmpx utx; 1219*7c478bd9Sstevel@tonic-gate 1220*7c478bd9Sstevel@tonic-gate construct_utmpx(li, &utx); 1221*7c478bd9Sstevel@tonic-gate return wtmpx_write(li, &utx); 1222*7c478bd9Sstevel@tonic-gate } 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate 1225*7c478bd9Sstevel@tonic-gate static int 1226*7c478bd9Sstevel@tonic-gate wtmpx_perform_logout(struct logininfo *li) 1227*7c478bd9Sstevel@tonic-gate { 1228*7c478bd9Sstevel@tonic-gate struct utmpx utx; 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate construct_utmpx(li, &utx); 1231*7c478bd9Sstevel@tonic-gate return wtmpx_write(li, &utx); 1232*7c478bd9Sstevel@tonic-gate } 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate int 1236*7c478bd9Sstevel@tonic-gate wtmpx_write_entry(struct logininfo *li) 1237*7c478bd9Sstevel@tonic-gate { 1238*7c478bd9Sstevel@tonic-gate switch(li->type) { 1239*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 1240*7c478bd9Sstevel@tonic-gate return wtmpx_perform_login(li); 1241*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 1242*7c478bd9Sstevel@tonic-gate return wtmpx_perform_logout(li); 1243*7c478bd9Sstevel@tonic-gate default: 1244*7c478bd9Sstevel@tonic-gate log("wtmpx_write_entry: invalid type field"); 1245*7c478bd9Sstevel@tonic-gate return 0; 1246*7c478bd9Sstevel@tonic-gate } 1247*7c478bd9Sstevel@tonic-gate } 1248*7c478bd9Sstevel@tonic-gate 1249*7c478bd9Sstevel@tonic-gate /* Please see the notes above wtmp_islogin() for information about the 1250*7c478bd9Sstevel@tonic-gate next two functions */ 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate /* Return true if this wtmpx entry indicates a login */ 1253*7c478bd9Sstevel@tonic-gate static int 1254*7c478bd9Sstevel@tonic-gate wtmpx_islogin(struct logininfo *li, struct utmpx *utx) 1255*7c478bd9Sstevel@tonic-gate { 1256*7c478bd9Sstevel@tonic-gate if ( strncmp(li->username, utx->ut_name, 1257*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) { 1258*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TYPE_IN_UTMPX 1259*7c478bd9Sstevel@tonic-gate if (utx->ut_type == USER_PROCESS) 1260*7c478bd9Sstevel@tonic-gate return 1; 1261*7c478bd9Sstevel@tonic-gate # else 1262*7c478bd9Sstevel@tonic-gate return 1; 1263*7c478bd9Sstevel@tonic-gate # endif 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate return 0; 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate 1269*7c478bd9Sstevel@tonic-gate #if 0 1270*7c478bd9Sstevel@tonic-gate int 1271*7c478bd9Sstevel@tonic-gate wtmpx_get_entry(struct logininfo *li) 1272*7c478bd9Sstevel@tonic-gate { 1273*7c478bd9Sstevel@tonic-gate struct stat st; 1274*7c478bd9Sstevel@tonic-gate struct utmpx utx; 1275*7c478bd9Sstevel@tonic-gate int fd, found=0; 1276*7c478bd9Sstevel@tonic-gate 1277*7c478bd9Sstevel@tonic-gate /* Clear the time entries */ 1278*7c478bd9Sstevel@tonic-gate li->tv_sec = li->tv_usec = 0; 1279*7c478bd9Sstevel@tonic-gate 1280*7c478bd9Sstevel@tonic-gate if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { 1281*7c478bd9Sstevel@tonic-gate log("wtmpx_get_entry: problem opening %s: %s", 1282*7c478bd9Sstevel@tonic-gate WTMPX_FILE, strerror(errno)); 1283*7c478bd9Sstevel@tonic-gate return 0; 1284*7c478bd9Sstevel@tonic-gate } 1285*7c478bd9Sstevel@tonic-gate if (fstat(fd, &st) != 0) { 1286*7c478bd9Sstevel@tonic-gate log("wtmpx_get_entry: couldn't stat %s: %s", 1287*7c478bd9Sstevel@tonic-gate WTMPX_FILE, strerror(errno)); 1288*7c478bd9Sstevel@tonic-gate (void) close(fd); 1289*7c478bd9Sstevel@tonic-gate return 0; 1290*7c478bd9Sstevel@tonic-gate } 1291*7c478bd9Sstevel@tonic-gate 1292*7c478bd9Sstevel@tonic-gate /* Seek to the start of the last struct utmpx */ 1293*7c478bd9Sstevel@tonic-gate if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { 1294*7c478bd9Sstevel@tonic-gate /* probably a newly rotated wtmpx file */ 1295*7c478bd9Sstevel@tonic-gate (void) close(fd); 1296*7c478bd9Sstevel@tonic-gate return 0; 1297*7c478bd9Sstevel@tonic-gate } 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate while (!found) { 1300*7c478bd9Sstevel@tonic-gate if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { 1301*7c478bd9Sstevel@tonic-gate log("wtmpx_get_entry: read of %s failed: %s", 1302*7c478bd9Sstevel@tonic-gate WTMPX_FILE, strerror(errno)); 1303*7c478bd9Sstevel@tonic-gate (void) close (fd); 1304*7c478bd9Sstevel@tonic-gate return 0; 1305*7c478bd9Sstevel@tonic-gate } 1306*7c478bd9Sstevel@tonic-gate /* Logouts are recorded as a blank username on a particular line. 1307*7c478bd9Sstevel@tonic-gate * So, we just need to find the username in struct utmpx */ 1308*7c478bd9Sstevel@tonic-gate if ( wtmpx_islogin(li, &utx) ) { 1309*7c478bd9Sstevel@tonic-gate found = 1; 1310*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TV_IN_UTMPX 1311*7c478bd9Sstevel@tonic-gate li->tv_sec = utx.ut_tv.tv_sec; 1312*7c478bd9Sstevel@tonic-gate # else 1313*7c478bd9Sstevel@tonic-gate # ifdef HAVE_TIME_IN_UTMPX 1314*7c478bd9Sstevel@tonic-gate li->tv_sec = utx.ut_time; 1315*7c478bd9Sstevel@tonic-gate # endif 1316*7c478bd9Sstevel@tonic-gate # endif 1317*7c478bd9Sstevel@tonic-gate (void) line_fullname(li->line, utx.ut_line, sizeof(li->line)); 1318*7c478bd9Sstevel@tonic-gate # ifdef HAVE_HOST_IN_UTMPX 1319*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->hostname, utx.ut_host, 1320*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(li->hostname, utx.ut_host)); 1321*7c478bd9Sstevel@tonic-gate # endif 1322*7c478bd9Sstevel@tonic-gate continue; 1323*7c478bd9Sstevel@tonic-gate } 1324*7c478bd9Sstevel@tonic-gate if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { 1325*7c478bd9Sstevel@tonic-gate (void) close (fd); 1326*7c478bd9Sstevel@tonic-gate return 0; 1327*7c478bd9Sstevel@tonic-gate } 1328*7c478bd9Sstevel@tonic-gate } 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate (void) close(fd); 1331*7c478bd9Sstevel@tonic-gate return 1; 1332*7c478bd9Sstevel@tonic-gate } 1333*7c478bd9Sstevel@tonic-gate #endif 1334*7c478bd9Sstevel@tonic-gate #endif /* USE_WTMPX */ 1335*7c478bd9Sstevel@tonic-gate 1336*7c478bd9Sstevel@tonic-gate /** 1337*7c478bd9Sstevel@tonic-gate ** Low-level libutil login() functions 1338*7c478bd9Sstevel@tonic-gate **/ 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate #ifdef USE_LOGIN 1341*7c478bd9Sstevel@tonic-gate static int 1342*7c478bd9Sstevel@tonic-gate syslogin_perform_login(struct logininfo *li) 1343*7c478bd9Sstevel@tonic-gate { 1344*7c478bd9Sstevel@tonic-gate struct utmp *ut; 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) { 1347*7c478bd9Sstevel@tonic-gate log("syslogin_perform_login: couldn't malloc()"); 1348*7c478bd9Sstevel@tonic-gate return 0; 1349*7c478bd9Sstevel@tonic-gate } 1350*7c478bd9Sstevel@tonic-gate construct_utmp(li, ut); 1351*7c478bd9Sstevel@tonic-gate login(ut); 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate return 1; 1354*7c478bd9Sstevel@tonic-gate } 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate static int 1357*7c478bd9Sstevel@tonic-gate syslogin_perform_logout(struct logininfo *li) 1358*7c478bd9Sstevel@tonic-gate { 1359*7c478bd9Sstevel@tonic-gate # ifdef HAVE_LOGOUT 1360*7c478bd9Sstevel@tonic-gate char line[8]; 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate (void)line_stripname(line, li->line, sizeof(line)); 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate if (!logout(line)) { 1365*7c478bd9Sstevel@tonic-gate log("syslogin_perform_logout: logout() returned an error"); 1366*7c478bd9Sstevel@tonic-gate # ifdef HAVE_LOGWTMP 1367*7c478bd9Sstevel@tonic-gate } else { 1368*7c478bd9Sstevel@tonic-gate logwtmp(line, "", ""); 1369*7c478bd9Sstevel@tonic-gate # endif 1370*7c478bd9Sstevel@tonic-gate } 1371*7c478bd9Sstevel@tonic-gate /* FIXME: (ATL - if the need arises) What to do if we have 1372*7c478bd9Sstevel@tonic-gate * login, but no logout? what if logout but no logwtmp? All 1373*7c478bd9Sstevel@tonic-gate * routines are in libutil so they should all be there, 1374*7c478bd9Sstevel@tonic-gate * but... */ 1375*7c478bd9Sstevel@tonic-gate # endif 1376*7c478bd9Sstevel@tonic-gate return 1; 1377*7c478bd9Sstevel@tonic-gate } 1378*7c478bd9Sstevel@tonic-gate 1379*7c478bd9Sstevel@tonic-gate int 1380*7c478bd9Sstevel@tonic-gate syslogin_write_entry(struct logininfo *li) 1381*7c478bd9Sstevel@tonic-gate { 1382*7c478bd9Sstevel@tonic-gate switch (li->type) { 1383*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 1384*7c478bd9Sstevel@tonic-gate return syslogin_perform_login(li); 1385*7c478bd9Sstevel@tonic-gate case LTYPE_LOGOUT: 1386*7c478bd9Sstevel@tonic-gate return syslogin_perform_logout(li); 1387*7c478bd9Sstevel@tonic-gate default: 1388*7c478bd9Sstevel@tonic-gate log("syslogin_write_entry: Invalid type field"); 1389*7c478bd9Sstevel@tonic-gate return 0; 1390*7c478bd9Sstevel@tonic-gate } 1391*7c478bd9Sstevel@tonic-gate } 1392*7c478bd9Sstevel@tonic-gate #endif /* USE_LOGIN */ 1393*7c478bd9Sstevel@tonic-gate 1394*7c478bd9Sstevel@tonic-gate /* end of file log-syslogin.c */ 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate /** 1397*7c478bd9Sstevel@tonic-gate ** Low-level lastlog functions 1398*7c478bd9Sstevel@tonic-gate **/ 1399*7c478bd9Sstevel@tonic-gate 1400*7c478bd9Sstevel@tonic-gate #ifdef USE_LASTLOG 1401*7c478bd9Sstevel@tonic-gate #define LL_FILE 1 1402*7c478bd9Sstevel@tonic-gate #define LL_DIR 2 1403*7c478bd9Sstevel@tonic-gate #define LL_OTHER 3 1404*7c478bd9Sstevel@tonic-gate 1405*7c478bd9Sstevel@tonic-gate static void 1406*7c478bd9Sstevel@tonic-gate lastlog_construct(struct logininfo *li, struct lastlog *last) 1407*7c478bd9Sstevel@tonic-gate { 1408*7c478bd9Sstevel@tonic-gate /* clear the structure */ 1409*7c478bd9Sstevel@tonic-gate (void) memset(last, '\0', sizeof(*last)); 1410*7c478bd9Sstevel@tonic-gate 1411*7c478bd9Sstevel@tonic-gate (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); 1412*7c478bd9Sstevel@tonic-gate (void) strlcpy(last->ll_host, li->hostname, 1413*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(last->ll_host, li->hostname)); 1414*7c478bd9Sstevel@tonic-gate last->ll_time = li->tv_sec; 1415*7c478bd9Sstevel@tonic-gate } 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate static int 1418*7c478bd9Sstevel@tonic-gate lastlog_filetype(char *filename) 1419*7c478bd9Sstevel@tonic-gate { 1420*7c478bd9Sstevel@tonic-gate struct stat st; 1421*7c478bd9Sstevel@tonic-gate 1422*7c478bd9Sstevel@tonic-gate if (stat(LASTLOG_FILE, &st) != 0) { 1423*7c478bd9Sstevel@tonic-gate log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE, 1424*7c478bd9Sstevel@tonic-gate strerror(errno)); 1425*7c478bd9Sstevel@tonic-gate return 0; 1426*7c478bd9Sstevel@tonic-gate } 1427*7c478bd9Sstevel@tonic-gate if (S_ISDIR(st.st_mode)) 1428*7c478bd9Sstevel@tonic-gate return LL_DIR; 1429*7c478bd9Sstevel@tonic-gate else if (S_ISREG(st.st_mode)) 1430*7c478bd9Sstevel@tonic-gate return LL_FILE; 1431*7c478bd9Sstevel@tonic-gate else 1432*7c478bd9Sstevel@tonic-gate return LL_OTHER; 1433*7c478bd9Sstevel@tonic-gate } 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate /* open the file (using filemode) and seek to the login entry */ 1437*7c478bd9Sstevel@tonic-gate static int 1438*7c478bd9Sstevel@tonic-gate lastlog_openseek(struct logininfo *li, int *fd, int filemode) 1439*7c478bd9Sstevel@tonic-gate { 1440*7c478bd9Sstevel@tonic-gate off_t offset; 1441*7c478bd9Sstevel@tonic-gate int type; 1442*7c478bd9Sstevel@tonic-gate char lastlog_file[1024]; 1443*7c478bd9Sstevel@tonic-gate 1444*7c478bd9Sstevel@tonic-gate type = lastlog_filetype(LASTLOG_FILE); 1445*7c478bd9Sstevel@tonic-gate switch (type) { 1446*7c478bd9Sstevel@tonic-gate case LL_FILE: 1447*7c478bd9Sstevel@tonic-gate (void) strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); 1448*7c478bd9Sstevel@tonic-gate break; 1449*7c478bd9Sstevel@tonic-gate case LL_DIR: 1450*7c478bd9Sstevel@tonic-gate (void) snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", 1451*7c478bd9Sstevel@tonic-gate LASTLOG_FILE, li->username); 1452*7c478bd9Sstevel@tonic-gate break; 1453*7c478bd9Sstevel@tonic-gate default: 1454*7c478bd9Sstevel@tonic-gate log("lastlog_openseek: %.100s is not a file or directory!", 1455*7c478bd9Sstevel@tonic-gate LASTLOG_FILE); 1456*7c478bd9Sstevel@tonic-gate return 0; 1457*7c478bd9Sstevel@tonic-gate } 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate *fd = open(lastlog_file, filemode); 1460*7c478bd9Sstevel@tonic-gate if ( *fd < 0) { 1461*7c478bd9Sstevel@tonic-gate debug("lastlog_openseek: Couldn't open %s: %s", 1462*7c478bd9Sstevel@tonic-gate lastlog_file, strerror(errno)); 1463*7c478bd9Sstevel@tonic-gate return 0; 1464*7c478bd9Sstevel@tonic-gate } 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate if (type == LL_FILE) { 1467*7c478bd9Sstevel@tonic-gate /* find this uid's offset in the lastlog file */ 1468*7c478bd9Sstevel@tonic-gate offset = (off_t) ((long)li->uid * sizeof(struct lastlog)); 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate if ( lseek(*fd, offset, SEEK_SET) != offset ) { 1471*7c478bd9Sstevel@tonic-gate log("lastlog_openseek: %s->lseek(): %s", 1472*7c478bd9Sstevel@tonic-gate lastlog_file, strerror(errno)); 1473*7c478bd9Sstevel@tonic-gate return 0; 1474*7c478bd9Sstevel@tonic-gate } 1475*7c478bd9Sstevel@tonic-gate } 1476*7c478bd9Sstevel@tonic-gate 1477*7c478bd9Sstevel@tonic-gate return 1; 1478*7c478bd9Sstevel@tonic-gate } 1479*7c478bd9Sstevel@tonic-gate 1480*7c478bd9Sstevel@tonic-gate static int 1481*7c478bd9Sstevel@tonic-gate lastlog_perform_login(struct logininfo *li) 1482*7c478bd9Sstevel@tonic-gate { 1483*7c478bd9Sstevel@tonic-gate struct lastlog last; 1484*7c478bd9Sstevel@tonic-gate int fd; 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate /* create our struct lastlog */ 1487*7c478bd9Sstevel@tonic-gate lastlog_construct(li, &last); 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) 1490*7c478bd9Sstevel@tonic-gate return(0); 1491*7c478bd9Sstevel@tonic-gate 1492*7c478bd9Sstevel@tonic-gate /* write the entry */ 1493*7c478bd9Sstevel@tonic-gate if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) { 1494*7c478bd9Sstevel@tonic-gate (void) close(fd); 1495*7c478bd9Sstevel@tonic-gate log("lastlog_write_filemode: Error writing to %s: %s", 1496*7c478bd9Sstevel@tonic-gate LASTLOG_FILE, strerror(errno)); 1497*7c478bd9Sstevel@tonic-gate return 0; 1498*7c478bd9Sstevel@tonic-gate } 1499*7c478bd9Sstevel@tonic-gate 1500*7c478bd9Sstevel@tonic-gate (void) close(fd); 1501*7c478bd9Sstevel@tonic-gate return 1; 1502*7c478bd9Sstevel@tonic-gate } 1503*7c478bd9Sstevel@tonic-gate 1504*7c478bd9Sstevel@tonic-gate int 1505*7c478bd9Sstevel@tonic-gate lastlog_write_entry(struct logininfo *li) 1506*7c478bd9Sstevel@tonic-gate { 1507*7c478bd9Sstevel@tonic-gate switch(li->type) { 1508*7c478bd9Sstevel@tonic-gate case LTYPE_LOGIN: 1509*7c478bd9Sstevel@tonic-gate return lastlog_perform_login(li); 1510*7c478bd9Sstevel@tonic-gate default: 1511*7c478bd9Sstevel@tonic-gate log("lastlog_write_entry: Invalid type field"); 1512*7c478bd9Sstevel@tonic-gate return 0; 1513*7c478bd9Sstevel@tonic-gate } 1514*7c478bd9Sstevel@tonic-gate } 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate static void 1517*7c478bd9Sstevel@tonic-gate lastlog_populate_entry(struct logininfo *li, struct lastlog *last) 1518*7c478bd9Sstevel@tonic-gate { 1519*7c478bd9Sstevel@tonic-gate (void) line_fullname(li->line, last->ll_line, sizeof(li->line)); 1520*7c478bd9Sstevel@tonic-gate (void) strlcpy(li->hostname, last->ll_host, 1521*7c478bd9Sstevel@tonic-gate MIN_SIZEOF(li->hostname, last->ll_host)); 1522*7c478bd9Sstevel@tonic-gate li->tv_sec = last->ll_time; 1523*7c478bd9Sstevel@tonic-gate } 1524*7c478bd9Sstevel@tonic-gate 1525*7c478bd9Sstevel@tonic-gate int 1526*7c478bd9Sstevel@tonic-gate lastlog_get_entry(struct logininfo *li) 1527*7c478bd9Sstevel@tonic-gate { 1528*7c478bd9Sstevel@tonic-gate struct lastlog last; 1529*7c478bd9Sstevel@tonic-gate int fd; 1530*7c478bd9Sstevel@tonic-gate 1531*7c478bd9Sstevel@tonic-gate if (!lastlog_openseek(li, &fd, O_RDONLY)) 1532*7c478bd9Sstevel@tonic-gate return 0; 1533*7c478bd9Sstevel@tonic-gate 1534*7c478bd9Sstevel@tonic-gate if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) { 1535*7c478bd9Sstevel@tonic-gate (void) close(fd); 1536*7c478bd9Sstevel@tonic-gate log("lastlog_get_entry: Error reading from %s: %s", 1537*7c478bd9Sstevel@tonic-gate LASTLOG_FILE, strerror(errno)); 1538*7c478bd9Sstevel@tonic-gate return 0; 1539*7c478bd9Sstevel@tonic-gate } 1540*7c478bd9Sstevel@tonic-gate 1541*7c478bd9Sstevel@tonic-gate (void) close(fd); 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate lastlog_populate_entry(li, &last); 1544*7c478bd9Sstevel@tonic-gate 1545*7c478bd9Sstevel@tonic-gate return 1; 1546*7c478bd9Sstevel@tonic-gate } 1547*7c478bd9Sstevel@tonic-gate #endif /* USE_LASTLOG */ 1548