如何確定我的 sudoer 權限是否逾時?

如何確定我的 sudoer 權限是否逾時?

我正在編寫一個腳本,該腳本以sudo 身份運行命令,並且僅當我的sudo 權限超時才時才回顯一行文本,因此僅當使用sudo 運行命令需要我的用戶(而不是root)再次輸入其密碼時。

我如何驗證這一點?請注意,$(id -u)即使以 sudo 身份運行也會返回我當前的用戶 ID,因此無法檢查它是否與 0 匹配...

我需要一種可以安靜地檢查這一點的方法。

答案1

使用該選項-n檢查您是否仍擁有權限;從man sudo

-n,--非互動式

避免提示使用者進行任何類型的輸入。如果命令運行需要密碼,sudo 將顯示錯誤訊息並退出。

例如,

sudo -n true 2>/dev/null && echo Privileges active || echo Privileges inactive

sudo -n true請注意,在檢查和實際使用權限之間,權限可能會過期。您可能想直接嘗試,sudo -n command...並在失敗的情況下顯示一條訊息,並可能重試sudo互動運行。

編輯:另請參閱下面 ruakh 的評論。

答案2

跑步:

sudo -nv

如果您的 sudo 權限已逾時,則會以退出代碼 1 退出並輸出:

sudo: a password is required

如果您具有有效的快取憑證,則此命令將成功並且不輸出任何內容。

因此,將所有內容放在一起,這是一個腳本默默檢查您是否有有效的快取憑證:

if sudo -nv 2>/dev/null; then
  echo "no sudo password required"
else
  echo "sudo password expired"
fi

如同提到的其他答案/評論,-v如果有任何提示,則 sudo 的選項(「驗證」)會默默地更新快取的憑證,否則會提示進行驗證以產生快取的憑證,並且選項-n(「非互動式”)會阻止sudo 產生任何互動式提示,例如身份驗證提示。

答案3

sudo -nv工作正常,但會因 sudo 錯誤和 pam 身份驗證資訊污染系統日誌。我需要檢查 bash 提示字元的 sudo 權限,因此它經常被執行,而我的日誌幾乎只包含這些雜訊。

可以直接解析 sudo 時間戳檔案 - 我為它寫了一個小的 C util:

/* compile and set permissions: */
/* $ gcc checksudo.c -o checksudo -std=gnu99 -O2 */
/* $ chown root:root checksudo */
/* $ chmod +s checksudo */

#define USERNAME "replace-with-your-username"
#define TIMEOUT 5

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <time.h>

void timespec_diff(struct timespec *start, struct timespec *stop, struct timespec *result) {
    if ((stop->tv_nsec - start->tv_nsec) < 0) {
        result->tv_sec = stop->tv_sec - start->tv_sec - 1;
        result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000;
    } else {
        result->tv_sec = stop->tv_sec - start->tv_sec;
        result->tv_nsec = stop->tv_nsec - start->tv_nsec;
    }
    return;
}

int main(int argc, char** argv) {
  if (geteuid() != 0) {
    printf("uid is not 0 - checksudo must be owned by uid 0 and have the setuid bit set\n");
    return 2;
  }

  struct timespec current_time;
  if (clock_gettime(CLOCK_BOOTTIME, &current_time) != 0) {
    printf("Unable to get current time: %s\n", strerror(errno));
    return 2;
  }

  struct stat ttypath_stat;
  if (stat(ttyname(0), &ttypath_stat) != 0) {
    printf("Unable to stat current tty: %s\n", strerror(errno));
    return 2;
  }

  FILE* timestamp_fd = fopen("/var/run/sudo/ts/" USERNAME, "rb");
  if (timestamp_fd == NULL) {
    printf("Unable to open sudo timestamp file: %s\n", strerror(errno));
    return 2;
  }

  long offset = 0;
  int found = 0;

  while (1) {
    if (fseek(timestamp_fd, offset, SEEK_SET) != 0) {
      printf("Failed to seek timestamp file: %s\n", strerror(errno));
      return 2;
    }
    unsigned short timestamp_entry_header[4];
    if (feof(timestamp_fd)) {
      printf("matching timestamp not found\n");
      return 2;
    }
    if (fread(&timestamp_entry_header, sizeof(unsigned short), 4, timestamp_fd) < 4) {
      break;
    }
    if (ferror(timestamp_fd)) {
      printf("IO error when reading timestamp file\n");
      return 2;
    }

    // read tty device id
    if (timestamp_entry_header[2] == 2 && timestamp_entry_header[3] == 0) {
      if (fseek(timestamp_fd, offset + 32, SEEK_SET) != 0) {
        printf("Failed to seek timestamp file: %s\n", strerror(errno));
        return 2;
      }
      dev_t tty_dev_id;
      if (fread(&tty_dev_id, sizeof(dev_t), 1, timestamp_fd) < 1) {
        printf("EOF when reading tty device id\n");
        return 2;
      }
      if (tty_dev_id == ttypath_stat.st_rdev) {
        // read timestamp
        if (fseek(timestamp_fd, offset + 16, SEEK_SET) != 0) {
          printf("Failed to seek timestamp file: %s\n", strerror(errno));
          return 2;
        }
        struct timespec sudo_time;
        if (fread(&sudo_time, sizeof(struct timespec), 1, timestamp_fd) < 1) {
          printf("EOF when reading timestamp\n");
          return 2;
        }

        struct timespec time_since_sudo;
        timespec_diff(&sudo_time, &current_time, &time_since_sudo);
        found = time_since_sudo.tv_sec < TIMEOUT * 60;
        break;
      }
    }

    offset += timestamp_entry_header[1];
  }

  fclose(timestamp_fd);

  return !found;
}

相關內容