login帐户有一个不活动的计时器设置为35天。 也就是说,/etc/pam.d/passwd-auth有一行
auth required pam_lastlog.so inactive=35
所以我得到像这样的线
sshd[29629]: pam_unix(sshd:account): account weaverw has expired (failed to change password) sshd[29629]: pam_lastlog(sshd:account): user weaverw inactive for 71 days - denied
问题:重新激活这些帐户的最佳方法是什么? SA已经做了什么,然后退出,所以它会在lastlog中进入,但这似乎不雅观。
要修复pam_unix密码过期,请编辑/etc/shadow 。 它有格式[冒号分隔字段]:
username:passwd:number_of_days_since_pw_changed:...
并将第三个字段设置为零。
要修复pam_lastlog这有点丑陋。 控制文件是/var/log/lastlog 。 这是一个压缩和/或二进制格式的文件。
它可以用lastlog实用程序查看 。 但[AFAICT]公用事业机构没有提供更改个人条目的机制。
看来推荐的方法是清空文件。 虽然这改变了所有的用户,这不是严重的passwd到期的变化。 cp /dev/null /var/log/lastlog会在不影响selinux权限的情况下执行此操作。
usermod实用程序将重置单个用户的信息,但仅在使用-u选项更改用户的uid时才会重置。 也许,与-o一起使用:
usermod -o -u <current_uid_of_user> <username>
在最坏的情况下,在两个命令中执行,首先将uid设置为新的唯一uid,然后将其设置回旧的。 例如,如果用户的uid是5001,并且没有使用uid 5500,请执行以下操作:
usermod -u 5500 fred usermod -u 5001 fred
如果你真的想保留/var/log/lastlog大部分信息,并且上面的方法不起作用,那么shadow-utils源代码包有办法做到这一点…
以下是useradd的源代码片段:
static void lastlog_reset (uid_t uid) { struct lastlog ll; int fd; off_t offset_uid = (off_t) (sizeof ll) * uid; if (access (LASTLOG_FILE, F_OK) != 0) { return; } memzero (&ll, sizeof (ll)); fd = open (LASTLOG_FILE, O_RDWR); if ( (-1 == fd) || (lseek (fd, offset_uid, SEEK_SET) != offset_uid) || (write (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll)) || (fsync (fd) != 0) || (close (fd) != 0)) { fprintf (stderr, _("%s: failed to reset the lastlog entry of UID %lu: %s\n"), Prog, (unsigned long) uid, strerror (errno)); SYSLOG ((LOG_WARN, "failed to reset the lastlog entry of UID %lu", (unsigned long) uid)); /* continue */ } }
这是一个来自usermod的片段:
/* * update_lastlog - update the lastlog file * * Relocate the "lastlog" entries for the user. The old entry is * left alone in case the UID was shared. It doesn't hurt anything * to just leave it be. */ static void update_lastlog (void) { struct lastlog ll; int fd; off_t off_uid = (off_t) user_id * sizeof ll; off_t off_newuid = (off_t) user_newid * sizeof ll; if (access (LASTLOG_FILE, F_OK) != 0) { return; } fd = open (LASTLOG_FILE, O_RDWR); if (-1 == fd) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno)); return; } if ( (lseek (fd, off_uid, SEEK_SET) == off_uid) && (read (fd, &ll, sizeof ll) == (ssize_t) sizeof ll)) { /* Copy the old entry to its new location */ if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) || (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) || (fsync (fd) != 0) || (close (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno)); } } else { /* Assume lseek or read failed because there is * no entry for the old UID */ /* Check if the new UID already has an entry */ if ( (lseek (fd, off_newuid, SEEK_SET) == off_newuid) && (read (fd, &ll, sizeof ll) == (ssize_t) sizeof ll)) { /* Reset the new uid's lastlog entry */ memzero (&ll, sizeof (ll)); if ( (lseek (fd, off_newuid, SEEK_SET) != off_newuid) || (write (fd, &ll, sizeof ll) != (ssize_t) sizeof ll) || (fsync (fd) != 0) || (close (fd) != 0)) { fprintf (stderr, _("%s: failed to copy the lastlog entry of user %lu to user %lu: %s\n"), Prog, (unsigned long) user_id, (unsigned long) user_newid, strerror (errno)); } } else { (void) close (fd); } } }
struct lastlog的定义来自#include <lastlog.h> ,其#include <lastlog.h>如下:
/* The structure describing an entry in the database of previous logins. */ struct lastlog { #ifdef __WORDSIZE_TIME64_COMPAT32 int32_t ll_time; #else __time_t ll_time; #endif char ll_line[UT_LINESIZE]; char ll_host[UT_HOSTSIZE]; };
如果您可以以另一个用户身份login到服务器,则可以“su – user ”重置login时间。