]> granicus.if.org Git - linux-pam/blob - modules/pam_listfile/pam_listfile.c
Relevant BUGIDs: 124923
[linux-pam] / modules / pam_listfile / pam_listfile.c
1 /*
2  * $Id$
3  *
4  */
5
6 /*
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
9  *
10  * This code began life as the pam_rootok module.
11  */
12
13 #include <security/_pam_aconf.h>
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <syslog.h>
21 #include <stdarg.h>
22 #include <string.h>
23 #include <pwd.h>
24 #include <grp.h>
25
26 #ifdef DEBUG
27 #include <assert.h>
28 #endif
29
30 /*
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.
35  */
36
37 #define PAM_SM_AUTH
38
39 #include <security/pam_modules.h>
40 #include <security/_pam_macros.h>
41
42 /* some syslogging */
43
44 #define LOCAL_LOG_PREFIX "PAM-listfile: "
45
46 static void _pam_log(int err, const char *format, ...)
47 {
48     va_list args;
49  
50     va_start(args, format);
51     vsyslog(LOG_AUTH | err, format, args);
52     va_end(args);
53 }
54
55 /* checks if a user is on a list of members */
56 static int is_on_list(char * const *list, const char *member)
57 {
58     while (*list) {
59         if (strcmp(*list, member) == 0)
60             return 1;
61         list++;
62     }
63     return 0;
64 }
65
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)
68 {
69     struct passwd *pwd;
70     struct group *grp, *pgrp;
71     char uname[BUFSIZ], gname[BUFSIZ];
72     
73     if (!strlen(user_name))
74         return 0;
75     if (!strlen(group_name))
76         return 0;
77     bzero(uname, sizeof(uname));
78     strncpy(uname, user_name, BUFSIZ-1);
79     bzero(gname, sizeof(gname));
80     strncpy(gname, group_name, BUFSIZ-1);
81         
82     setpwent();
83     pwd = getpwnam(uname);
84     endpwent();
85     if (!pwd)
86         return 0;
87
88     /* the info about this group */
89     setgrent();
90     grp = getgrnam(gname);
91     endgrent();
92     if (!grp)
93         return 0;
94     
95     /* first check: is a member of the group_name group ? */
96     if (is_on_list(grp->gr_mem, uname))
97         return 1;
98
99     /* next check: user primary group is group_name ? */
100     setgrent();
101     pgrp = getgrgid(pwd->pw_gid);
102     endgrent();
103     if (!pgrp)
104         return 0;
105     if (!strcmp(pgrp->gr_name, gname))
106         return 1;
107         
108     return 0;
109 }
110
111 /* --- authentication management functions (only) --- */
112
113 /* Extended Items that are not directly available via pam_get_item() */
114 #define EI_GROUP (1 << 0)
115 #define EI_SHELL (1 << 1)
116
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
122
123 PAM_EXTERN
124 int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
125 {
126     int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2;
127     const char *citemp;
128     char *ifname=NULL;
129     char aline[256];
130     char mybuf[256],myval[256];
131     struct stat fileinfo;
132     FILE *inf;
133     char apply_val[256];
134     int apply_type;
135
136     /* Stuff for "extended" items */
137     struct passwd *userinfo;
138     struct group *grpinfo;
139     char *itemlist[256]; /* Maximum of 256 items */
140
141     D(("called."));
142
143     apply_type=APPLY_TYPE_NULL;
144     memset(apply_val,0,sizeof(apply_val));
145
146     for(i=0; i < argc; i++) {
147         {
148             char *junk;
149             junk = (char *) malloc(strlen(argv[i])+1);
150             if (junk == NULL) {
151                 return PAM_BUF_ERR;
152             }
153             strcpy(junk,argv[i]);
154             strncpy(mybuf,strtok(junk,"="),255);
155             strncpy(myval,strtok(NULL,"="),255);
156             free(junk);
157         }
158         if(!strcmp(mybuf,"onerr"))
159             if(!strcmp(myval,"succeed"))
160                 onerr = PAM_SUCCESS;
161             else if(!strcmp(myval,"fail"))
162                 onerr = PAM_SERVICE_ERR;
163             else
164                 return PAM_SERVICE_ERR;
165         else if(!strcmp(mybuf,"sense"))
166             if(!strcmp(myval,"allow"))
167                 sense=0;
168             else if(!strcmp(myval,"deny"))
169                 sense=1;
170             else
171                 return onerr;
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"))
177                 citem = PAM_USER;
178             else if(!strcmp(myval,"tty"))
179                 citem = PAM_TTY;
180             else if(!strcmp(myval,"rhost"))
181                 citem = PAM_RHOST;
182             else if(!strcmp(myval,"ruser"))
183                 citem = PAM_RUSER;
184             else { /* These items are related to the user, but are not
185                       directly gettable with pam_get_item */
186                 citem = PAM_USER;
187                 if(!strcmp(myval,"group"))
188                     extitem = EI_GROUP;
189                 else if(!strcmp(myval,"shell"))
190                     extitem = EI_SHELL;
191                 else
192                     citem = 0;
193             } else if(!strcmp(mybuf,"apply")) {
194                 apply_type=APPLY_TYPE_NONE;
195                 if (myval[0]=='@') {
196                     apply_type=APPLY_TYPE_GROUP;
197                     strncpy(apply_val,myval+1,sizeof(apply_val)-1);
198                 } else {
199                     apply_type=APPLY_TYPE_USER;
200                     strncpy(apply_val,myval,sizeof(apply_val)-1);
201                 }
202             } else {
203                 _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Unknown option: %s",mybuf);
204                 return onerr;
205             }
206     }
207
208     if(!citem) {
209         _pam_log(LOG_ERR,
210                  LOCAL_LOG_PREFIX "Unknown item or item not specified");
211         return onerr;
212     } else if(!ifname) {
213         _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "List filename not specified");
214         return onerr;
215     } else if(sense == 2) {
216         _pam_log(LOG_ERR,
217                  LOCAL_LOG_PREFIX "Unknown sense or sense not specified");
218         return onerr;
219     } else if(
220               (apply_type==APPLY_TYPE_NONE) || 
221               ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0'))
222               ) {
223         _pam_log(LOG_ERR,
224                  LOCAL_LOG_PREFIX "Invalid usage for apply= parameter");
225         return onerr;
226     }
227      
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;
234         }
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;
239         }
240     }
241      
242     /* Short-circuit - test if this session apply for this user */
243     {
244         const char *user_name;
245         int rval;
246        
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 */
253 #ifdef DEBUG
254                     _pam_log(LOG_DEBUG,
255                              LOCAL_LOG_PREFIX "don't apply: apply=%s, user=%s",
256                              apply_val,user_name);
257 #endif /* DEBUG */
258                     return PAM_IGNORE;
259                 }
260             } else if(apply_type==APPLY_TYPE_GROUP) {
261                 if(!is_on_group(user_name,apply_val)) {
262                     /* Not a member of apply= group */
263 #ifdef DEBUG
264                     _pam_log(LOG_DEBUG,
265                              LOCAL_LOG_PREFIX
266                              "don't apply: %s not a member of group %s",
267                              user_name,apply_val);
268 #endif /* DEBUG */
269                     return PAM_IGNORE;
270                 }
271             }
272         }
273     }
274
275     retval = pam_get_item(pamh,citem,(const void **)&citemp);
276     if(retval != PAM_SUCCESS) {
277         return onerr;
278     }
279     if((citem == PAM_USER) && !citemp) {
280         pam_get_user(pamh,&citemp,NULL);
281         if (retval != PAM_SUCCESS)
282             return PAM_SERVICE_ERR;
283     }
284
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;
288     }
289
290     if(extitem) {
291         switch(extitem) {
292             case EI_GROUP:
293                 setpwent();
294                 userinfo = getpwnam(citemp);
295                 setgrent();
296                 grpinfo = getgrgid(userinfo->pw_gid);
297                 itemlist[0] = x_strdup(grpinfo->gr_name);
298                 setgrent();
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);
303                     }
304                 }
305                 itemlist[i] = NULL;
306                 endgrent();
307                 endpwent();
308                 break;
309             case EI_SHELL:
310                 setpwent();
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;
316                 endpwent();
317                 break;
318             default:
319                 _pam_log(LOG_ERR,
320                          LOCAL_LOG_PREFIX
321                          "Internal weirdness, unknown extended item %d",
322                          extitem);
323                 return onerr;
324         }
325     }
326 #ifdef DEBUG
327     _pam_log(LOG_INFO,
328              LOCAL_LOG_PREFIX
329              "Got file = %s, item = %d, value = %s, sense = %d",
330              ifname, citem, citemp, sense);
331 #endif
332     if(lstat(ifname,&fileinfo)) {
333         _pam_log(LOG_ERR,LOCAL_LOG_PREFIX "Couldn't open %s",ifname);
334         return onerr;
335     }
336
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",
343                  ifname);
344         return PAM_AUTH_ERR;
345     }
346
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);
352         }
353         return onerr;
354     }
355     /* There should be no more errors from here on */
356     retval=PAM_AUTH_ERR;
357     /* This loop assumes that PAM_SUCCESS == 0
358        and PAM_AUTH_ERR != 0 */
359 #ifdef DEBUG
360     assert(PAM_SUCCESS == 0);
361     assert(PAM_AUTH_ERR != 0);
362 #endif
363     if(extitem == EI_GROUP) {
364         while((fgets(aline,255,inf) != NULL)
365               && retval) {
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
370                    of this loop */
371                 retval = (strcmp(aline,itemlist[i++]) && retval);
372         }
373         for(i=0;itemlist[i];)
374             free(itemlist[i++]);
375     } else {
376         while((fgets(aline,255,inf) != NULL)
377               && retval) {
378             if(aline[strlen(aline) - 1] == '\n')
379                 aline[strlen(aline) - 1] = '\0';
380             retval = strcmp(aline,citemp);
381         }
382     }
383     fclose(inf);
384     free(ifname);
385     if ((sense && retval) || (!sense && !retval)) {
386 #ifdef DEBUG
387         _pam_log(LOG_INFO, LOCAL_LOG_PREFIX
388                  "Returning PAM_SUCCESS, retval = %d", retval);
389 #endif
390         return PAM_SUCCESS;
391     }
392     else {
393         const char *service, *user_name;
394 #ifdef DEBUG
395         _pam_log(LOG_INFO,LOCAL_LOG_PREFIX
396                  "Returning PAM_AUTH_ERR, retval = %d", retval);
397 #endif
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",
401                  user_name, service);
402         return PAM_AUTH_ERR;
403     }
404 }
405
406 PAM_EXTERN
407 int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
408 {
409     return PAM_SUCCESS;
410 }
411
412 #ifdef PAM_STATIC
413
414 /* static module data */
415
416 struct pam_module _pam_listfile_modstruct = {
417     "pam_listfile",
418     pam_sm_authenticate,
419     pam_sm_setcred,
420     NULL,
421     NULL,
422     NULL,
423     NULL,
424 };
425
426 #endif
427
428 /* end of module definition */
429