4 * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
5 * See the end of the file for Copyright Information
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.
19 * - try to use make_remark from pam_unix/support.c
20 * - consider returning on failure PAM_FAIL_NOW if the user is not
31 #include <sys/types.h>
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.
43 #define PAM_SM_ACCOUNT
45 #include <security/pam_modules.h>
46 #include <security/pam_modutil.h>
47 #include <security/pam_ext.h>
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)
52 while (list && *list) {
53 if (strcmp(*list, member) == 0)
60 /* argument parsing */
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
69 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
70 char *use_group, size_t group_length)
74 memset(use_group, '\0', group_length);
76 /* step through arguments */
77 for (ctrl=0; argc-- > 0; ++argv) {
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"))
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);
94 pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
102 perform_check (pam_handle_t *pamh, int ctrl, const char *use_group)
104 const char *username = NULL;
106 struct passwd *pwd, *tpwd = NULL;
108 int retval = PAM_AUTH_ERR;
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");
115 return PAM_SERVICE_ERR;
118 pwd = pam_modutil_getpwnam (pamh, username);
120 if (ctrl & PAM_DEBUG_ARG) {
121 pam_syslog(pamh, LOG_NOTICE, "unknown user %s", username);
123 return PAM_USER_UNKNOWN;
125 if (ctrl & PAM_ROOT_ONLY_ARG) {
126 /* su to a non uid 0 account ? */
127 if (pwd->pw_uid != 0) {
132 if (ctrl & PAM_USE_UID_ARG) {
133 tpwd = pam_modutil_getpwuid (pamh, getuid());
135 if (ctrl & PAM_DEBUG_ARG) {
136 pam_syslog(pamh, LOG_NOTICE, "who is running me ?!");
138 return PAM_SERVICE_ERR;
140 fromsu = tpwd->pw_name;
142 fromsu = pam_modutil_getlogin(pamh);
144 tpwd = pam_modutil_getpwnam (pamh, fromsu);
146 if (!fromsu || !tpwd) {
147 if (ctrl & PAM_DEBUG_ARG) {
148 pam_syslog(pamh, LOG_NOTICE, "who is running me ?!");
150 return PAM_SERVICE_ERR;
155 * At this point fromsu = username-of-invoker; tpwd = pwd ptr for fromsu
159 if ((grp = pam_modutil_getgrnam (pamh, "wheel")) == NULL) {
160 grp = pam_modutil_getgrgid (pamh, 0);
163 grp = pam_modutil_getgrnam (pamh, use_group);
166 if (!grp || (!grp->gr_mem && (tpwd->pw_gid != grp->gr_gid))) {
167 if (ctrl & PAM_DEBUG_ARG) {
169 pam_syslog(pamh, LOG_NOTICE, "no members in a GID 0 group");
171 pam_syslog(pamh, LOG_NOTICE,
172 "no members in '%s' group", use_group);
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
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.
191 if (is_on_list(grp->gr_mem, fromsu) || (tpwd->pw_gid == grp->gr_gid)) {
193 if (ctrl & PAM_DENY_ARG) {
194 retval = PAM_PERM_DENIED;
196 } else if (ctrl & PAM_TRUST_ARG) {
197 retval = PAM_SUCCESS; /* this can be a sufficient check */
205 if (ctrl & PAM_DENY_ARG) {
207 if (ctrl & PAM_TRUST_ARG) {
208 retval = PAM_SUCCESS; /* this can be a sufficient check */
214 retval = PAM_PERM_DENIED;
218 if (ctrl & PAM_DEBUG_ARG) {
219 if (retval == PAM_IGNORE) {
220 pam_syslog(pamh, LOG_NOTICE,
221 "Ignoring access request '%s' for '%s'",
224 pam_syslog(pamh, LOG_NOTICE, "Access %s to '%s' for '%s'",
225 (retval != PAM_SUCCESS) ? "denied":"granted",
233 /* --- authentication management functions --- */
236 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
237 int argc, const char **argv)
239 char use_group[BUFSIZ];
242 ctrl = _pam_parse(pamh, argc, argv, use_group, sizeof(use_group));
244 return perform_check(pamh, ctrl, use_group);
248 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
249 int argc UNUSED, const char **argv UNUSED)
255 pam_sm_acct_mgmt (pam_handle_t *pamh, int flags UNUSED,
256 int argc, const char **argv)
258 char use_group[BUFSIZ];
261 ctrl = _pam_parse(pamh, argc, argv, use_group, sizeof(use_group));
263 return perform_check(pamh, ctrl, use_group);
267 * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997
268 * All rights reserved
270 * Redistribution and use in source and binary forms, with or without
271 * modification, are permitted provided that the following conditions
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.
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.)
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.