내 sudoer 권한이 시간 초과되었는지 어떻게 알 수 있나요?

내 sudoer 권한이 시간 초과되었는지 어떻게 알 수 있나요?

저는 sudo로 명령을 실행하고 sudo 권한이 시간 초과된 경우에만 텍스트 줄을 에코하는 스크립트를 작업 중입니다. 따라서 sudo로 명령을 실행하려면 루트가 아닌 사용자가 비밀번호를 다시 입력해야 합니다.

어떻게 확인하나요? sudo로 실행하더라도 현재 사용자 ID 가 $(id -u)반환되므로 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

언급된 다른 답변/설명에 따르면 -vsudo 옵션("유효성 검사")은 캐시된 자격 증명을 생성하기 위해 인증을 묻는 메시지가 있는 경우 캐시된 자격 증명을 자동으로 갱신하고 옵션 -n("비대화형")은 sudo가 생성되는 것을 방지합니다. 인증 프롬프트와 같은 대화형 프롬프트.

답변3

sudo -nv잘 작동하지만 sudo 오류 및 pam 인증 정보로 시스템 로그를 오염시킵니다. 내 bash 프롬프트에 대한 sudo 권한을 확인해야 했기 때문에 꽤 자주 실행되었고 내 로그는 거의 이 소음으로만 구성되었습니다.

sudo 타임스탬프 파일을 직접 구문 분석하는 것이 가능합니다. 이를 위해 작은 C 유틸리티를 작성했습니다.

/* 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;
}

관련 정보