1 /*
2 * pam_shells module
3 *
4 * by Erik Troan <ewt@redhat.com>, Red Hat Software.
5 * August 5, 1996.
6 * This code shamelessly ripped from the pam_securetty module.
7 */
8
9 #include "config.h"
10
11 #include <pwd.h>
12 #include <stdarg.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdbool.h>
17 #include <sys/stat.h>
18 #include <syslog.h>
19 #include <unistd.h>
20 #if defined (USE_ECONF) && defined (VENDORDIR)
21 #include <libeconf.h>
22 #endif
23
24 #include <security/pam_modules.h>
25 #include <security/pam_modutil.h>
26 #include <security/pam_ext.h>
27
28 #define SHELL_FILE "/etc/shells"
29 #define SHELLS "shells"
30 #define ETCDIR "/etc"
31 #define DEFAULT_SHELL "/bin/sh"
32
33 static bool check_file(const char *filename, const void *pamh)
34 {
35 struct stat sb;
36
37 if (stat(filename, &sb)) {
38 pam_syslog(pamh, LOG_ERR, "Cannot stat %s: %m", filename);
39 return false; /* must have /etc/shells */
40 }
41
42 if ((sb.st_mode & S_IWOTH) || !S_ISREG(sb.st_mode)) {
43 pam_syslog(pamh, LOG_ERR,
44 "%s is either world writable or not a normal file",
45 filename);
46 return false;
47 }
48 return true;
49 }
50
51 static int perform_check(pam_handle_t *pamh)
52 {
53 int retval = PAM_AUTH_ERR;
54 const char *userName;
55 const char *userShell;
56 struct passwd * pw;
57
58 retval = pam_get_user(pamh, &userName, NULL);
59 if (retval != PAM_SUCCESS) {
60 return PAM_SERVICE_ERR;
61 }
62
63 pw = pam_modutil_getpwnam(pamh, userName);
64 if (pw == NULL || pw->pw_shell == NULL) {
65 return PAM_AUTH_ERR; /* user doesn't exist */
66 }
67 userShell = pw->pw_shell;
68 if (userShell[0] == '\0')
69 userShell = DEFAULT_SHELL;
70
71 #if defined (USE_ECONF) && defined (VENDORDIR)
72 size_t size = 0;
73 econf_err error;
74 char **keys;
75 econf_file *key_file;
76
77 error = econf_readDirsWithCallback(&key_file,
78 VENDORDIR,
79 ETCDIR,
80 SHELLS,
81 NULL,
82 "", /* key only */
83 "#", /* comment */
84 check_file, pamh);
85 if (error) {
86 pam_syslog(pamh, LOG_ERR,
87 "Cannot parse shell files: %s",
88 econf_errString(error));
89 return PAM_AUTH_ERR;
90 }
91
92 error = econf_getKeys(key_file, NULL, &size, &keys);
93 if (error) {
94 pam_syslog(pamh, LOG_ERR,
95 "Cannot evaluate entries in shell files: %s",
96 econf_errString(error));
97 econf_free (key_file);
98 return PAM_AUTH_ERR;
99 }
100
101 retval = 1;
102 for (size_t i = 0; i < size; i++) {
103 retval = strcmp(keys[i], userShell);
104 if (!retval)
105 break;
106 }
107 econf_free (key_file);
108 #else
109 char shellFileLine[256];
110 FILE * shellFile;
111
112 if (!check_file(SHELL_FILE, pamh))
113 return PAM_AUTH_ERR;
114
115 shellFile = fopen(SHELL_FILE,"r");
116 if (shellFile == NULL) { /* Check that we opened it successfully */
117 pam_syslog(pamh, LOG_ERR, "Error opening %s: %m", SHELL_FILE);
118 return PAM_SERVICE_ERR;
119 }
120
121 retval = 1;
122
123 while(retval && (fgets(shellFileLine, 255, shellFile) != NULL)) {
124 if (shellFileLine[strlen(shellFileLine) - 1] == '\n')
125 shellFileLine[strlen(shellFileLine) - 1] = '\0';
126 retval = strcmp(shellFileLine, userShell);
127 }
128
129 fclose(shellFile);
130 #endif
131
132 if (retval) {
133 return PAM_AUTH_ERR;
134 } else {
135 return PAM_SUCCESS;
136 }
137 }
138
139 /* --- authentication management functions (only) --- */
140
141 int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
142 int argc UNUSED, const char **argv UNUSED)
143 {
144 return perform_check(pamh);
145 }
146
147 int pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
148 int argc UNUSED, const char **argv UNUSED)
149 {
150 return PAM_SUCCESS;
151 }
152
153 /* --- account management functions (only) --- */
154
155 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
156 int argc UNUSED, const char **argv UNUSED)
157 {
158 return perform_check(pamh);
159 }
160
161 /* end of module definition */