You can write a small PAM module to accept several different (hardcoded) passwords for an account.
Here's an example source code for such a module:
// Compile with:
// gcc -fPIC -shared -o pam_multipass.so pam_multipass.c -lpam -lssl -lcrypto
// Install into /lib/security/ (or other location, depending on your distribution):
// sudo install --mode=0755 --owner=root --group=root pam_multipass.so /lib/security/pam_multipass.so
#define _GNU_SOURCE
#include <stdio.h>
#include <security/pam_modules.h>
#include <security/pam_ext.h>
#include <string.h>
#include <openssl/sha.h>
#define USERNAME "username"
#define PASSWORD_HASH_1 "xxxxxxxx"
#define PASSWORD_HASH_2 "xxxxxxxx"
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) {
const char *username;
char *password;
unsigned char result[SHA256_DIGEST_LENGTH];
char hexstring[65];
// Get the username
pam_get_user(pamh, &username, NULL);
if (strcmp(username, USERNAME) != 0) {
return PAM_IGNORE; // Not the user we're interested in
}
// Prompt for password
if (pam_prompt(pamh, PAM_PROMPT_ECHO_OFF, &password, "%s", "Password: ") != PAM_SUCCESS) {
fprintf(stderr, "pam_multipass pam_prompt failed\n");
return PAM_IGNORE;
}
if (pam_set_item(pamh, PAM_AUTHTOK, password) != PAM_SUCCESS) {
fprintf(stderr, "pam_multipass failed to set PAM_AUTHTOK\n");
}
SHA256((unsigned char *) password, strlen(password), result);
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(hexstring + (i * 2), "%02x", result[i]);
}
// Compare with expected hash
if (
strcmp(hexstring, PASSWORD_HASH_1) == 0
|| strcmp(hexstring, PASSWORD_HASH_2) == 0
) {
return PAM_SUCCESS;
} else {
return PAM_IGNORE; // Allow other modules to authenticate
}
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) { return PAM_IGNORE; }
You'll need to add the module to the PAM configuration, and that might be tricky. I'll give an example for Arch Linux distribution, adapt to other distributions as needed:
# in /etc/pam.d/system-auth
auth required pam_faillock.so preauth
auth [success=3 default=ignore] pam_multipass.so # <--- our module
auth [success=2 default=ignore] pam_unix.so try_first_pass nullok
-auth [success=1 default=ignore] pam_systemd_home.so
auth [default=die] pam_faillock.so authfail
auth optional pam_permit.so
auth required pam_env.so
auth required pam_faillock.so authsucc
But in any case, be extra careful - don't do any such thing if you don't thoroughly understand everything that you are doing (e.g., why is there success=3
directive in PAM config?).
sudo
to allow user1 to run commands as user2. (sudo
isn't just for running commands as root; it can run commands as any user.)