📄 loginrec.c
字号:
return ret;}static intwtmp_perform_login(struct logininfo *li){ struct utmp ut; construct_utmp(li, &ut); return wtmp_write(li, &ut);}static intwtmp_perform_logout(struct logininfo *li){ struct utmp ut; construct_utmp(li, &ut); return wtmp_write(li, &ut);}intwtmp_write_entry(struct logininfo *li){ switch(li->type) { case LTYPE_LOGIN: return wtmp_perform_login(li); case LTYPE_LOGOUT: return wtmp_perform_logout(li); default: log("wtmp_write_entry: invalid type field"); return 0; }}/* Notes on fetching login data from wtmp/wtmpx * * Logouts are usually recorded with (amongst other things) a blank * username on a given tty line. However, some systems (HP-UX is one) * leave all fields set, but change the ut_type field to DEAD_PROCESS. * * Since we're only looking for logins here, we know that the username * must be set correctly. On systems that leave it in, we check for * ut_type==USER_PROCESS (indicating a login.) * * Portability: Some systems may set something other than USER_PROCESS * to indicate a login process. I don't know of any as I write. Also, * it's possible that some systems may both leave the username in * place and not have ut_type. *//* return true if this wtmp entry indicates a login */static intwtmp_islogin(struct logininfo *li, struct utmp *ut){ if (strncmp(li->username, ut->ut_name, MIN_SIZEOF(li->username, ut->ut_name)) == 0) {# ifdef HAVE_TYPE_IN_UTMP if (ut->ut_type & USER_PROCESS) return 1;# else return 1;# endif } return 0;}intwtmp_get_entry(struct logininfo *li){ struct stat st; struct utmp ut; int fd, found=0; /* Clear the time entries in our logininfo */ li->tv_sec = li->tv_usec = 0; if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { log("wtmp_get_entry: problem opening %s: %s", WTMP_FILE, strerror(errno)); return 0; } if (fstat(fd, &st) != 0) { log("wtmp_get_entry: couldn't stat %s: %s", WTMP_FILE, strerror(errno)); close(fd); return 0; } /* Seek to the start of the last struct utmp */ if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { /* Looks like we've got a fresh wtmp file */ close(fd); return 0; } while (!found) { if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { log("wtmp_get_entry: read of %s failed: %s", WTMP_FILE, strerror(errno)); close (fd); return 0; } if ( wtmp_islogin(li, &ut) ) { found = 1; /* We've already checked for a time in struct * utmp, in login_getlast(). */# ifdef HAVE_TIME_IN_UTMP li->tv_sec = ut.ut_time;# else# if HAVE_TV_IN_UTMP li->tv_sec = ut.ut_tv.tv_sec;# endif# endif line_fullname(li->line, ut.ut_line, MIN_SIZEOF(li->line, ut.ut_line));# ifdef HAVE_HOST_IN_UTMP strlcpy(li->hostname, ut.ut_host, MIN_SIZEOF(li->hostname, ut.ut_host));# endif continue; } /* Seek back 2 x struct utmp */ if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { /* We've found the start of the file, so quit */ close (fd); return 0; } } /* We found an entry. Tidy up and return */ close(fd); return 1;}# endif /* USE_WTMP *//** ** Low-level wtmpx functions **/#ifdef USE_WTMPX/* write a wtmpx entry direct to the end of the file *//* This is a slight modification of code in OpenBSD's logwtmp.c */static intwtmpx_write(struct logininfo *li, struct utmpx *utx){ struct stat buf; int fd, ret = 1; if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { log("wtmpx_write: problem opening %s: %s", WTMPX_FILE, strerror(errno)); return 0; } if (fstat(fd, &buf) == 0) if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) { ftruncate(fd, buf.st_size); log("wtmpx_write: problem writing %s: %s", WTMPX_FILE, strerror(errno)); ret = 0; } (void)close(fd); return ret;}static intwtmpx_perform_login(struct logininfo *li){ struct utmpx utx; construct_utmpx(li, &utx); return wtmpx_write(li, &utx);}static intwtmpx_perform_logout(struct logininfo *li){ struct utmpx utx; construct_utmpx(li, &utx); return wtmpx_write(li, &utx);}intwtmpx_write_entry(struct logininfo *li){ switch(li->type) { case LTYPE_LOGIN: return wtmpx_perform_login(li); case LTYPE_LOGOUT: return wtmpx_perform_logout(li); default: log("wtmpx_write_entry: invalid type field"); return 0; }}/* Please see the notes above wtmp_islogin() for information about the next two functions *//* Return true if this wtmpx entry indicates a login */static intwtmpx_islogin(struct logininfo *li, struct utmpx *utx){ if ( strncmp(li->username, utx->ut_name, MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {# ifdef HAVE_TYPE_IN_UTMPX if (utx->ut_type == USER_PROCESS) return 1;# else return 1;# endif } return 0;}intwtmpx_get_entry(struct logininfo *li){ struct stat st; struct utmpx utx; int fd, found=0; /* Clear the time entries */ li->tv_sec = li->tv_usec = 0; if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { log("wtmpx_get_entry: problem opening %s: %s", WTMPX_FILE, strerror(errno)); return 0; } if (fstat(fd, &st) != 0) { log("wtmpx_get_entry: couldn't stat %s: %s", WTMP_FILE, strerror(errno)); close(fd); return 0; } /* Seek to the start of the last struct utmpx */ if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { /* probably a newly rotated wtmpx file */ close(fd); return 0; } while (!found) { if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { log("wtmpx_get_entry: read of %s failed: %s", WTMPX_FILE, strerror(errno)); close (fd); return 0; } /* 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) ) {# ifdef HAVE_TV_IN_UTMPX li->tv_sec = utx.ut_tv.tv_sec;# else# ifdef HAVE_TIME_IN_UTMPX li->tv_sec = utx.ut_time;# endif# endif line_fullname(li->line, utx.ut_line, sizeof(li->line));# ifdef HAVE_HOST_IN_UTMPX strlcpy(li->hostname, utx.ut_host, MIN_SIZEOF(li->hostname, utx.ut_host));# endif continue; } if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { close (fd); return 0; } } close(fd); return 1;}#endif /* USE_WTMPX *//** ** Low-level libutil login() functions **/#ifdef USE_LOGINstatic intsyslogin_perform_login(struct logininfo *li){ struct utmp *ut; if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) { log("syslogin_perform_login: couldn't malloc()"); return 0; } construct_utmp(li, ut); login(ut); return 1;}static intsyslogin_perform_logout(struct logininfo *li){# ifdef HAVE_LOGOUT char line[8]; (void)line_stripname(line, li->line, sizeof(line)); if (!logout(line)) { log("syslogin_perform_logout: logout() returned an error");# ifdef HAVE_LOGWTMP } else { logwtmp(line, "", "");# endif } /* FIXME: (ATL - if the need arises) What to do if we have * login, but no logout? what if logout but no logwtmp? All * routines are in libutil so they should all be there, * but... */# endif return 1;}intsyslogin_write_entry(struct logininfo *li){ switch (li->type) { case LTYPE_LOGIN: return syslogin_perform_login(li); case LTYPE_LOGOUT: return syslogin_perform_logout(li); default: log("syslogin_write_entry: Invalid type field"); return 0; }}#endif /* USE_LOGIN *//* end of file log-syslogin.c *//** ** Low-level lastlog functions **/#ifdef USE_LASTLOG#define LL_FILE 1#define LL_DIR 2#define LL_OTHER 3static voidlastlog_construct(struct logininfo *li, struct lastlog *last){ /* clear the structure */ memset(last, '\0', sizeof(*last)); (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); strlcpy(last->ll_host, li->hostname, MIN_SIZEOF(last->ll_host, li->hostname)); last->ll_time = li->tv_sec;}static intlastlog_filetype(char *filename){ struct stat st; if (stat(LASTLOG_FILE, &st) != 0) { log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE, strerror(errno)); return 0; } if (S_ISDIR(st.st_mode)) return LL_DIR; else if (S_ISREG(st.st_mode)) return LL_FILE; else return LL_OTHER;}/* open the file (using filemode) and seek to the login entry */static intlastlog_openseek(struct logininfo *li, int *fd, int filemode){ off_t offset; int type; char lastlog_file[1024]; type = lastlog_filetype(LASTLOG_FILE); switch (type) { case LL_FILE: strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); break; case LL_DIR: snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", LASTLOG_FILE, li->username); break; default: log("lastlog_openseek: %.100s is not a file or directory!", LASTLOG_FILE); return 0; } *fd = open(lastlog_file, filemode); if ( *fd < 0) { debug("lastlog_openseek: Couldn't open %s: %s", lastlog_file, strerror(errno)); return 0; } if (type == LL_FILE) { /* find this uid's offset in the lastlog file */ offset = (off_t) ((long)li->uid * sizeof(struct lastlog)); if ( lseek(*fd, offset, SEEK_SET) != offset ) { log("lastlog_openseek: %s->lseek(): %s", lastlog_file, strerror(errno)); return 0; } } return 1;}static intlastlog_perform_login(struct logininfo *li){ struct lastlog last; int fd; /* create our struct lastlog */ lastlog_construct(li, &last); if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) return(0); /* write the entry */ if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) { close(fd); log("lastlog_write_filemode: Error writing to %s: %s", LASTLOG_FILE, strerror(errno)); return 0; } close(fd); return 1;}intlastlog_write_entry(struct logininfo *li){ switch(li->type) { case LTYPE_LOGIN: return lastlog_perform_login(li); default: log("lastlog_write_entry: Invalid type field"); return 0; }}static voidlastlog_populate_entry(struct logininfo *li, struct lastlog *last){ line_fullname(li->line, last->ll_line, sizeof(li->line)); strlcpy(li->hostname, last->ll_host, MIN_SIZEOF(li->hostname, last->ll_host)); li->tv_sec = last->ll_time;}intlastlog_get_entry(struct logininfo *li){ struct lastlog last; int fd; if (!lastlog_openseek(li, &fd, O_RDONLY)) return 0; if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) { close(fd); log("lastlog_get_entry: Error reading from %s: %s", LASTLOG_FILE, strerror(errno)); return 0; } close(fd); lastlog_populate_entry(li, &last); return 1;}#endif /* USE_LASTLOG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -