7 * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996.
8 * log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11
10 * This code began life as the pam_rootok module.
13 #include <security/_pam_aconf.h>
17 #include <sys/types.h>
31 * here, we make a definition for the externally accessible function
32 * in this file (this definition is required for static a module
33 * but strongly encouraged generally) it is used to instruct the
34 * modules include file to define the function prototypes.
39 #include <security/pam_modules.h>
40 #include <security/_pam_macros.h>
44 #define LOCAL_LOG_PREFIX "PAM-listfile: "
46 static void _pam_log(int err, const char *format, ...)
50 va_start(args, format);
51 vsyslog(LOG_AUTH | err, format, args);
55 /* checks if a user is on a list of members */
56 static int is_on_list(char * const *list, const char *member)
59 if (strcmp(*list, member) == 0)
66 /* Checks if a user is a member of a group */
67 static int is_on_group(const char *user_name, const char *group_name)
70 struct group *grp, *pgrp;
71 char uname[BUFSIZ], gname[BUFSIZ];
73 if (!strlen(user_name))
75 if (!strlen(group_name))
77 bzero(uname, sizeof(uname));
78 strncpy(uname, user_name, BUFSIZ-1);
79 bzero(gname, sizeof(gname));
80 strncpy(gname, group_name, BUFSIZ-1);
83 pwd = getpwnam(uname);
88 /* the info about this group */
90 grp = getgrnam(gname);
95 /* first check: is a member of the group_name group ? */
96 if (is_on_list(grp->gr_mem, uname))
99 /* next check: user primary group is group_name ? */
101 pgrp = getgrgid(pwd->pw_gid);
105 if (!strcmp(pgrp->gr_name, gname))
111 /* --- authentication management functions (only) --- */
113 /* Extended Items that are not directly available via pam_get_item() */
114 #define EI_GROUP (1 << 0)
115 #define EI_SHELL (1 << 1)
117 /* Constants for apply= parameter */
118 #define APPLY_TYPE_NULL 0
119 #define APPLY_TYPE_NONE 1
120 #define APPLY_TYPE_USER 2
121 #define APPLY_TYPE_GROUP 3
124 int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
126 int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2;
130 char mybuf[256],myval[256];
131 struct stat fileinfo;
136 /* Stuff for "extended" items */
137 struct passwd *userinfo;
138 struct group *grpinfo;
139 char *itemlist[256]; /* Maximum of 256 items */
143 apply_type=APPLY_TYPE_NULL;
144 memset(apply_val,0,sizeof(apply_val));
146 for(i=0; i < argc; i++) {
149 junk = (char *) malloc(strlen(argv[i])+1);
153 strcpy(junk,argv[i]);
154 strncpy(mybuf,strtok(junk,"="),255);
155 strncpy(myval,strtok(NULL,"="),255);
158 if(!strcmp(mybuf,"onerr"))
159 if(!strcmp(myval,"succeed"))
161 else if(!strcmp(myval,"fail"))
162 onerr = PAM_SERVICE_ERR;
164 return PAM_SERVICE_ERR;
165 else if(!strcmp(mybuf,"sense"))
166 if(!strcmp(myval,"allow"))
168 else if(!strcmp(myval,"deny"))
172 else if(!strcmp(mybuf,"file")) {
173 ifname = (char *)malloc(strlen(myval)+1);
174 strcpy(ifname,myval);
175 } else if(!strcmp(mybuf,"item"))
176 if(!strcmp(myval,"user"))
178 else if(!strcmp(myval,"tty"))
180 else if(!strcmp(myval,"rhost"))
182 else if(!strcmp(myval,"ruser"))
184 else { /* These items are related to the user, but are not
185 directly gettable with pam_get_item */
187 if(!strcmp(myval,"group"))
189 else if(!strcmp(myval,"shell"))
193 } else if(!strcmp(mybuf,"apply")) {
194 apply_type=APPLY_TYPE_NONE;
196 apply_type=APPLY_TYPE_GROUP;
197 strncpy(apply_val,myval+1,sizeof(apply_val)-1);
199 apply_type=APPLY_TYPE_USER;
200 strncpy(apply_val,myval,sizeof(apply_val)-1);
203 _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Unknown option: %s",mybuf);
210 LOCAL_LOG_PREFIX "Unknown item or item not specified");
213 _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "List filename not specified");
215 } else if(sense == 2) {
217 LOCAL_LOG_PREFIX "Unknown sense or sense not specified");
220 (apply_type==APPLY_TYPE_NONE) ||
221 ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0'))
224 LOCAL_LOG_PREFIX "Invalid usage for apply= parameter");
228 /* Check if it makes sense to use the apply= parameter */
229 if (apply_type != APPLY_TYPE_NULL) {
230 if((citem==PAM_USER) || (citem==PAM_RUSER)) {
231 _pam_log(LOG_WARNING,
232 LOCAL_LOG_PREFIX "Non-sense use for apply= parameter");
233 apply_type=APPLY_TYPE_NULL;
235 if(extitem && (extitem==EI_GROUP)) {
236 _pam_log(LOG_WARNING,
237 LOCAL_LOG_PREFIX "Non-sense use for apply= parameter");
238 apply_type=APPLY_TYPE_NULL;
242 /* Short-circuit - test if this session apply for this user */
244 const char *user_name;
247 rval=pam_get_user(pamh,&user_name,NULL);
248 if((rval==PAM_SUCCESS) && user_name[0]) {
249 /* Got it ? Valid ? */
250 if(apply_type==APPLY_TYPE_USER) {
251 if(strcmp(user_name, apply_val)) {
252 /* Does not apply to this user */
255 LOCAL_LOG_PREFIX "don't apply: apply=%s, user=%s",
256 apply_val,user_name);
260 } else if(apply_type==APPLY_TYPE_GROUP) {
261 if(!is_on_group(user_name,apply_val)) {
262 /* Not a member of apply= group */
266 "don't apply: %s not a member of group %s",
267 user_name,apply_val);
275 retval = pam_get_item(pamh,citem,(const void **)&citemp);
276 if(retval != PAM_SUCCESS) {
279 if((citem == PAM_USER) && !citemp) {
280 pam_get_user(pamh,&citemp,NULL);
281 if (retval != PAM_SUCCESS)
282 return PAM_SERVICE_ERR;
285 if(!citemp || (strlen(citemp) <= 0)) {
286 /* The item was NULL - we are sure not to match */
287 return sense?PAM_SUCCESS:PAM_AUTH_ERR;
294 userinfo = getpwnam(citemp);
296 grpinfo = getgrgid(userinfo->pw_gid);
297 itemlist[0] = x_strdup(grpinfo->gr_name);
299 for (i=1; (i < sizeof(itemlist)/sizeof(itemlist[0])-1) &&
300 (grpinfo = getgrent()); ) {
301 if (is_on_list(grpinfo->gr_mem,citemp)) {
302 itemlist[i++] = x_strdup(grpinfo->gr_name);
311 userinfo = getpwnam(citemp); /* Assume that we have already gotten
312 PAM_USER in pam_get_item() - a valid
313 assumption since citem gets set to
314 PAM_USER in the extitem switch */
315 citemp = userinfo->pw_shell;
321 "Internal weirdness, unknown extended item %d",
329 "Got file = %s, item = %d, value = %s, sense = %d",
330 ifname, citem, citemp, sense);
332 if(lstat(ifname,&fileinfo)) {
333 _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Couldn't open %s",ifname);
337 if((fileinfo.st_mode & S_IWOTH)
338 || !S_ISREG(fileinfo.st_mode)) {
339 /* If the file is world writable or is not a
340 normal file, return error */
341 _pam_log(LOG_ERR,LOCAL_LOG_PREFIX
342 "%s is either world writable or not a normal file",
347 inf = fopen(ifname,"r");
348 if(inf == NULL) { /* Check that we opened it successfully */
349 if (onerr == PAM_SERVICE_ERR) {
350 /* Only report if it's an error... */
351 _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Error opening %s", ifname);
355 /* There should be no more errors from here on */
357 /* This loop assumes that PAM_SUCCESS == 0
358 and PAM_AUTH_ERR != 0 */
360 assert(PAM_SUCCESS == 0);
361 assert(PAM_AUTH_ERR != 0);
363 if(extitem == EI_GROUP) {
364 while((fgets(aline,255,inf) != NULL)
366 if(aline[strlen(aline) - 1] == '\n')
367 aline[strlen(aline) - 1] = '\0';
368 for(i=0;itemlist[i];)
369 /* If any of the items match, strcmp() == 0, and we get out
371 retval = (strcmp(aline,itemlist[i++]) && retval);
373 for(i=0;itemlist[i];)
376 while((fgets(aline,255,inf) != NULL)
378 if(aline[strlen(aline) - 1] == '\n')
379 aline[strlen(aline) - 1] = '\0';
380 retval = strcmp(aline,citemp);
385 if ((sense && retval) || (!sense && !retval)) {
387 _pam_log(LOG_INFO, LOCAL_LOG_PREFIX
388 "Returning PAM_SUCCESS, retval = %d", retval);
393 const char *service, *user_name;
395 _pam_log(LOG_INFO,LOCAL_LOG_PREFIX
396 "Returning PAM_AUTH_ERR, retval = %d", retval);
398 (void) pam_get_item(pamh, PAM_SERVICE, (const void **)&service);
399 (void) pam_get_user(pamh, &user_name, NULL);
400 _pam_log(LOG_ALERT,LOCAL_LOG_PREFIX "Refused user %s for service %s",
407 int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
414 /* static module data */
416 struct pam_module _pam_listfile_modstruct = {
428 /* end of module definition */