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