]> granicus.if.org Git - linux-pam/blob - modules/pam_wheel/pam_wheel.c
Relevant BUGIDs:
[linux-pam] / modules / pam_wheel / pam_wheel.c
1 /* pam_wheel module */
2
3 /*
4  * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
5  * See the end of the file for Copyright Information
6  *
7  *
8  * 1.2 - added 'deny' and 'group=' options
9  * 1.1 - added 'trust' option
10  * 1.0 - the code is working for at least another person, so... :-)
11  * 0.1 - use vsyslog instead of vfprintf/syslog in _pam_log
12  *     - return PAM_IGNORE on success (take care of sloppy sysadmins..)
13  *     - use pam_get_user instead of pam_get_item(...,PAM_USER,...)
14  *     - a new arg use_uid to auth the current uid instead of the
15  *       initial (logged in) one.
16  * 0.0 - first release
17  *
18  * TODO:
19  *  - try to use make_remark from pam_unix/support.c
20  *  - consider returning on failure PAM_FAIL_NOW if the user is not
21  *    a wheel member.
22  */
23
24 #define _BSD_SOURCE
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <syslog.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <pwd.h>
33 #include <grp.h>
34
35 /*
36  * here, we make a definition for the externally accessible function
37  * in this file (this definition is required for static a module
38  * but strongly encouraged generally) it is used to instruct the
39  * modules include file to define the function prototypes.
40  */
41
42 #define PAM_SM_AUTH
43 #define PAM_SM_ACCOUNT
44
45 #include <security/pam_modules.h>
46 #include <security/_pam_modutil.h>
47
48 /* some syslogging */
49
50 static void _pam_log(int err, const char *format, ...)
51 {
52     va_list args;
53
54     va_start(args, format);
55     openlog("PAM-Wheel", LOG_CONS|LOG_PID, LOG_AUTH);
56     vsyslog(err, format, args);
57     va_end(args);
58     closelog();
59 }
60
61 /* checks if a user is on a list of members of the GID 0 group */
62
63 static int is_on_list(char * const *list, const char *member)
64 {
65     while (list && *list) {
66         if (strcmp(*list, member) == 0)
67             return 1;
68         list++;
69     }
70     return 0;
71 }
72
73 /* argument parsing */
74
75 #define PAM_DEBUG_ARG       0x0001
76 #define PAM_USE_UID_ARG     0x0002
77 #define PAM_TRUST_ARG       0x0004
78 #define PAM_DENY_ARG        0x0010  
79
80 static int _pam_parse(int argc, const char **argv, char *use_group,
81                       size_t group_length)
82 {
83      int ctrl=0;
84
85      memset(use_group, '\0', group_length);
86
87      /* step through arguments */
88      for (ctrl=0; argc-- > 0; ++argv) {
89
90           /* generic options */
91
92           if (!strcmp(*argv,"debug"))
93                ctrl |= PAM_DEBUG_ARG;
94           else if (!strcmp(*argv,"use_uid"))
95                ctrl |= PAM_USE_UID_ARG;
96           else if (!strcmp(*argv,"trust"))
97                ctrl |= PAM_TRUST_ARG;
98           else if (!strcmp(*argv,"deny"))
99                ctrl |= PAM_DENY_ARG;
100           else if (!strncmp(*argv,"group=",6))
101                strncpy(use_group,*argv+6,group_length-1);
102           else {
103                _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
104           }
105      }
106
107      return ctrl;
108 }
109
110 static int perform_check(pam_handle_t *pamh, int flags, int ctrl,
111                          const char *use_group)
112 {
113     const char *username = NULL;
114     const char *fromsu;
115     struct passwd *pwd, *tpwd = NULL;
116     struct group *grp;
117     int retval = PAM_AUTH_ERR;
118
119     retval = pam_get_user(pamh, &username, NULL);
120     if ((retval != PAM_SUCCESS) || (!username)) {
121         if (ctrl & PAM_DEBUG_ARG) {
122             _pam_log(LOG_DEBUG,"can not get the username");
123         }
124         return PAM_SERVICE_ERR;
125     }
126
127     /* su to a uid 0 account ? */
128     pwd = _pammodutil_getpwnam (pamh, username);
129     if (!pwd) {
130         if (ctrl & PAM_DEBUG_ARG) {
131             _pam_log(LOG_NOTICE,"unknown user %s",username);
132         }
133         return PAM_USER_UNKNOWN;
134     }
135      
136     if (ctrl & PAM_USE_UID_ARG) {
137         tpwd = _pammodutil_getpwuid (pamh, getuid());
138         if (!tpwd) {
139             if (ctrl & PAM_DEBUG_ARG) {
140                 _pam_log(LOG_NOTICE, "who is running me ?!");
141             }
142             return PAM_SERVICE_ERR;
143         }
144         fromsu = tpwd->pw_name;
145     } else {
146         fromsu = _pammodutil_getlogin(pamh);
147         if (fromsu) {
148             tpwd = _pammodutil_getpwnam (pamh, fromsu);
149         }
150         if (!fromsu || !tpwd) {
151             if (ctrl & PAM_DEBUG_ARG) {
152                 _pam_log(LOG_NOTICE, "who is running me ?!");
153             }
154             return PAM_SERVICE_ERR;
155         }
156     }
157
158     /*
159      * At this point fromsu = username-of-invoker; tpwd = pwd ptr for fromsu
160      */
161      
162     if (!use_group[0]) {
163         if ((grp = _pammodutil_getgrnam (pamh, "wheel")) == NULL) {
164             grp = _pammodutil_getgrgid (pamh, 0);
165         }
166     } else {
167         grp = _pammodutil_getgrnam (pamh, use_group);
168     }
169
170     if (!grp || (!grp->gr_mem && (tpwd->pw_gid != grp->gr_gid))) {
171         if (ctrl & PAM_DEBUG_ARG) {
172             if (!use_group[0]) {
173                 _pam_log(LOG_NOTICE,"no members in a GID 0 group");
174             } else {
175                 _pam_log(LOG_NOTICE,"no members in '%s' group", use_group);
176             }
177         }
178         if (ctrl & PAM_DENY_ARG) {
179             /* if this was meant to deny access to the members
180              * of this group and the group does not exist, allow
181              * access
182              */
183             return PAM_IGNORE;
184         } else {
185             return PAM_AUTH_ERR;
186         }
187     }
188      
189     /*
190      * test if the user is a member of the group, or if the
191      * user has the "wheel" (sic) group as its primary group.
192      */
193
194     if (is_on_list(grp->gr_mem, fromsu) || (tpwd->pw_gid == grp->gr_gid)) {
195
196         if (ctrl & PAM_DENY_ARG) {
197             retval = PAM_PERM_DENIED;
198
199         } else if (ctrl & PAM_TRUST_ARG) {
200             retval = PAM_SUCCESS;        /* this can be a sufficient check */
201
202         } else {
203             retval = PAM_IGNORE;
204         }
205
206     } else {
207
208         if (ctrl & PAM_DENY_ARG) {
209
210             if (ctrl & PAM_TRUST_ARG) {
211                 retval = PAM_SUCCESS;    /* this can be a sufficient check */
212             } else {
213                 retval = PAM_IGNORE;
214             }
215
216         } else {
217             retval = PAM_PERM_DENIED;
218         }
219     }
220
221     if (ctrl & PAM_DEBUG_ARG) {
222         if (retval == PAM_IGNORE) {
223             _pam_log(LOG_NOTICE, "Ignoring access request '%s' for '%s'",
224                      fromsu, username);
225         } else {
226             _pam_log(LOG_NOTICE, "Access %s to '%s' for '%s'",
227                      (retval != PAM_SUCCESS) ? "denied":"granted",
228                      fromsu, username);
229         }
230     }
231
232     return retval;
233 }
234
235 /* --- authentication management functions --- */
236
237 PAM_EXTERN
238 int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
239                         const char **argv)
240 {
241     char use_group[BUFSIZ];
242     int ctrl;
243
244     ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group));
245
246     return perform_check(pamh, flags, ctrl, use_group);
247 }
248
249 PAM_EXTERN
250 int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
251                    ,const char **argv)
252 {
253     return PAM_SUCCESS;
254 }
255
256 PAM_EXTERN
257 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc,
258                      const char **argv)
259 {
260     char use_group[BUFSIZ];
261     int ctrl;
262
263     ctrl = _pam_parse(argc, argv, use_group, sizeof(use_group));
264
265     return perform_check(pamh, flags, ctrl, use_group);
266 }
267
268 #ifdef PAM_STATIC
269
270 /* static module data */
271
272 struct pam_module _pam_wheel_modstruct = {
273     "pam_wheel",
274     pam_sm_authenticate,
275     pam_sm_setcred,
276     pam_sm_acct_mgmt,
277     NULL,
278     NULL,
279     NULL,
280     NULL,
281 };
282
283 #endif /* PAM_STATIC */
284
285 /*
286  * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997
287  *                                              All rights reserved
288  *
289  * Redistribution and use in source and binary forms, with or without
290  * modification, are permitted provided that the following conditions
291  * are met:
292  * 1. Redistributions of source code must retain the above copyright
293  *    notice, and the entire permission notice in its entirety,
294  *    including the disclaimer of warranties.
295  * 2. Redistributions in binary form must reproduce the above copyright
296  *    notice, this list of conditions and the following disclaimer in the
297  *    documentation and/or other materials provided with the distribution.
298  * 3. The name of the author may not be used to endorse or promote
299  *    products derived from this software without specific prior
300  *    written permission.
301  *
302  * ALTERNATIVELY, this product may be distributed under the terms of
303  * the GNU Public License, in which case the provisions of the GPL are
304  * required INSTEAD OF the above restrictions.  (This clause is
305  * necessary due to a potential bad interaction between the GPL and
306  * the restrictions contained in a BSD-style copyright.)
307  *
308  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
309  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
310  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
311  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
312  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
313  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
314  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
315  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
316  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
317  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
318  * OF THE POSSIBILITY OF SUCH DAMAGE.
319  */