ฉันจะรู้ได้อย่างไรว่าสิทธิ์ sudoer หมดเวลาหรือไม่


20

ฉันกำลังทำงานกับสคริปต์ที่รันคำสั่งเป็น sudo และ echoes บรรทัดข้อความเท่านั้นหากสิทธิ์ sudo ของฉันหมดเวลาดังนั้นหากใช้คำสั่งด้วย sudo จะต้องให้ผู้ใช้ของฉัน (ไม่รูท) เพื่อพิมพ์รหัสผ่านอีกครั้ง

ฉันจะตรวจสอบได้อย่างไร โปรดทราบว่า$(id -u)แม้ในขณะที่ทำงานเป็น sudo จะส่งคืนรหัสผู้ใช้ปัจจุบันของฉันดังนั้นจึงไม่สามารถตรวจสอบเพื่อให้ตรงกับ 0 ...

ฉันต้องการวิธีที่จะตรวจสอบเรื่องนี้อย่างเงียบ ๆ

คำตอบ:


28

ใช้ตัวเลือก-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 ด้านล่าง


ขอบคุณฉันลองสิ่งที่คล้ายกันมาก่อน แต่ฉันไม่สามารถทำให้มันเป็นไปตามที่ฉันต้องการ
TonyMorello

3
Re: "ระวังว่ามันเป็นไปได้สำหรับสิทธิ์ที่จะหมดอายุระหว่างการตรวจสอบกับsudo -n trueและใช้พวกเขาจริง ๆ ": เอกสารเป็นบิตคลุมเครือในจุดนี้ แต่ฉันคิดว่าการใช้sudoคำสั่งแม้เพียงแค่sudo -n trueจะตั้งค่าการหมดเวลาอีกครั้ง นาฬิกา. ไม่ว่าจะด้วยวิธีใดก็ตาม-vจะได้รับการบันทึกอย่างชัดเจนว่าเป็นสิ่งนั้นและsudo -n -vอาจเหมาะสมกว่าsudo -n trueสำหรับวัตถุประสงค์นี้อยู่ดี
ruakh

hostname sudo[8870]: username : a password is required ; TTY=pts/0 ; PWD=/home/username ; USER=root ; COMMAND=/usr/bin/trueในขณะนี้จะเงียบจริงมันจะเข้าสู่ระบบข้อผิดพลาดวารสารระบบถ้ามีไม่มีสิทธิ: ถ้าคุณใช้มันใน bash prompt มันจะส่งผลให้เกิดข้อความแสดงข้อผิดพลาดมากมาย
Rogach

และหากมีสิทธิพิเศษจะมีการบันทึกการดีบักจากการประมวลผลคำสั่ง pam_unix และ sudo
Rogach

8

วิ่ง:

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 จากการสร้าง พรอมต์แบบโต้ตอบใด ๆ เช่นพรอมต์การตรวจสอบความถูกต้อง


นี่เป็นทางออกที่ดี ... ฉันลองมาก่อน แต่คำตอบของ AlexP ทำตามที่ฉันต้องการ ... ฉันคิดว่าฉันเข้าใจผิดพารามิเตอร์ -n ก่อน
TonyMorello

1

sudo -nvทำงานได้ดี แต่บันทึกของระบบจะปนเปื้อนด้วยข้อผิดพลาด sudo และข้อมูลการตรวจสอบสิทธิ์แพม ฉันต้องการตรวจสอบสิทธิ์ sudo สำหรับ bash prompt ของฉันดังนั้นจึงมีการดำเนินการค่อนข้างบ่อยและบันทึกของฉันมีเพียงเสียงนี้เท่านั้น

เป็นไปได้ที่จะแยกวิเคราะห์ไฟล์ timestamp 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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.