📄 loginrec.c
字号:
/* * Copyright (c) 2000 Andre Lucas. All rights reserved. * Portions copyright (c) 1998 Todd C. Miller * Portions copyright (c) 1996 Jason Downs * Portions copyright (c) 1996 Theo de Raadt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//* * The btmp logging code is derived from login.c from util-linux and is under * the the following license: * * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. *//** ** loginrec.c: platform-independent login recording and lastlog retrieval **//* * The new login code explained * ============================ * * This code attempts to provide a common interface to login recording * (utmp and friends) and last login time retrieval. * * Its primary means of achieving this is to use 'struct logininfo', a * union of all the useful fields in the various different types of * system login record structures one finds on UNIX variants. * * We depend on autoconf to define which recording methods are to be * used, and which fields are contained in the relevant data structures * on the local system. Many C preprocessor symbols affect which code * gets compiled here. * * The code is designed to make it easy to modify a particular * recording method, without affecting other methods nor requiring so * many nested conditional compilation blocks as were commonplace in * the old code. * * For login recording, we try to use the local system's libraries as * these are clearly most likely to work correctly. For utmp systems * this usually means login() and logout() or setutent() etc., probably * in libutil, along with logwtmp() etc. On these systems, we fall back * to writing the files directly if we have to, though this method * requires very thorough testing so we do not corrupt local auditing * information. These files and their access methods are very system * specific indeed. * * For utmpx systems, the corresponding library functions are * setutxent() etc. To the author's knowledge, all utmpx systems have * these library functions and so no direct write is attempted. If such * a system exists and needs support, direct analogues of the [uw]tmp * code should suffice. * * Retrieving the time of last login ('lastlog') is in some ways even * more problemmatic than login recording. Some systems provide a * simple table of all users which we seek based on uid and retrieve a * relatively standard structure. Others record the same information in * a directory with a separate file, and others don't record the * information separately at all. For systems in the latter category, * we look backwards in the wtmp or wtmpx file for the last login entry * for our user. Naturally this is slower and on busy systems could * incur a significant performance penalty. * * Calling the new code * -------------------- * * In OpenSSH all login recording and retrieval is performed in * login.c. Here you'll find working examples. Also, in the logintest.c * program there are more examples. * * Internal handler calling method * ------------------------------- * * When a call is made to login_login() or login_logout(), both * routines set a struct logininfo flag defining which action (log in, * or log out) is to be taken. They both then call login_write(), which * calls whichever of the many structure-specific handlers autoconf * selects for the local system. * * The handlers themselves handle system data structure specifics. Both * struct utmp and struct utmpx have utility functions (see * construct_utmp*()) to try to make it simpler to add extra systems * that introduce new features to either structure. * * While it may seem terribly wasteful to replicate so much similar * code for each method, experience has shown that maintaining code to * write both struct utmp and utmpx in one function, whilst maintaining * support for all systems whether they have library support or not, is * a difficult and time-consuming task. * * Lastlog support proceeds similarly. Functions login_get_lastlog() * (and its OpenSSH-tuned friend login_get_lastlog_time()) call * getlast_entry(), which tries one of three methods to find the last * login time. It uses local system lastlog support if it can, * otherwise it tries wtmp or wtmpx before giving up and returning 0, * meaning "tilt". * * Maintenance * ----------- * * In many cases it's possible to tweak autoconf to select the correct * methods for a particular platform, either by improving the detection * code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE * symbols for the platform. * * Use logintest to check which symbols are defined before modifying * configure.ac and loginrec.c. (You have to build logintest yourself * with 'make logintest' as it's not built by default.) * * Otherwise, patches to the specific method(s) are very helpful! */#include "includes.h"#include "ssh.h"#include "xmalloc.h"#include "loginrec.h"#include "log.h"#include "atomicio.h"#include "packet.h"#include "canohost.h"#include "auth.h"#include "buffer.h"#ifdef HAVE_UTIL_H# include <util.h>#endif#ifdef HAVE_LIBUTIL_H# include <libutil.h>#endifRCSID("$Id: loginrec.c,v 1.67 2005/02/15 11:19:28 dtucker Exp $");/** ** prototypes for helper functions in this file **/#if HAVE_UTMP_Hvoid set_utmp_time(struct logininfo *li, struct utmp *ut);void construct_utmp(struct logininfo *li, struct utmp *ut);#endif#ifdef HAVE_UTMPX_Hvoid set_utmpx_time(struct logininfo *li, struct utmpx *ut);void construct_utmpx(struct logininfo *li, struct utmpx *ut);#endifint utmp_write_entry(struct logininfo *li);int utmpx_write_entry(struct logininfo *li);int wtmp_write_entry(struct logininfo *li);int wtmpx_write_entry(struct logininfo *li);int lastlog_write_entry(struct logininfo *li);int syslogin_write_entry(struct logininfo *li);int getlast_entry(struct logininfo *li);int lastlog_get_entry(struct logininfo *li);int wtmp_get_entry(struct logininfo *li);int wtmpx_get_entry(struct logininfo *li);extern Buffer loginmsg;/* pick the shortest string */#define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2))/** ** platform-independent login functions **//* * login_login(struct logininfo *) - Record a login * * Call with a pointer to a struct logininfo initialised with * login_init_entry() or login_alloc_entry() * * Returns: * >0 if successful * 0 on failure (will use OpenSSH's logging facilities for diagnostics) */intlogin_login(struct logininfo *li){ li->type = LTYPE_LOGIN; return (login_write(li));}/* * login_logout(struct logininfo *) - Record a logout * * Call as with login_login() * * Returns: * >0 if successful * 0 on failure (will use OpenSSH's logging facilities for diagnostics) */intlogin_logout(struct logininfo *li){ li->type = LTYPE_LOGOUT; return (login_write(li));}/* * login_get_lastlog_time(int) - Retrieve the last login time * * Retrieve the last login time for the given uid. Will try to use the * system lastlog facilities if they are available, but will fall back * to looking in wtmp/wtmpx if necessary * * Returns: * 0 on failure, or if user has never logged in * Time in seconds from the epoch if successful * * Useful preprocessor symbols: * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog * info * USE_LASTLOG: If set, indicates the presence of system lastlog * facilities. If this and DISABLE_LASTLOG are not set, * try to retrieve lastlog information from wtmp/wtmpx. */unsigned intlogin_get_lastlog_time(const int uid){ struct logininfo li; if (login_get_lastlog(&li, uid)) return (li.tv_sec); else return (0);}/* * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry * * Retrieve a logininfo structure populated (only partially) with * information from the system lastlog data, or from wtmp/wtmpx if no * system lastlog information exists. * * Note this routine must be given a pre-allocated logininfo. * * Returns: * >0: A pointer to your struct logininfo if successful * 0 on failure (will use OpenSSH's logging facilities for diagnostics) */struct logininfo *login_get_lastlog(struct logininfo *li, const int uid){ struct passwd *pw; memset(li, '\0', sizeof(*li)); li->uid = uid; /* * If we don't have a 'real' lastlog, we need the username to * reliably search wtmp(x) for the last login (see * wtmp_get_entry().) */ pw = getpwuid(uid); if (pw == NULL) fatal("%s: Cannot find account for uid %i", __func__, uid); /* No MIN_SIZEOF here - we absolutely *must not* truncate the * username (XXX - so check for trunc!) */ strlcpy(li->username, pw->pw_name, sizeof(li->username)); if (getlast_entry(li)) return (li); else return (NULL);}/* * login_alloc_entry(int, char*, char*, char*) - Allocate and initialise * a logininfo structure * * This function creates a new struct logininfo, a data structure * meant to carry the information required to portably record login info. * * Returns a pointer to a newly created struct logininfo. If memory * allocation fails, the program halts. */structlogininfo *login_alloc_entry(int pid, const char *username, const char *hostname, const char *line){ struct logininfo *newli; newli = xmalloc(sizeof(*newli)); login_init_entry(newli, pid, username, hostname, line); return (newli);}/* login_free_entry(struct logininfo *) - free struct memory */voidlogin_free_entry(struct logininfo *li){ xfree(li);}/* login_init_entry(struct logininfo *, int, char*, char*, char*) * - initialise a struct logininfo * * Populates a new struct logininfo, a data structure meant to carry * the information required to portably record login info. * * Returns: 1 */intlogin_init_entry(struct logininfo *li, int pid, const char *username, const char *hostname, const char *line){ struct passwd *pw; memset(li, 0, sizeof(*li)); li->pid = pid; /* set the line information */ if (line) line_fullname(li->line, line, sizeof(li->line)); if (username) { strlcpy(li->username, username, sizeof(li->username)); pw = getpwnam(li->username); if (pw == NULL) { fatal("%s: Cannot find user \"%s\"", __func__, li->username); } li->uid = pw->pw_uid; } if (hostname) strlcpy(li->hostname, hostname, sizeof(li->hostname)); return (1);}/* * login_set_current_time(struct logininfo *) - set the current time * * Set the current time in a logininfo structure. This function is * meant to eliminate the need to deal with system dependencies for * time handling. */voidlogin_set_current_time(struct logininfo *li){ struct timeval tv; gettimeofday(&tv, NULL); li->tv_sec = tv.tv_sec; li->tv_usec = tv.tv_usec;}/* copy a sockaddr_* into our logininfo */voidlogin_set_addr(struct logininfo *li, const struct sockaddr *sa, const unsigned int sa_size){ unsigned int bufsize = sa_size; /* make sure we don't overrun our union */ if (sizeof(li->hostaddr) < sa_size) bufsize = sizeof(li->hostaddr); memcpy(&li->hostaddr.sa, sa, bufsize);}/** ** login_write: Call low-level recording functions based on autoconf ** results **/intlogin_write(struct logininfo *li){#ifndef HAVE_CYGWIN if (geteuid() != 0) { logit("Attempt to write login records by non-root user (aborting)"); return (1); }#endif /* set the timestamp */ login_set_current_time(li);#ifdef USE_LOGIN syslogin_write_entry(li);#endif#ifdef USE_LASTLOG if (li->type == LTYPE_LOGIN) lastlog_write_entry(li);#endif#ifdef USE_UTMP utmp_write_entry(li);#endif#ifdef USE_WTMP wtmp_write_entry(li);#endif#ifdef USE_UTMPX utmpx_write_entry(li);#endif#ifdef USE_WTMPX wtmpx_write_entry(li);#endif#ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN if (li->type == LTYPE_LOGIN && !sys_auth_record_login(li->username,li->hostname,li->line, &loginmsg)) logit("Writing login record failed for %s", li->username);#endif#ifdef SSH_AUDIT_EVENTS if (li->type == LTYPE_LOGIN) audit_session_open(li->line); else if (li->type == LTYPE_LOGOUT) audit_session_close(li->line);#endif return (0);}#ifdef LOGIN_NEEDS_UTMPXintlogin_utmp_only(struct logininfo *li){ li->type = LTYPE_LOGIN; login_set_current_time(li);# ifdef USE_UTMP utmp_write_entry(li);# endif# ifdef USE_WTMP wtmp_write_entry(li);# endif# ifdef USE_UTMPX utmpx_write_entry(li);# endif# ifdef USE_WTMPX wtmpx_write_entry(li);# endif return (0);}#endif/** ** getlast_entry: Call low-level functions to retrieve the last login ** time. **//* take the uid in li and return the last login time */intgetlast_entry(struct logininfo *li){#ifdef USE_LASTLOG return(lastlog_get_entry(li));#else /* !USE_LASTLOG */#if defined(DISABLE_LASTLOG) /* On some systems we shouldn't even try to obtain last login * time, e.g. AIX */ return (0);# elif defined(USE_WTMP) && \ (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) /* retrieve last login time from utmp */ return (wtmp_get_entry(li));# elif defined(USE_WTMPX) && \ (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) /* If wtmp isn't available, try wtmpx */ return (wtmpx_get_entry(li));# else /* Give up: No means of retrieving last login time */ return (0);# endif /* DISABLE_LASTLOG */#endif /* USE_LASTLOG */}/* * 'line' string utility functions * * These functions process the 'line' string into one of three forms: * * 1. The full filename (including '/dev') * 2. The stripped name (excluding '/dev') * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00 * /dev/pts/1 -> ts/1 ) * * Form 3 is used on some systems to identify a .tmp.? entry when * attempting to remove it. Typically both addition and removal is * performed by one application - say, sshd - so as long as the choice * uniquely identifies a terminal it's ok. *//* * line_fullname(): add the leading '/dev/' if it doesn't exist make * sure dst has enough space, if not just copy src (ugh) */char *line_fullname(char *dst, const char *src, int dstsize){ memset(dst, '\0', dstsize); if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) strlcpy(dst, src, dstsize); else { strlcpy(dst, "/dev/", dstsize); strlcat(dst, src, dstsize); } return (dst);}/* line_stripname(): strip the leading '/dev' if it exists, return dst */char *line_stripname(char *dst, const char *src, int dstsize){ memset(dst, '\0', dstsize); if (strncmp(src, "/dev/", 5) == 0) strlcpy(dst, src + 5, dstsize); else strlcpy(dst, src, dstsize); return (dst);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -