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