1
0
Fork 0
pam/modules/pam_shells/pam_shells.c
Daniel Baumann 82f0236850
Adding upstream version 1.7.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 06:53:43 +02:00

177 lines
3.9 KiB
C

/*
* pam_shells module
*
* by Erik Troan <ewt@redhat.com>, Red Hat Software.
* August 5, 1996.
* This code shamelessly ripped from the pam_securetty module.
*/
#include "config.h"
#include <limits.h>
#include <pwd.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <syslog.h>
#include <unistd.h>
#if defined (USE_ECONF) && defined (VENDORDIR)
#include "pam_econf.h"
#endif
#include <security/pam_modules.h>
#include <security/pam_modutil.h>
#include <security/pam_ext.h>
#define SHELL_FILE "/etc/shells"
#define SHELLS "shells"
#define ETCDIR "/etc"
#define DEFAULT_SHELL "/bin/sh"
static bool check_file(const char *filename, const void *pamh)
{
struct stat sb;
if (stat(filename, &sb)) {
pam_syslog(pamh, LOG_ERR, "Cannot stat %s: %m", filename);
return false; /* must have /etc/shells */
}
if ((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) {
pam_syslog(pamh, LOG_ERR,
"%s is either world writable or not a normal file",
filename);
return false;
}
return true;
}
static int perform_check(pam_handle_t *pamh)
{
int retval = PAM_AUTH_ERR;
const char *userName;
const char *userShell;
struct passwd * pw;
retval = pam_get_user(pamh, &userName, NULL);
if (retval != PAM_SUCCESS) {
return PAM_SERVICE_ERR;
}
pw = pam_modutil_getpwnam(pamh, userName);
if (pw == NULL) {
return PAM_USER_UNKNOWN;
}
if (pw->pw_shell == NULL) {
/* TODO: when does this happen? I would join it with
* the case userShell[0] == '\0' below.
*
* For now, keep the existing stricter behaviour
*/
return PAM_AUTH_ERR;
}
userShell = pw->pw_shell;
if (userShell[0] == '\0')
userShell = DEFAULT_SHELL;
#if defined (USE_ECONF) && defined (VENDORDIR)
size_t size = 0;
econf_err error;
char **keys;
econf_file *key_file = NULL;
error = pam_econf_readconfig(&key_file,
VENDORDIR,
ETCDIR,
SHELLS,
NULL,
"", /* key only */
"#", /* comment */
check_file, pamh);
if (error != ECONF_SUCCESS) {
pam_syslog(pamh, LOG_ERR,
"Cannot parse shell files: %s",
econf_errString(error));
return PAM_AUTH_ERR;
}
error = econf_getKeys(key_file, NULL, &size, &keys);
if (error) {
pam_syslog(pamh, LOG_ERR,
"Cannot evaluate entries in shell files: %s",
econf_errString(error));
econf_free (key_file);
return PAM_AUTH_ERR;
}
retval = 1;
for (size_t i = 0; i < size; i++) {
retval = strcmp(keys[i], userShell);
if (!retval)
break;
}
econf_free (keys);
econf_free (key_file);
#else
FILE *shellFile;
char *p = NULL;
size_t n = 0;
if (!check_file(SHELL_FILE, pamh))
return PAM_AUTH_ERR;
shellFile = fopen(SHELL_FILE,"r");
if (shellFile == NULL) { /* Check that we opened it successfully */
pam_syslog(pamh, LOG_ERR, "Error opening %s: %m", SHELL_FILE);
return PAM_SERVICE_ERR;
}
retval = 1;
while (retval && getline(&p, &n, shellFile) != -1) {
p[strcspn(p, "\n")] = '\0';
if (p[0] != '/') {
continue;
}
retval = strcmp(p, userShell);
}
free(p);
fclose(shellFile);
#endif
if (retval) {
pam_syslog(pamh, LOG_NOTICE, "User has an invalid shell '%s'", userShell);
return PAM_AUTH_ERR;
} else {
return PAM_SUCCESS;
}
}
/* --- authentication management functions (only) --- */
int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return perform_check(pamh);
}
int pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return PAM_SUCCESS;
}
/* --- account management functions (only) --- */
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
int argc UNUSED, const char **argv UNUSED)
{
return perform_check(pamh);
}
/* end of module definition */