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


20

sudo로 명령을 실행하고 sudo 권한이 시간 초과 된 경우에만 텍스트 줄을 표시하는 스크립트를 작성 중이므로 sudo로 명령을 실행하면 root가 아닌 사용자가 암호를 다시 입력해야합니다.

이를 어떻게 확인합니까? 염두 $(id -u)내 현재 사용자 ID를 반환합니다 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하고 실제로 사용하는 사이에 권한이 만료 될 수 있다는 점에 유의하십시오." :이 시점에서 설명서가 약간 모호하지만 명령 을 실행 해도 시간 초과가 재설정 된다고 생각 합니다. 시계. 어느 쪽이든, 그렇게 명시 적으로 문서화되어 있으며 어쨌든이 목적 보다 더 적합 할 것 입니다. sudosudo -n true-vsudo -n -vsudo -n true
ruakh

이것은 실제로는 자동이지만 권한이 없으면 시스템 저널에 오류를 기록합니다 hostname sudo[8870]: username : a password is required ; TTY=pts/0 ; PWD=/home/username ; USER=root ; COMMAND=/usr/bin/true. 예를 들어 bash 프롬프트에서 사용하면 많은 오류 메시지가 나타납니다.
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 오류 및 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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.