Làm thế nào để tôi biết nếu đặc quyền sudoer của tôi hết thời gian?


20

Tôi đang làm việc với một tập lệnh chạy lệnh là sudo và lặp lại một dòng văn bản CHỈ nếu đặc quyền sudo của tôi đã hết thời gian, vì vậy chỉ khi chạy một lệnh với sudo thì sẽ yêu cầu người dùng của tôi (không phải root) nhập lại mật khẩu của nó.

Làm thế nào để tôi xác minh điều đó? Nhớ rằng$(id -u) ngay cả khi chạy dưới dạng sudo sẽ trả về id người dùng hiện tại của tôi để không thể kiểm tra để khớp với 0 ...

Tôi cần một phương pháp sẽ kiểm tra điều này một cách lặng lẽ.

Câu trả lời:


28

Sử dụng tùy chọn -nđể kiểm tra xem bạn vẫn có đặc quyền hay không; từ man sudo:

-n , --non-tương tác

Tránh nhắc nhở người dùng cho bất kỳ loại đầu vào. Nếu mật khẩu được yêu cầu để lệnh chạy, sudo sẽ hiển thị thông báo lỗi và thoát.

Ví dụ,

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

Xin lưu ý rằng các đặc quyền có thể hết hạn giữa việc kiểm tra sudo -n truevà thực sự sử dụng chúng. Bạn có thể muốn thử trực tiếp với sudo -n command...và trong trường hợp không hiển thị thông báo và có thể thử lại đang chạysudo tương tác.

Chỉnh sửa: Xem thêm bình luận của ruakh dưới đây.


Cảm ơn bạn tôi đã thử một cái gì đó tương tự trước đây nhưng tôi không thể làm cho nó hoạt động theo cách tôi muốn.
TonyMorello

3
Re: "Hãy lưu ý rằng các đặc quyền có thể hết hạn giữa việc kiểm tra sudo -n truevà thực sự sử dụng chúng": Tài liệu này hơi mơ hồ về điểm này, nhưng tôi nghĩ rằng việc chạy một sudolệnh, thậm chí chỉ sudo -n true, sẽ đặt lại thời gian chờ đồng hồ. Dù bằng cách nào, -vđược ghi lại rõ ràng là làm như vậy, và sudo -n -vcó lẽ phù hợp hơn so sudo -n truevới mục đích này.
ruakh

Mặc dù điều này sẽ thực sự im lặng, nó sẽ ghi lỗi vào nhật ký hệ thống nếu không có đặc quyền : hostname sudo[8870]: username : a password is required ; TTY=pts/0 ; PWD=/home/username ; USER=root ; COMMAND=/usr/bin/true. Ví dụ, nếu bạn sử dụng nó trong dấu nhắc bash, nó sẽ dẫn đến nhiều thông báo lỗi.
Rogach

Và nếu có đặc quyền, sẽ có ghi nhật ký gỡ lỗi từ pam_unix và thực thi lệnh sudo.
Rogach

8

Chạy:

sudo -nv

Nếu đặc quyền sudo của bạn đã hết thời gian, điều này sẽ thoát với mã thoát là 1 và đầu ra:

sudo: a password is required

Nếu bạn có thông tin lưu trữ hợp lệ, lệnh này sẽ thành công và không tạo ra kết quả gì.

Vì vậy, để kết hợp tất cả lại, đây là một tập lệnh sẽ âm thầm kiểm tra xem bạn có thông tin lưu trữ hợp lệ không:

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

Như các câu trả lời / nhận xét khác đã đề cập, -vtùy chọn ("xác thực") để sudo âm thầm gia hạn thông tin xác thực được lưu trong bộ nhớ cache nếu có bất kỳ lời nhắc nào khác để xác thực để tạo thông tin lưu trữ được lưu trữ và -ntùy chọn ("không tương tác") ngăn sudo tạo bất kỳ lời nhắc tương tác nào, chẳng hạn như lời nhắc xác thực.


Đây là một giải pháp tốt ... Tôi đã thử nó trước đây nhưng câu trả lời của AlexP thực hiện chính xác những gì tôi cần ... Tôi nghĩ rằng tôi đã hiểu nhầm thông số -n trước đây
TonyMorello

1

sudo -nvhoạt động tốt, nhưng gây ô nhiễm nhật ký hệ thống với lỗi sudo và thông tin xác thực pam. Tôi cần kiểm tra đặc quyền sudo cho dấu nhắc bash của mình, vì vậy nó được thực thi khá thường xuyên và nhật ký của tôi hầu như chỉ có tiếng ồn này.

Có thể phân tích trực tiếp tệp dấu thời gian sudo - Tôi đã viết một C nhỏ sử dụng cho nó:

/* 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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.