将 sudo 会话的状态添加到 PS1 而不扩展会话

将 sudo 会话的状态添加到 PS1 而不扩展会话

我可以将 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 还不需要密码。

相关内容