]> granicus.if.org Git - linux-pam/blob - modules/pam_wheel/pam_wheel.c
doc: fix module type written in MODULE TYPES PROVIDED
[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 #include "config.h"
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 #include <security/pam_ext.h>
48
49 /* checks if a user is on a list of members of the GID 0 group */
50 static int is_on_list(char * const *list, const char *member)
51 {
52     while (list && *list) {
53         if (strcmp(*list, member) == 0)
54             return 1;
55         list++;
56     }
57     return 0;
58 }
59
60 /* argument parsing */
61
62 #define PAM_DEBUG_ARG       0x0001
63 #define PAM_USE_UID_ARG     0x0002
64 #define PAM_TRUST_ARG       0x0004
65 #define PAM_DENY_ARG        0x0010
66 #define PAM_ROOT_ONLY_ARG   0x0020
67
68 static int
69 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
70             char *use_group, size_t group_length)
71 {
72      int ctrl=0;
73
74      memset(use_group, '\0', group_length);
75
76      /* step through arguments */
77      for (ctrl=0; argc-- > 0; ++argv) {
78
79           /* generic options */
80
81           if (!strcmp(*argv,"debug"))
82                ctrl |= PAM_DEBUG_ARG;
83           else if (!strcmp(*argv,"use_uid"))
84                ctrl |= PAM_USE_UID_ARG;
85           else if (!strcmp(*argv,"trust"))
86                ctrl |= PAM_TRUST_ARG;
87           else if (!strcmp(*argv,"deny"))
88                ctrl |= PAM_DENY_ARG;
89           else if (!strcmp(*argv,"root_only"))
90                ctrl |= PAM_ROOT_ONLY_ARG;
91           else if (!strncmp(*argv,"group=",6))
92                strncpy(use_group,*argv+6,group_length-1);
93           else {
94                pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
95           }
96      }
97
98      return ctrl;
99 }
100
101 static int
102 perform_check (pam_handle_t *pamh, int ctrl, const char *use_group)
103 {
104     const char *username = NULL;
105     const char *fromsu;
106     struct passwd *pwd, *tpwd = NULL;
107     struct group *grp;
108     int retval = PAM_AUTH_ERR;
109
110     retval = pam_get_user(pamh, &username, NULL);
111     if ((retval != PAM_SUCCESS) || (!username)) {
112         if (ctrl & PAM_DEBUG_ARG) {
113             pam_syslog(pamh, LOG_DEBUG, "can not get the username");
114         }
115         return PAM_SERVICE_ERR;
116     }
117
118     pwd = pam_modutil_getpwnam (pamh, username);
119     if (!pwd) {
120         if (ctrl & PAM_DEBUG_ARG) {
121             pam_syslog(pamh, LOG_NOTICE, "unknown user %s", username);
122         }
123         return PAM_USER_UNKNOWN;
124     }
125     if (ctrl & PAM_ROOT_ONLY_ARG) {
126         /* su to a non uid 0 account ? */
127         if (pwd->pw_uid != 0) {
128             return PAM_IGNORE;
129         }
130     }
131
132     if (ctrl & PAM_USE_UID_ARG) {
133         tpwd = pam_modutil_getpwuid (pamh, getuid());
134         if (!tpwd) {
135             if (ctrl & PAM_DEBUG_ARG) {
136                 pam_syslog(pamh, LOG_NOTICE, "who is running me ?!");
137             }
138             return PAM_SERVICE_ERR;
139         }
140         fromsu = tpwd->pw_name;
141     } else {
142         fromsu = pam_modutil_getlogin(pamh);
143         if (fromsu) {
144             tpwd = pam_modutil_getpwnam (pamh, fromsu);
145         }
146         if (!fromsu || !tpwd) {
147             if (ctrl & PAM_DEBUG_ARG) {
148                 pam_syslog(pamh, LOG_NOTICE, "who is running me ?!");
149             }
150             return PAM_SERVICE_ERR;
151         }
152     }
153
154     /*
155      * At this point fromsu = username-of-invoker; tpwd = pwd ptr for fromsu
156      */
157
158     if (!use_group[0]) {
159         if ((grp = pam_modutil_getgrnam (pamh, "wheel")) == NULL) {
160             grp = pam_modutil_getgrgid (pamh, 0);
161         }
162     } else {
163         grp = pam_modutil_getgrnam (pamh, use_group);
164     }
165
166     if (!grp || (!grp->gr_mem && (tpwd->pw_gid != grp->gr_gid))) {
167         if (ctrl & PAM_DEBUG_ARG) {
168             if (!use_group[0]) {
169                 pam_syslog(pamh, LOG_NOTICE, "no members in a GID 0 group");
170             } else {
171                 pam_syslog(pamh, LOG_NOTICE,
172                            "no members in '%s' group", use_group);
173             }
174         }
175         if (ctrl & PAM_DENY_ARG) {
176             /* if this was meant to deny access to the members
177              * of this group and the group does not exist, allow
178              * access
179              */
180             return PAM_IGNORE;
181         } else {
182             return PAM_AUTH_ERR;
183         }
184     }
185
186     /*
187      * test if the user is a member of the group, or if the
188      * user has the "wheel" (sic) group as its primary group.
189      */
190
191     if (is_on_list(grp->gr_mem, fromsu) || (tpwd->pw_gid == grp->gr_gid)) {
192
193         if (ctrl & PAM_DENY_ARG) {
194             retval = PAM_PERM_DENIED;
195
196         } else if (ctrl & PAM_TRUST_ARG) {
197             retval = PAM_SUCCESS;        /* this can be a sufficient check */
198
199         } else {
200             retval = PAM_IGNORE;
201         }
202
203     } else {
204
205         if (ctrl & PAM_DENY_ARG) {
206
207             if (ctrl & PAM_TRUST_ARG) {
208                 retval = PAM_SUCCESS;    /* this can be a sufficient check */
209             } else {
210                 retval = PAM_IGNORE;
211             }
212
213         } else {
214             retval = PAM_PERM_DENIED;
215         }
216     }
217
218     if (ctrl & PAM_DEBUG_ARG) {
219         if (retval == PAM_IGNORE) {
220             pam_syslog(pamh, LOG_NOTICE,
221                        "Ignoring access request '%s' for '%s'",
222                        fromsu, username);
223         } else {
224             pam_syslog(pamh, LOG_NOTICE, "Access %s to '%s' for '%s'",
225                        (retval != PAM_SUCCESS) ? "denied":"granted",
226                        fromsu, username);
227         }
228     }
229
230     return retval;
231 }
232
233 /* --- authentication management functions --- */
234
235 int
236 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
237                      int argc, const char **argv)
238 {
239     char use_group[BUFSIZ];
240     int ctrl;
241
242     ctrl = _pam_parse(pamh, argc, argv, use_group, sizeof(use_group));
243
244     return perform_check(pamh, ctrl, use_group);
245 }
246
247 int
248 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
249                 int argc UNUSED, const char **argv UNUSED)
250 {
251     return PAM_SUCCESS;
252 }
253
254 int
255 pam_sm_acct_mgmt (pam_handle_t *pamh, int flags UNUSED,
256                   int argc, const char **argv)
257 {
258     char use_group[BUFSIZ];
259     int ctrl;
260
261     ctrl = _pam_parse(pamh, argc, argv, use_group, sizeof(use_group));
262
263     return perform_check(pamh, ctrl, use_group);
264 }
265
266 /*
267  * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997
268  *                                              All rights reserved
269  *
270  * Redistribution and use in source and binary forms, with or without
271  * modification, are permitted provided that the following conditions
272  * are met:
273  * 1. Redistributions of source code must retain the above copyright
274  *    notice, and the entire permission notice in its entirety,
275  *    including the disclaimer of warranties.
276  * 2. Redistributions in binary form must reproduce the above copyright
277  *    notice, this list of conditions and the following disclaimer in the
278  *    documentation and/or other materials provided with the distribution.
279  * 3. The name of the author may not be used to endorse or promote
280  *    products derived from this software without specific prior
281  *    written permission.
282  *
283  * ALTERNATIVELY, this product may be distributed under the terms of
284  * the GNU Public License, in which case the provisions of the GPL are
285  * required INSTEAD OF the above restrictions.  (This clause is
286  * necessary due to a potential bad interaction between the GPL and
287  * the restrictions contained in a BSD-style copyright.)
288  *
289  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
290  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
291  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
292  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
293  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
294  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
295  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
296  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
297  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
299  * OF THE POSSIBILITY OF SUCH DAMAGE.
300  */