📄 loginrec.c
字号:
/* * line_abbrevname(): Return the abbreviated (usually four-character) * form of the line (Just use the last <dstsize> characters of the * full name.) * * NOTE: use strncpy because we do NOT necessarily want zero * termination */char *line_abbrevname(char *dst, const char *src, int dstsize){ size_t len; memset(dst, '\0', dstsize); /* Always skip prefix if present */ if (strncmp(src, "/dev/", 5) == 0) src += 5;#ifdef WITH_ABBREV_NO_TTY if (strncmp(src, "tty", 3) == 0) src += 3;#endif len = strlen(src); if (len > 0) { if (((int)len - dstsize) > 0) src += ((int)len - dstsize); /* note: _don't_ change this to strlcpy */ strncpy(dst, src, (size_t)dstsize); } return (dst);}/** ** utmp utility functions ** ** These functions manipulate struct utmp, taking system differences ** into account. **/#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)/* build the utmp structure */voidset_utmp_time(struct logininfo *li, struct utmp *ut){# if defined(HAVE_TV_IN_UTMP) ut->ut_tv.tv_sec = li->tv_sec; ut->ut_tv.tv_usec = li->tv_usec;# elif defined(HAVE_TIME_IN_UTMP) ut->ut_time = li->tv_sec;# endif}voidconstruct_utmp(struct logininfo *li, struct utmp *ut){# ifdef HAVE_ADDR_V6_IN_UTMP struct sockaddr_in6 *sa6;# endif memset(ut, '\0', sizeof(*ut)); /* First fill out fields used for both logins and logouts */# ifdef HAVE_ID_IN_UTMP line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));# endif# ifdef HAVE_TYPE_IN_UTMP /* This is done here to keep utmp constants out of struct logininfo */ switch (li->type) { case LTYPE_LOGIN: ut->ut_type = USER_PROCESS;#ifdef _UNICOS cray_set_tmpdir(ut);#endif break; case LTYPE_LOGOUT: ut->ut_type = DEAD_PROCESS;#ifdef _UNICOS cray_retain_utmp(ut, li->pid);#endif break; }# endif set_utmp_time(li, ut); line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));# ifdef HAVE_PID_IN_UTMP ut->ut_pid = li->pid;# endif /* If we're logging out, leave all other fields blank */ if (li->type == LTYPE_LOGOUT) return; /* * These fields are only used when logging in, and are blank * for logouts. */ /* Use strncpy because we don't necessarily want null termination */ strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));# ifdef HAVE_HOST_IN_UTMP strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));# endif# ifdef HAVE_ADDR_IN_UTMP /* this is just a 32-bit IP address */ if (li->hostaddr.sa.sa_family == AF_INET) ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;# endif# ifdef HAVE_ADDR_V6_IN_UTMP /* this is just a 128-bit IPv6 address */ if (li->hostaddr.sa.sa_family == AF_INET6) { sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; ut->ut_addr_v6[1] = 0; ut->ut_addr_v6[2] = 0; ut->ut_addr_v6[3] = 0; } }# endif}#endif /* USE_UTMP || USE_WTMP || USE_LOGIN *//** ** utmpx utility functions ** ** These functions manipulate struct utmpx, accounting for system ** variations. **/#if defined(USE_UTMPX) || defined (USE_WTMPX)/* build the utmpx structure */voidset_utmpx_time(struct logininfo *li, struct utmpx *utx){# if defined(HAVE_TV_IN_UTMPX) utx->ut_tv.tv_sec = li->tv_sec; utx->ut_tv.tv_usec = li->tv_usec;# elif defined(HAVE_TIME_IN_UTMPX) utx->ut_time = li->tv_sec;# endif}voidconstruct_utmpx(struct logininfo *li, struct utmpx *utx){# ifdef HAVE_ADDR_V6_IN_UTMP struct sockaddr_in6 *sa6;# endif memset(utx, '\0', sizeof(*utx));# ifdef HAVE_ID_IN_UTMPX line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));# endif /* this is done here to keep utmp constants out of loginrec.h */ switch (li->type) { case LTYPE_LOGIN: utx->ut_type = USER_PROCESS; break; case LTYPE_LOGOUT: utx->ut_type = DEAD_PROCESS; break; } line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); set_utmpx_time(li, utx); utx->ut_pid = li->pid; /* strncpy(): Don't necessarily want null termination */ strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username)); if (li->type == LTYPE_LOGOUT) return; /* * These fields are only used when logging in, and are blank * for logouts. */# ifdef HAVE_HOST_IN_UTMPX strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));# endif# ifdef HAVE_ADDR_IN_UTMPX /* this is just a 32-bit IP address */ if (li->hostaddr.sa.sa_family == AF_INET) utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;# endif# ifdef HAVE_ADDR_V6_IN_UTMP /* this is just a 128-bit IPv6 address */ if (li->hostaddr.sa.sa_family == AF_INET6) { sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; ut->ut_addr_v6[1] = 0; ut->ut_addr_v6[2] = 0; ut->ut_addr_v6[3] = 0; } }# endif# ifdef HAVE_SYSLEN_IN_UTMPX /* ut_syslen is the length of the utx_host string */ utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));# endif}#endif /* USE_UTMPX || USE_WTMPX *//** ** Low-level utmp functions **//* FIXME: (ATL) utmp_write_direct needs testing */#ifdef USE_UTMP/* if we can, use pututline() etc. */# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ defined(HAVE_PUTUTLINE)# define UTMP_USE_LIBRARY# endif/* write a utmp entry with the system's help (pututline() and pals) */# ifdef UTMP_USE_LIBRARYstatic intutmp_write_library(struct logininfo *li, struct utmp *ut){ setutent(); pututline(ut);# ifdef HAVE_ENDUTENT endutent();# endif return (1);}# else /* UTMP_USE_LIBRARY *//* * Write a utmp entry direct to the file * This is a slightly modification of code in OpenBSD's login.c */static intutmp_write_direct(struct logininfo *li, struct utmp *ut){ struct utmp old_ut; register int fd; int tty; /* FIXME: (ATL) ttyslot() needs local implementation */#if defined(HAVE_GETTTYENT) struct ttyent *ty; tty=0; setttyent(); while (NULL != (ty = getttyent())) { tty++; if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) break; } endttyent(); if (NULL == ty) { logit("%s: tty not found", __func__); return (0); }#else /* FIXME */ tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */#endif /* HAVE_GETTTYENT */ if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) { off_t pos, ret; pos = (off_t)tty * sizeof(struct utmp); if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { logit("%s: lseek: %s", __func__, strerror(errno)); return (0); } if (ret != pos) { logit("%s: Couldn't seek to tty %d slot in %s", __func__, tty, UTMP_FILE); return (0); } /* * Prevent luser from zero'ing out ut_host. * If the new ut_line is empty but the old one is not * and ut_line and ut_name match, preserve the old ut_line. */ if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { logit("%s: lseek: %s", __func__, strerror(errno)); return (0); } if (ret != pos) { logit("%s: Couldn't seek to tty %d slot in %s", __func__, tty, UTMP_FILE); return (0); } if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { logit("%s: error writing %s: %s", __func__, UTMP_FILE, strerror(errno)); } close(fd); return (1); } else { return (0); }}# endif /* UTMP_USE_LIBRARY */static intutmp_perform_login(struct logininfo *li){ struct utmp ut; construct_utmp(li, &ut);# ifdef UTMP_USE_LIBRARY if (!utmp_write_library(li, &ut)) { logit("%s: utmp_write_library() failed", __func__); return (0); }# else if (!utmp_write_direct(li, &ut)) { logit("%s: utmp_write_direct() failed", __func__); return (0); }# endif return (1);}static intutmp_perform_logout(struct logininfo *li){ struct utmp ut; construct_utmp(li, &ut);# ifdef UTMP_USE_LIBRARY if (!utmp_write_library(li, &ut)) { logit("%s: utmp_write_library() failed", __func__); return (0); }# else if (!utmp_write_direct(li, &ut)) { logit("%s: utmp_write_direct() failed", __func__); return (0); }# endif return (1);}intutmp_write_entry(struct logininfo *li){ switch(li->type) { case LTYPE_LOGIN: return (utmp_perform_login(li)); case LTYPE_LOGOUT: return (utmp_perform_logout(li)); default: logit("%s: invalid type field", __func__); return (0); }}#endif /* USE_UTMP *//** ** Low-level utmpx functions **//* not much point if we don't want utmpx entries */#ifdef USE_UTMPX/* if we have the wherewithall, use pututxline etc. */# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \ defined(HAVE_PUTUTXLINE)# define UTMPX_USE_LIBRARY# endif/* write a utmpx entry with the system's help (pututxline() and pals) */# ifdef UTMPX_USE_LIBRARYstatic intutmpx_write_library(struct logininfo *li, struct utmpx *utx){ setutxent(); pututxline(utx);# ifdef HAVE_ENDUTXENT endutxent();# endif return (1);}# else /* UTMPX_USE_LIBRARY *//* write a utmp entry direct to the file */static intutmpx_write_direct(struct logininfo *li, struct utmpx *utx){ logit("%s: not implemented!", __func__); return (0);}# endif /* UTMPX_USE_LIBRARY */static intutmpx_perform_login(struct logininfo *li){ struct utmpx utx; construct_utmpx(li, &utx);# ifdef UTMPX_USE_LIBRARY if (!utmpx_write_library(li, &utx)) { logit("%s: utmp_write_library() failed", __func__); return (0); }# else if (!utmpx_write_direct(li, &ut)) { logit("%s: utmp_write_direct() failed", __func__); return (0); }# endif return (1);}static intutmpx_perform_logout(struct logininfo *li){ struct utmpx utx; construct_utmpx(li, &utx);# ifdef HAVE_ID_IN_UTMPX line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));# endif# ifdef HAVE_TYPE_IN_UTMPX utx.ut_type = DEAD_PROCESS;# endif# ifdef UTMPX_USE_LIBRARY utmpx_write_library(li, &utx);# else utmpx_write_direct(li, &utx);# endif return (1);}intutmpx_write_entry(struct logininfo *li){ switch(li->type) { case LTYPE_LOGIN: return (utmpx_perform_login(li)); case LTYPE_LOGOUT: return (utmpx_perform_logout(li)); default: logit("%s: invalid type field", __func__); return (0); }}#endif /* USE_UTMPX *//** ** Low-level wtmp functions **/#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 */static intwtmp_write(struct logininfo *li, struct utmp *ut){ struct stat buf; int fd, ret = 1; if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { logit("%s: problem writing %s: %s", __func__, WTMP_FILE, strerror(errno)); return (0); } if (fstat(fd, &buf) == 0) if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { ftruncate(fd, buf.st_size); logit("%s: problem writing %s: %s", __func__, WTMP_FILE, strerror(errno)); ret = 0; } close(fd); 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: logit("%s: invalid type field", __func__); 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -