¿Cómo puedo saber si mi privilegio sudoer expiró?

¿Cómo puedo saber si mi privilegio sudoer expiró?

Estoy trabajando en un script que ejecuta un comando como sudo y repite una línea de texto SÓLO si mis privilegios de sudo han expirado, por lo que solo si ejecutar un comando con sudo requeriría que mi usuario (no root) escriba su contraseña nuevamente.

¿Cómo verifico eso? Tenga en cuenta que $(id -u)incluso cuando se ejecuta como sudo devolverá mi identificación de usuario actual, por lo que no se puede verificar para que coincida con 0...

Necesito un método que pueda comprobar esto silenciosamente.

Respuesta1

Utilice la opción -npara comprobar si todavía tiene privilegios; de man sudo:

-norte,--no interactivo

Evite solicitar al usuario datos de cualquier tipo. Si se requiere una contraseña para ejecutar el comando, sudo mostrará un mensaje de error y saldrá.

Por ejemplo,

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

Tenga en cuenta que es posible que los privilegios caduquen entre la verificación sudo -n truey el uso. Es posible que desee intentarlo directamente sudo -n command...y, en caso de falla, mostrar un mensaje y posiblemente volver a intentar ejecutar sudode forma interactiva.

Editar: consulte también el comentario de ruakh a continuación.

Respuesta2

Correr:

sudo -nv

Si sus privilegios de sudo han expirado, esto saldrá con un código de salida de 1 y generará:

sudo: a password is required

Si tiene credenciales válidas en caché, este comando se ejecutará correctamente y no generará nada.

Entonces, para ponerlo todo junto, aquí hay un scriptlet quesilenciosamentecompruebe si tiene credenciales válidas en caché:

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

Como se mencionaron otras respuestas/comentarios, la -vopción ("validar") para sudo renueva silenciosamente las credenciales almacenadas en caché si hay alguna solicitud de autenticación para generar credenciales almacenadas en caché, y la -nopción ("no interactiva") evita que sudo genere cualquier mensaje interactivo, como el mensaje de autenticación.

Respuesta3

sudo -nvfunciona bien, pero contamina los registros del sistema con errores de sudo e información de autenticación pam. Necesitaba verificar los privilegios de sudo para mi indicador de bash, por lo que se ejecutaba con bastante frecuencia y mis registros consistían casi únicamente en este ruido.

Es posible analizar el archivo de marca de tiempo sudo directamente; escribí una pequeña utilidad C para ello:

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

información relacionada