X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/a233586ba70f404ce62e749d8428d96204f192ca..aa56f760ea15248e3eeea92349bc5d0f27b053e3:/loginrec.c diff --git a/loginrec.c b/loginrec.c index 0945caaf..e5912774 100644 --- a/loginrec.c +++ b/loginrec.c @@ -25,6 +25,27 @@ * 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 **/ @@ -126,11 +147,33 @@ #include "includes.h" -#include "ssh.h" +#include +#include +#include + +#include + +#include +#include +#ifdef HAVE_PATHS_H +# include +#endif +#include +#include +#include +#include + #include "xmalloc.h" +#include "key.h" +#include "hostfile.h" +#include "ssh.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 @@ -140,8 +183,6 @@ # include #endif -RCSID("$Id$"); - /** ** prototypes for helper functions in this file **/ @@ -168,6 +209,8 @@ 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)) @@ -335,7 +378,7 @@ login_init_entry(struct logininfo *li, int pid, const char *username, strlcpy(li->username, username, sizeof(li->username)); pw = getpwnam(li->username); if (pw == NULL) { - fatal("%s: Cannot find user \"%s\"", __func__, + fatal("%s: Cannot find user \"%s\"", __func__, li->username); } li->uid = pw->pw_uid; @@ -347,7 +390,7 @@ login_init_entry(struct logininfo *li, int pid, const char *username, return (1); } -/* +/* * login_set_current_time(struct logininfo *) - set the current time * * Set the current time in a logininfo structure. This function is @@ -416,9 +459,16 @@ login_write(struct logininfo *li) 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)) + 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); } @@ -501,7 +551,7 @@ getlast_entry(struct logininfo *li) * sure dst has enough space, if not just copy src (ugh) */ char * -line_fullname(char *dst, const char *src, int dstsize) +line_fullname(char *dst, const char *src, u_int dstsize) { memset(dst, '\0', dstsize); if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) @@ -525,7 +575,7 @@ line_stripname(char *dst, const char *src, int dstsize) return (dst); } -/* +/* * line_abbrevname(): Return the abbreviated (usually four-character) * form of the line (Just use the last characters of the * full name.) @@ -775,7 +825,7 @@ utmp_write_library(struct logininfo *li, struct utmp *ut) } # else /* UTMP_USE_LIBRARY */ -/* +/* * Write a utmp entry direct to the file * This is a slightly modification of code in OpenBSD's login.c */ @@ -819,7 +869,7 @@ utmp_write_direct(struct logininfo *li, struct utmp *ut) return (0); } if (ret != pos) { - logit("%s: Couldn't seek to tty %d slot in %s", + logit("%s: Couldn't seek to tty %d slot in %s", __func__, tty, UTMP_FILE); return (0); } @@ -1019,7 +1069,7 @@ utmpx_write_entry(struct logininfo *li) #ifdef USE_WTMP -/* +/* * Write a wtmp entry direct to the end of the file * This is a slight modification of code in OpenBSD's logwtmp.c */ @@ -1080,7 +1130,7 @@ wtmp_write_entry(struct logininfo *li) } -/* +/* * Notes on fetching login data from wtmp/wtmpx * * Logouts are usually recorded with (amongst other things) a blank @@ -1124,12 +1174,12 @@ wtmp_get_entry(struct logininfo *li) li->tv_sec = li->tv_usec = 0; if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { - logit("%s: problem opening %s: %s", __func__, + logit("%s: problem opening %s: %s", __func__, WTMP_FILE, strerror(errno)); return (0); } if (fstat(fd, &st) != 0) { - logit("%s: couldn't stat %s: %s", __func__, + logit("%s: couldn't stat %s: %s", __func__, WTMP_FILE, strerror(errno)); close(fd); return (0); @@ -1144,7 +1194,7 @@ wtmp_get_entry(struct logininfo *li) while (!found) { if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { - logit("%s: read of %s failed: %s", __func__, + logit("%s: read of %s failed: %s", __func__, WTMP_FILE, strerror(errno)); close (fd); return (0); @@ -1202,7 +1252,7 @@ wtmpx_write(struct logininfo *li, struct utmpx *utx) int fd, ret = 1; if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { - logit("%s: problem opening %s: %s", __func__, + logit("%s: problem opening %s: %s", __func__, WTMPX_FILE, strerror(errno)); return (0); } @@ -1289,12 +1339,12 @@ wtmpx_get_entry(struct logininfo *li) li->tv_sec = li->tv_usec = 0; if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { - logit("%s: problem opening %s: %s", __func__, + logit("%s: problem opening %s: %s", __func__, WTMPX_FILE, strerror(errno)); return (0); } if (fstat(fd, &st) != 0) { - logit("%s: couldn't stat %s: %s", __func__, + logit("%s: couldn't stat %s: %s", __func__, WTMPX_FILE, strerror(errno)); close(fd); return (0); @@ -1309,13 +1359,13 @@ wtmpx_get_entry(struct logininfo *li) while (!found) { if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { - logit("%s: read of %s failed: %s", __func__, + logit("%s: read of %s failed: %s", __func__, WTMPX_FILE, strerror(errno)); close (fd); return (0); } /* - * Logouts are recorded as a blank username on a particular + * Logouts are recorded as a blank username on a particular * line. So, we just need to find the username in struct utmpx */ if (wtmpx_islogin(li, &utx)) { @@ -1353,10 +1403,7 @@ syslogin_perform_login(struct logininfo *li) { struct utmp *ut; - if ((ut = (struct utmp *)malloc(sizeof(*ut))) == NULL) { - logit("%s: couldn't malloc()", __func__); - return (0); - } + ut = xmalloc(sizeof(*ut)); construct_utmp(li, ut); login(ut); free(ut); @@ -1558,7 +1605,7 @@ lastlog_get_entry(struct logininfo *li) return (0); default: error("%s: Error reading from %s: Expecting %d, got %d", - __func__, LASTLOG_FILE, sizeof(last), ret); + __func__, LASTLOG_FILE, (int)sizeof(last), ret); return (0); } @@ -1566,3 +1613,82 @@ lastlog_get_entry(struct logininfo *li) return (0); } #endif /* USE_LASTLOG */ + +#ifdef USE_BTMP + /* + * Logs failed login attempts in _PATH_BTMP if that exists. + * The most common login failure is to give password instead of username. + * So the _PATH_BTMP file checked for the correct permission, so that + * only root can read it. + */ + +void +record_failed_login(const char *username, const char *hostname, + const char *ttyn) +{ + int fd; + struct utmp ut; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + struct sockaddr_in *a4; + struct sockaddr_in6 *a6; + time_t t; + struct stat fst; + + if (geteuid() != 0) + return; + if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) { + debug("Unable to open the btmp file %s: %s", _PATH_BTMP, + strerror(errno)); + return; + } + if (fstat(fd, &fst) < 0) { + logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP, + strerror(errno)); + goto out; + } + if((fst.st_mode & (S_IRWXG | S_IRWXO)) || (fst.st_uid != 0)){ + logit("Excess permission or bad ownership on file %s", + _PATH_BTMP); + goto out; + } + + memset(&ut, 0, sizeof(ut)); + /* strncpy because we don't necessarily want nul termination */ + strncpy(ut.ut_user, username, sizeof(ut.ut_user)); + strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); + + time(&t); + ut.ut_time = t; /* ut_time is not always a time_t */ + ut.ut_type = LOGIN_PROCESS; + ut.ut_pid = getpid(); + + /* strncpy because we don't necessarily want nul termination */ + strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); + + if (packet_connection_is_on_socket() && + getpeername(packet_get_connection_in(), + (struct sockaddr *)&from, &fromlen) == 0) { + ipv64_normalise_mapped(&from, &fromlen); + if (from.ss_family == AF_INET) { + a4 = (struct sockaddr_in *)&from; + memcpy(&ut.ut_addr, &(a4->sin_addr), + MIN_SIZEOF(ut.ut_addr, a4->sin_addr)); + } +#ifdef HAVE_ADDR_V6_IN_UTMP + if (from.ss_family == AF_INET6) { + a6 = (struct sockaddr_in6 *)&from; + memcpy(&ut.ut_addr_v6, &(a6->sin6_addr), + MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr)); + } +#endif + } + + if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut)) + error("Failed to write to %s: %s", _PATH_BTMP, + strerror(errno)); + +out: + close(fd); +} +#endif /* USE_BTMP */