Bagaimana saya mengetahui jika hak istimewa sudoer saya habis?

20

Saya sedang mengerjakan skrip yang menjalankan perintah sebagai sudo dan menggemakan satu baris teks SAJA jika hak sudo saya telah habis, jadi hanya jika menjalankan perintah dengan sudo akan meminta pengguna saya (bukan root) untuk mengetikkan kata sandinya lagi.

Bagaimana saya memverifikasi itu? Ingatlah bahwa $(id -u)bahkan ketika berjalan sebagai sudo akan mengembalikan id pengguna saya saat ini sehingga tidak dapat diperiksa untuk mencocokkannya dengan 0 ...

Saya membutuhkan metode yang akan memeriksa ini dengan tenang.

TonyMorello
sumber

Jawaban:

28

Gunakan opsi -nuntuk memeriksa apakah Anda masih memiliki hak istimewa; dari man sudo:

-n , --non-interaktif

Hindari meminta pengguna untuk memberi masukan apa pun. Jika kata sandi diperlukan untuk menjalankan perintah, sudo akan menampilkan pesan kesalahan dan keluar.

Sebagai contoh,

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

Ketahuilah bahwa ada hak istimewa untuk kedaluwarsa antara memeriksa dengan sudo -n truedan benar-benar menggunakannya. Anda mungkin ingin mencoba secara langsung dengan sudo -n command...dan jika gagal menampilkan pesan dan mungkin mencoba lagi berjalan secara sudointeraktif.

Sunting: Lihat juga komentar ruakh di bawah ini.

AlexP
sumber
Terima kasih, saya sudah mencoba yang serupa sebelumnya, tetapi saya tidak bisa membuatnya bekerja seperti yang saya inginkan.
TonyMorello
3
Re: "Ketahuilah bahwa ada kemungkinan hak istimewa kedaluwarsa antara memeriksa dengan sudo -n truedan benar-benar menggunakannya": Dokumentasi agak kabur tentang hal ini, tapi saya pikir menjalankan sudoperintah, bahkan hanya sudo -n true, akan mengatur ulang batas waktu jam. Either way, -vsecara eksplisit didokumentasikan melakukan hal itu, dan sudo -n -vmungkin lebih tepat daripada sudo -n trueuntuk tujuan ini pula.
ruakh
Sementara ini akan memang diam, itu akan log kesalahan untuk jurnal sistem jika tidak ada hak istimewa: hostname sudo[8870]: username : a password is required ; TTY=pts/0 ; PWD=/home/username ; USER=root ; COMMAND=/usr/bin/true. Jika Anda menggunakannya dalam bash prompt, misalnya, itu akan menghasilkan banyak pesan kesalahan.
Rogach
Dan jika ada hak istimewa, akan ada debug logging dari pam_unix dan eksekusi perintah sudo.
Rogach
8

Menjalankan:

sudo -nv

Jika hak akses sudo Anda telah habis, ini akan keluar dengan kode keluar 1 dan output:

sudo: a password is required

Jika Anda memiliki kredensial cache yang valid, perintah ini akan berhasil dan tidak menghasilkan apa-apa.

Jadi, untuk menyatukan semuanya, inilah scriptlet yang akan secara diam - diam memeriksa apakah Anda memiliki kredensial cache yang valid:

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

Seperti jawaban / komentar lain yang disebutkan, -vopsi ("validasi") untuk sudo diam-diam memperbarui kredensial yang di-cache jika ada atau yang lain diminta untuk otentikasi untuk menghasilkan kredensial yang di-cache, dan -nopsi ("non-interaktif") mencegah sudo dari menghasilkan setiap permintaan interaktif, seperti permintaan otentikasi.

jayhendren
sumber
Ini adalah solusi yang bagus ... Saya sudah mencobanya sebelumnya tetapi jawaban AlexP melakukan apa yang saya butuhkan ... Saya pikir saya salah paham parameter -n sebelumnya
TonyMorello
1

sudo -nvberfungsi dengan baik, tetapi mencemari log sistem dengan kesalahan sudo dan info otentikasi pam. Saya perlu memeriksa hak sudo untuk bash prompt saya, jadi itu dieksekusi cukup sering dan log saya hanya terdiri dari suara ini.

Dimungkinkan untuk mengurai file stempel waktu sudo secara langsung - Saya menulis util C kecil untuk itu:

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