我可以将 sudo 会话的状态添加到 bash 提示符中,如下所示:
function sudo_active() {
if sudo -n /bin/true 2> /dev/null
then
printf '(sudo) '
fi
}
PS1="$PS1"'$(sudo_active)'
这样我就可以运行一系列 sudo 命令,然后我就会知道 sudo 会话是否仍然处于活动状态。我可以使用 提前结束会话sudo -k
、关闭 shell,或者只是记住要小心。
这种方法的一个问题是,每次在没有 sudo 权限的情况下运行新提示时,它都会在系统日志中添加如下消息:
sudo[25653]: myusername : a password is required ; TTY=pts/13 ; PWD=/home/myusername/ ; USER=root ; COMMAND=/bin/true
另一个问题是,因为这sudo
每次都会在提示符中运行命令,所以每次运行命令时(取决于 的值passwd_timeout
),它都会重新延长超时,即使我不运行需要 的命令sudo
。
有没有办法可以测试 sudo 会话是否仍然处于活动状态并在 bash 提示符中显示这一点,而不会不断重新扩展会话作为副作用?
答案1
您可以使用 sudo 为每个用户创建的时间戳文件来查找该用户使用 sudo 命令的时间;如果比配置的时间长timestamp_timeout
(默认 5 分钟),则新的 sudo 将需要密码。
每个用户的文件是在/var/run/sudo/ts/
(在我的系统上)下创建的。其格式部分描述于man sudoers
,您可以从来源中看到时间戳.c和检查.h它由 structstruct timestamp_entry_v1
或较新的struct 描述的多个记录组成struct timestamp_entry
。
git 版本比我的旧系统对应的源更新,因此我使用旧的结构版本 1。您可能需要带有额外字段的新版本 2。
下面是一个最小的 C 程序,用于转储硬连线用户的记录:
/* https://unix.stackexchange.com/a/595473/119298
* struct from
* https://github.com/sudo-project/sudo/blob/master/plugins/sudoers/check.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define TS_VERSION 1
/* Time stamp entry types */
#define TS_GLOBAL 0x01
#define TS_TTY 0x02
#define TS_PPID 0x03
#define TS_LOCKEXCL 0x04
/* Time stamp flags */
#define TS_DISABLED 0x01 /* entry disabled */
#define TS_ANYUID 0x02 /* ignore uid, only valid in the key */
struct timestamp_entry {
unsigned short version; /* version number */
unsigned short size; /* entry size */
unsigned short type; /* TS_GLOBAL, TS_TTY, TS_PPID */
unsigned short flags; /* TS_DISABLED, TS_ANYUID */
uid_t auth_uid; /* uid to authenticate as */
pid_t sid; /* session ID associated with tty/ppid */
struct timespec ts; /* timestamp (CLOCK_MONOTONIC) */
union {
dev_t ttydev; /* tty device number */
pid_t ppid; /* parent pid */
} u;
};
void main(int argc, char **argv){
struct timestamp_entry entry;
struct timespec now;
int fd = open("/var/run/sudo/ts/meuh",O_RDONLY);
if(fd<0)exit(1);
clock_gettime(CLOCK_MONOTONIC, &now);
while(read(fd,&entry,sizeof(entry))==sizeof(entry)){
printf("type=%d flags=%d uid=%d sid=%d elapsedtime=%d\n",
entry.type, entry.flags, entry.auth_uid, entry.sid,
entry.ts.tv_sec-now.tv_sec);
}
exit(0);
}
在我的系统上编译并运行这个 setuid root 给了我这样的行
type=4 flags=0 uid=0 sid=0 elapsedtime=-4763540
type=2 flags=1 uid=1000 sid=7003 elapsedtime=-4763540
type=2 flags=0 uid=1000 sid=4378 elapsedtime=-12
类型 4 的第一个条目用于锁定记录。其他行可以是 per-tty 等等。标志为 1 表示禁用条目(例如由于sudo -k
)。最后一行是我的 uid 1000 在 12 秒前从进程 4378 执行了 sudo 命令。由于这不到 5*60 秒,因此进一步的 sudo 还不需要密码。