1 /*
2 * pam_listfile module
3 *
4 * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996.
5 * log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11
6 *
7 * This code began life as the pam_rootok module.
8 */
9
10 #include "config.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <unistd.h>
17 #include <syslog.h>
18 #include <stdarg.h>
19 #include <string.h>
20 #include <pwd.h>
21 #include <grp.h>
22
23 #ifdef PAM_DEBUG
24 #include <assert.h>
25 #endif
26
27 #include <security/pam_modules.h>
28 #include <security/_pam_macros.h>
29 #include <security/pam_modutil.h>
30 #include <security/pam_ext.h>
31 #include "pam_inline.h"
32
33 /* --- authentication management functions (only) --- */
34
35 /* Extended Items that are not directly available via pam_get_item() */
36 #define EI_GROUP (1 << 0)
37 #define EI_SHELL (1 << 1)
38
39 /* Constants for apply= parameter */
40 #define APPLY_TYPE_NULL 0
41 #define APPLY_TYPE_NONE 1
42 #define APPLY_TYPE_USER 2
43 #define APPLY_TYPE_GROUP 3
44
45 #define LESSER(a, b) ((a) < (b) ? (a) : (b))
46
47 int
48 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
49 int argc, const char **argv)
50 {
51 int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2, quiet=0;
52 const void *void_citemp;
53 const char *citemp;
54 char *ifname=NULL;
55 char aline[256];
56 char mybuf[256],myval[256],apply_val[256];
57 struct stat fileinfo;
58 FILE *inf;
59 int apply_type;
60
61 /* Stuff for "extended" items */
62 struct passwd *userinfo;
63
64 apply_type=APPLY_TYPE_NULL;
65 apply_val[0] = '\0';
66
67 for(i=0; i < argc; i++) {
68 {
69 const char *junk;
70
71 /* option quiet has no value */
72 if(!strcmp(argv[i],"quiet")) {
73 quiet = 1;
74 continue;
75 }
76
77 memset(mybuf,'\0',sizeof(mybuf));
78 memset(myval,'\0',sizeof(myval));
79 junk = strchr(argv[i], '=');
80 if((junk == NULL) || (junk - argv[i]) >= (int) sizeof(mybuf)) {
81 pam_syslog(pamh,LOG_ERR, "Bad option: \"%s\"",
82 argv[i]);
83 continue;
84 }
85 strncpy(mybuf, argv[i],
86 LESSER(junk - argv[i], (int)sizeof(mybuf) - 1));
87 strncpy(myval, junk + 1, sizeof(myval) - 1);
88 }
89 if(!strcmp(mybuf,"onerr"))
90 if(!strcmp(myval,"succeed"))
91 onerr = PAM_SUCCESS;
92 else if(!strcmp(myval,"fail"))
93 onerr = PAM_SERVICE_ERR;
94 else {
95 if (ifname) free (ifname);
96 return PAM_SERVICE_ERR;
97 }
98 else if(!strcmp(mybuf,"sense"))
99 if(!strcmp(myval,"allow"))
100 sense=0;
101 else if(!strcmp(myval,"deny"))
102 sense=1;
103 else {
104 if (ifname) free (ifname);
105 return onerr;
106 }
107 else if(!strcmp(mybuf,"file")) {
108 if (ifname) free (ifname);
109 ifname = (char *)malloc(strlen(myval)+1);
110 if (!ifname)
111 return PAM_BUF_ERR;
112 strcpy(ifname,myval);
113 } else if(!strcmp(mybuf,"item"))
114 if(!strcmp(myval,"user"))
115 citem = PAM_USER;
116 else if(!strcmp(myval,"tty"))
117 citem = PAM_TTY;
118 else if(!strcmp(myval,"rhost"))
119 citem = PAM_RHOST;
120 else if(!strcmp(myval,"ruser"))
121 citem = PAM_RUSER;
122 else { /* These items are related to the user, but are not
123 directly gettable with pam_get_item */
124 citem = PAM_USER;
125 if(!strcmp(myval,"group"))
126 extitem = EI_GROUP;
127 else if(!strcmp(myval,"shell"))
128 extitem = EI_SHELL;
129 else
130 citem = 0;
131 } else if(!strcmp(mybuf,"apply")) {
132 apply_type=APPLY_TYPE_NONE;
133 if (myval[0]=='@') {
134 apply_type=APPLY_TYPE_GROUP;
135 memcpy(apply_val,myval+1,sizeof(myval)-1);
136 } else {
137 apply_type=APPLY_TYPE_USER;
138 memcpy(apply_val,myval,sizeof(myval));
139 }
140 } else {
141 free(ifname);
142 pam_syslog(pamh,LOG_ERR, "Unknown option: %s",mybuf);
143 return onerr;
144 }
145 }
146
147 if(!citem) {
148 pam_syslog(pamh,LOG_ERR,
149 "Unknown item or item not specified");
150 free(ifname);
151 return onerr;
152 } else if(!ifname) {
153 pam_syslog(pamh,LOG_ERR, "List filename not specified");
154 return onerr;
155 } else if(sense == 2) {
156 pam_syslog(pamh,LOG_ERR,
157 "Unknown sense or sense not specified");
158 free(ifname);
159 return onerr;
160 } else if(
161 (apply_type==APPLY_TYPE_NONE) ||
162 ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0'))
163 ) {
164 pam_syslog(pamh,LOG_ERR,
165 "Invalid usage for apply= parameter");
166 free (ifname);
167 return onerr;
168 }
169
170 /* Check if it makes sense to use the apply= parameter */
171 if (apply_type != APPLY_TYPE_NULL) {
172 if((citem==PAM_USER) || (citem==PAM_RUSER)) {
173 pam_syslog(pamh,LOG_WARNING,
174 "Non-sense use for apply= parameter");
175 apply_type=APPLY_TYPE_NULL;
176 }
177 if(extitem && (extitem==EI_GROUP)) {
178 pam_syslog(pamh,LOG_WARNING,
179 "Non-sense use for apply= parameter");
180 apply_type=APPLY_TYPE_NULL;
181 }
182 }
183
184 /* Short-circuit - test if this session apply for this user */
185 {
186 const char *user_name;
187 int rval;
188
189 rval=pam_get_user(pamh,&user_name,NULL);
190 if(rval==PAM_SUCCESS && user_name[0]) {
191 /* Got it ? Valid ? */
192 if(apply_type==APPLY_TYPE_USER) {
193 if(strcmp(user_name, apply_val)) {
194 /* Does not apply to this user */
195 #ifdef PAM_DEBUG
196 pam_syslog(pamh,LOG_DEBUG,
197 "don't apply: apply=%s, user=%s",
198 apply_val,user_name);
199 #endif /* PAM_DEBUG */
200 free(ifname);
201 return PAM_IGNORE;
202 }
203 } else if(apply_type==APPLY_TYPE_GROUP) {
204 if(!pam_modutil_user_in_group_nam_nam(pamh,user_name,apply_val)) {
205 /* Not a member of apply= group */
206 #ifdef PAM_DEBUG
207 pam_syslog(pamh,LOG_DEBUG,
208
209 "don't apply: %s not a member of group %s",
210 user_name,apply_val);
211 #endif /* PAM_DEBUG */
212 free(ifname);
213 return PAM_IGNORE;
214 }
215 }
216 }
217 }
218
219 retval = pam_get_item(pamh,citem,&void_citemp);
220 citemp = void_citemp;
221 if(retval != PAM_SUCCESS) {
222 free(ifname);
223 return onerr;
224 }
225 if((citem == PAM_USER) && !citemp) {
226 retval = pam_get_user(pamh,&citemp,NULL);
227 if (retval != PAM_SUCCESS) {
228 free(ifname);
229 return PAM_SERVICE_ERR;
230 }
231 }
232 if((citem == PAM_TTY) && citemp) {
233 /* Normalize the TTY name. */
234 const char *str = pam_str_skip_prefix(citemp, "/dev/");
235 if (str != NULL)
236 citemp = str;
237 }
238
239 if(!citemp || (strlen(citemp) == 0)) {
240 free(ifname);
241 /* The item was NULL - we are sure not to match */
242 return sense?PAM_SUCCESS:PAM_AUTH_ERR;
243 }
244
245 if(extitem) {
246 switch(extitem) {
247 case EI_GROUP:
248 /* Just ignore, call pam_modutil_in_group... later */
249 break;
250 case EI_SHELL:
251 /* Assume that we have already gotten PAM_USER in
252 pam_get_item() - a valid assumption since citem
253 gets set to PAM_USER in the extitem switch */
254 userinfo = pam_modutil_getpwnam(pamh, citemp);
255 if (userinfo == NULL) {
256 pam_syslog(pamh, LOG_NOTICE, "getpwnam(%s) failed",
257 citemp);
258 free(ifname);
259 return onerr;
260 }
261 citemp = userinfo->pw_shell;
262 break;
263 default:
264 pam_syslog(pamh,LOG_ERR,
265
266 "Internal weirdness, unknown extended item %d",
267 extitem);
268 free(ifname);
269 return onerr;
270 }
271 }
272 #ifdef PAM_DEBUG
273 pam_syslog(pamh,LOG_INFO,
274
275 "Got file = %s, item = %d, value = %s, sense = %d",
276 ifname, citem, citemp, sense);
277 #endif
278 if(lstat(ifname,&fileinfo)) {
279 if(!quiet)
280 pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname);
281 free(ifname);
282 return onerr;
283 }
284
285 if((fileinfo.st_mode & S_IWOTH)
286 || !S_ISREG(fileinfo.st_mode)) {
287 /* If the file is world writable or is not a
288 normal file, return error */
289 pam_syslog(pamh,LOG_ERR,
290 "%s is either world writable or not a normal file",
291 ifname);
292 free(ifname);
293 return PAM_AUTH_ERR;
294 }
295
296 inf = fopen(ifname,"r");
297 if(inf == NULL) { /* Check that we opened it successfully */
298 if (onerr == PAM_SERVICE_ERR) {
299 /* Only report if it's an error... */
300 pam_syslog(pamh,LOG_ERR, "Error opening %s", ifname);
301 }
302 free(ifname);
303 return onerr;
304 }
305 /* There should be no more errors from here on */
306 retval=PAM_AUTH_ERR;
307 /* This loop assumes that PAM_SUCCESS == 0
308 and PAM_AUTH_ERR != 0 */
309 #ifdef PAM_DEBUG
310 assert(PAM_SUCCESS == 0);
311 assert(PAM_AUTH_ERR != 0);
312 #endif
313 while((fgets(aline,sizeof(aline),inf) != NULL)
314 && retval) {
315 const char *a = aline;
316
317 if(strlen(aline) == 0)
318 continue;
319 if(aline[strlen(aline) - 1] == '\n')
320 aline[strlen(aline) - 1] = '\0';
321 if(strlen(aline) == 0)
322 continue;
323 if(aline[strlen(aline) - 1] == '\r')
324 aline[strlen(aline) - 1] = '\0';
325 if(citem == PAM_TTY) {
326 const char *str = pam_str_skip_prefix(a, "/dev/");
327 if (str != NULL)
328 a = str;
329 }
330 if (extitem == EI_GROUP) {
331 retval = !pam_modutil_user_in_group_nam_nam(pamh,
332 citemp, aline);
333 } else {
334 retval = strcmp(a, citemp);
335 }
336 }
337
338 fclose(inf);
339 free(ifname);
340 if ((sense && retval) || (!sense && !retval)) {
341 #ifdef PAM_DEBUG
342 pam_syslog(pamh,LOG_INFO,
343 "Returning PAM_SUCCESS, retval = %d", retval);
344 #endif
345 return PAM_SUCCESS;
346 }
347 else {
348 const void *service;
349 const char *user_name;
350 #ifdef PAM_DEBUG
351 pam_syslog(pamh,LOG_INFO,
352 "Returning PAM_AUTH_ERR, retval = %d", retval);
353 #endif
354 (void) pam_get_item(pamh, PAM_SERVICE, &service);
355 (void) pam_get_user(pamh, &user_name, NULL);
356 if (!quiet)
357 pam_syslog (pamh, LOG_NOTICE, "Refused user %s for service %s",
358 user_name, (const char *)service);
359 return PAM_AUTH_ERR;
360 }
361 }
362
363 int
364 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
365 int argc UNUSED, const char **argv UNUSED)
366 {
367 return PAM_SUCCESS;
368 }
369
370 int
371 pam_sm_acct_mgmt (pam_handle_t *pamh, int flags,
372 int argc, const char **argv)
373 {
374 return pam_sm_authenticate(pamh, flags, argc, argv);
375 }
376
377 int
378 pam_sm_open_session (pam_handle_t *pamh, int flags,
379 int argc, const char **argv)
380 {
381 return pam_sm_authenticate(pamh, flags, argc, argv);
382 }
383
384 int
385 pam_sm_close_session (pam_handle_t *pamh, int flags,
386 int argc, const char **argv)
387 {
388 return pam_sm_authenticate(pamh, flags, argc, argv);
389 }
390
391 int
392 pam_sm_chauthtok (pam_handle_t *pamh, int flags,
393 int argc, const char **argv)
394 {
395 return pam_sm_authenticate(pamh, flags, argc, argv);
396 }