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