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