static void update_lastlog (const char *pty, const char *host) { # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX) struct lastlogx llx; # endif # ifdef HAVE_STRUCT_LASTLOG int fd; struct lastlog ll; # endif # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX) memset (&llx, 0, sizeof (llx)); llx.ll_tv.tv_sec = time (NULL); llx.ll_tv.tv_usec = 0; strncpy (llx.ll_line, pty, sizeof (llx.ll_line)); strncpy (llx.ll_host, host, sizeof (llx.ll_host)); updlastlogx (LASTLOGX_FILE, getuid (), &llx); # endif # ifdef HAVE_STRUCT_LASTLOG memset (&ll, 0, sizeof (ll)); ll.ll_time = time (NULL); strncpy (ll.ll_line, pty, sizeof (ll.ll_line)); strncpy (ll.ll_host, host, sizeof (ll.ll_host)); if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) { if (lseek (fd, (off_t) (getuid () * sizeof (ll)), SEEK_SET) != -1) write (fd, &ll, sizeof (ll)); close (fd); } # endif /* HAVE_STRUCT_LASTLOG */ }
static void dolastlogx(int quiet) { struct lastlogx ll; if (!quiet && getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) { time_t t = (time_t)ll.ll_tv.tv_sec; (void)printf("Last login: %.24s ", ctime(&t)); if (*ll.ll_host != '\0') (void)printf("from %.*s ", (int)sizeof(ll.ll_host), ll.ll_host); (void)printf("on %.*s\n", (int)sizeof(ll.ll_line), ll.ll_line); } ll.ll_tv = now; (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); if (hostname) (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); else (void)memset(ll.ll_host, '\0', sizeof(ll.ll_host)); if (have_ss) ll.ll_ss = ss; else (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) syslog(LOG_NOTICE, "Cannot update lastlogx: %m"); }
static void update_lastlog (const char *fname, const char *pty, const char *host) { # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX) struct lastlogx llx; # endif # ifdef HAVE_STRUCT_LASTLOG int fd; struct lastlog ll; char lastlogfile[256]; struct passwd *pwent; struct stat st; # endif # if defined(HAVE_STRUCT_LASTLOGX) && defined(HAVE_UPDLASTLOGX) memset (&llx, 0, sizeof (llx)); llx.ll_tv.tv_sec = time (NULL); llx.ll_tv.tv_usec = 0; strncpy (llx.ll_line, pty, sizeof (llx.ll_line)); strncpy (llx.ll_host, host, sizeof (llx.ll_host)); updlastlogx (LASTLOGX_FILE, getuid (), &llx); # endif # ifdef HAVE_STRUCT_LASTLOG pwent = getpwuid (getuid ()); if (!pwent) { ptytty_warn ("no entry in password file, not updating lastlog.\n", 0); return; } memset (&ll, 0, sizeof (ll)); ll.ll_time = time (NULL); strncpy (ll.ll_line, pty, sizeof (ll.ll_line)); strncpy (ll.ll_host, host, sizeof (ll.ll_host)); if (stat (fname, &st) != 0) return; if (S_ISDIR (st.st_mode)) { snprintf (lastlogfile, sizeof (lastlogfile), "%s/%s", fname, (!pwent->pw_name || pwent->pw_name[0] == '\0') ? "unknown" : pwent->pw_name); if ((fd = open (lastlogfile, O_WRONLY | O_CREAT, 0644)) >= 0) { write (fd, &ll, sizeof (ll)); close (fd); } } else if (S_ISREG (st.st_mode)) if ((fd = open (fname, O_RDWR)) != -1) { if (lseek (fd, (off_t) ((long)pwent->pw_uid * sizeof (ll)), SEEK_SET) != -1) write (fd, &ll, sizeof (ll)); close (fd); } # endif /* HAVE_STRUCT_LASTLOG */ }
/* INTPROTO */ static void rxvt_update_lastlog(const char *fname, const char *pty, const char *host) { # ifdef HAVE_STRUCT_LASTLOGX struct lastlogx llx; # endif # ifdef HAVE_STRUCT_LASTLOG int fd; struct lastlog ll; # ifdef LASTLOG_IS_DIR char lastlogfile[256]; # endif struct passwd *pwent; # endif # ifdef HAVE_STRUCT_LASTLOGX MEMSET(&llx, 0, sizeof(llx)); llx.ll_tv.tv_sec = time(NULL); llx.ll_tv.tv_usec = 0; STRNCPY(llx.ll_line, pty, sizeof(llx.ll_line)); STRNCPY(llx.ll_host, host, sizeof(llx.ll_host)); updlastlogx(RXVT_LASTLOGX_FILE, getuid(), &llx); # endif # ifdef HAVE_STRUCT_LASTLOG pwent = getpwuid(getuid()); if (!pwent) { rxvt_msg (DBG_ERROR, DBG_LOGGING, "no entry in password file"); return; } MEMSET(&ll, 0, sizeof(ll)); ll.ll_time = time(NULL); STRNCPY(ll.ll_line, pty, sizeof(ll.ll_line)); STRNCPY(ll.ll_host, host, sizeof(ll.ll_host)); # ifdef LASTLOG_IS_DIR sprintf(lastlogfile, "%.*s/%.*s", sizeof(lastlogfile) - sizeof(pwent->pw_name) - 2, fname, sizeof(pwent->pw_name), (!pwent->pw_name || pwent->pw_name[0] == '\0') ? "unknown" : pwent->pw_name); if ((fd = open(lastlogfile, O_WRONLY | O_CREAT, 0644)) >= 0) { write(fd, &ll, sizeof(ll)); close(fd); } # else if ((fd = open(fname, O_RDWR)) != -1) { if (lseek(fd, (off_t) ((long)pwent->pw_uid * sizeof(ll)), SEEK_SET) != -1) write(fd, &ll, sizeof(ll)); close(fd); } # endif /* LASTLOG_IS_DIR */ # endif /* HAVE_STRUCT_LASTLOG */ }
/* * Records that the user has logged in. I wish these parts of operating * systems were more standardized. */ void record_login(pid_t pid, const char *tty, const char *user, uid_t uid, const char *host, struct sockaddr *addr, socklen_t addrlen) { #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) int fd; #endif struct timeval tv; #ifdef SUPPORT_UTMP struct utmp u; struct lastlog ll; #endif #ifdef SUPPORT_UTMPX struct utmpx ux, *uxp = &ux; struct lastlogx llx; #endif (void)gettimeofday(&tv, NULL); /* * XXX: why do we need to handle logout cases here? * Isn't the function below taking care of this? */ /* save previous login details before writing new */ store_lastlog_message(user, uid); #ifdef SUPPORT_UTMP /* Construct an utmp/wtmp entry. */ memset(&u, 0, sizeof(u)); strncpy(u.ut_line, tty + 5, sizeof(u.ut_line)); u.ut_time = (time_t)tv.tv_sec; strncpy(u.ut_name, user, sizeof(u.ut_name)); strncpy(u.ut_host, host, sizeof(u.ut_host)); login(&u); /* Update lastlog unless actually recording a logout. */ if (*user != '\0') { /* * It is safer to memset the lastlog structure first because * some systems might have some extra fields in it (e.g. SGI) */ memset(&ll, 0, sizeof(ll)); /* Update lastlog. */ ll.ll_time = time(NULL); strncpy(ll.ll_line, tty + 5, sizeof(ll.ll_line)); strncpy(ll.ll_host, host, sizeof(ll.ll_host)); fd = open(_PATH_LASTLOG, O_RDWR); if (fd >= 0) { lseek(fd, (off_t)uid * sizeof(ll), SEEK_SET); if (write(fd, &ll, sizeof(ll)) != sizeof(ll)) logit("Could not write %.100s: %.100s", _PATH_LASTLOG, strerror(errno)); close(fd); } } #endif #ifdef SUPPORT_UTMPX /* Construct an utmpx/wtmpx entry. */ memset(&ux, 0, sizeof(ux)); strncpy(ux.ut_line, tty + 5, sizeof(ux.ut_line)); if (*user) { ux.ut_pid = pid; ux.ut_type = USER_PROCESS; ux.ut_tv = tv; strncpy(ux.ut_name, user, sizeof(ux.ut_name)); strncpy(ux.ut_host, host, sizeof(ux.ut_host)); /* XXX: need ut_id, use last 4 char of tty */ if (strlen(tty) > sizeof(ux.ut_id)) { strncpy(ux.ut_id, tty + strlen(tty) - sizeof(ux.ut_id), sizeof(ux.ut_id)); } else strncpy(ux.ut_id, tty, sizeof(ux.ut_id)); /* XXX: It would be better if we had sockaddr_storage here */ if (addrlen > sizeof(ux.ut_ss)) addrlen = sizeof(ux.ut_ss); (void)memcpy(&ux.ut_ss, addr, addrlen); if (pututxline(&ux) == NULL) logit("could not add utmpx line: %.100s", strerror(errno)); /* Update lastlog. */ (void)gettimeofday(&llx.ll_tv, NULL); strncpy(llx.ll_line, tty + 5, sizeof(llx.ll_line)); strncpy(llx.ll_host, host, sizeof(llx.ll_host)); (void)memcpy(&llx.ll_ss, addr, addrlen); if (updlastlogx(_PATH_LASTLOGX, uid, &llx) == -1) logit("Could not update %.100s: %.100s", _PATH_LASTLOGX, strerror(errno)); } else { if ((uxp = getutxline(&ux)) == NULL) logit("could not find utmpx line for %.100s", tty); else { uxp->ut_type = DEAD_PROCESS; uxp->ut_tv = tv; /* XXX: we don't record exit info yet */ if (pututxline(&ux) == NULL) logit("could not replace utmpx line: %.100s", strerror(errno)); } } endutxent(); updwtmpx(_PATH_WTMPX, uxp); #endif }
struct utmpx * pututxline(const struct utmpx *utx) { struct passwd *pw; struct lastlogx ll; struct utmpx temp, *u = NULL; int gotlock = 0; _DIAGASSERT(utx != NULL); if (utx == NULL) return NULL; if (utx->ut_type == USER_PROCESS) { ll.ll_tv = utx->ut_tv; strcpy(ll.ll_host, utx->ut_host); strcpy(ll.ll_line, utx->ut_line); pw = getpwnam(utx->ut_name); if (pw != NULL) updlastlogx(_PATH_LASTLOGX, pw->pw_uid, &ll); } if (strcmp(_PATH_UTMPX, utfile) == 0) if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0)) return utmp_update(utx); (void)memcpy(&temp, utx, sizeof(temp)); if (fp == NULL) { (void)getutxent(); if (fp == NULL || readonly) return NULL; } if (getutxid(&temp) == NULL) { setutxent(); if (getutxid(&temp) == NULL) { if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1) return NULL; gotlock++; if (fseeko(fp, (off_t)0, SEEK_END) == -1) goto fail; } } if (!gotlock) { /* we are not appending */ if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1) return NULL; } if (fwrite(&temp, sizeof (temp), 1, fp) != 1) goto fail; if (fflush(fp) == -1) goto fail; u = memcpy(&ut, &temp, sizeof(ut)); fail: if (gotlock) { if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1) return NULL; } return u; }