Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / libpam / 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  * $FreeBSD: src/contrib/libpam/modules/pam_wheel/pam_wheel.c,v 1.3.2.2 2001/06/11 15:28:35 markm Exp $
24  */
25
26 #define _BSD_SOURCE
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <stdarg.h>
33 #include <sys/types.h>
34 #include <pwd.h>
35 #include <grp.h>
36
37 /*
38  * here, we make a definition for the externally accessible function
39  * in this file (this definition is required for static a module
40  * but strongly encouraged generally) it is used to instruct the
41  * modules include file to define the function prototypes.
42  */
43
44 #define PAM_SM_AUTH
45
46 #include <security/pam_modules.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) {
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 {
82      int ctrl=0;
83
84      /* step through arguments */
85      for (ctrl=0; argc-- > 0; ++argv) {
86
87           /* generic options */
88
89           if (!strcmp(*argv,"debug"))
90                ctrl |= PAM_DEBUG_ARG;
91           else if (!strcmp(*argv,"use_uid"))
92                ctrl |= PAM_USE_UID_ARG;
93           else if (!strcmp(*argv,"trust"))
94                ctrl |= PAM_TRUST_ARG;
95           else if (!strcmp(*argv,"deny"))
96                ctrl |= PAM_DENY_ARG;
97           else if (!strncmp(*argv,"group=",6))
98                 strcpy(use_group,*argv+6);
99           else {
100                _pam_log(LOG_ERR,"pam_parse: unknown option; %s",*argv);
101           }
102      }
103
104      return ctrl;
105 }
106
107
108 /* --- authentication management functions (only) --- */
109
110 PAM_EXTERN
111 int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
112                         ,const char **argv)
113 {
114      int ctrl;
115      const char *username;
116      char *fromsu;
117      struct passwd *pwd, *tpwd;
118      struct group *grp;
119      int retval = PAM_AUTH_ERR;
120      char use_group[BUFSIZ];
121     
122      /* Init the optional group */
123      bzero(use_group,BUFSIZ);
124      
125      ctrl = _pam_parse(argc, argv, use_group);
126      retval = pam_get_user(pamh,&username,NULL);
127      if ((retval != PAM_SUCCESS) || (!username)) {
128         if (ctrl & PAM_DEBUG_ARG)
129             _pam_log(LOG_DEBUG,"can not get the username");
130         return PAM_SERVICE_ERR;
131      }
132
133      /* su to a uid 0 account ? */
134      pwd = getpwnam(username);
135      if (!pwd) {
136         if (ctrl & PAM_DEBUG_ARG)
137             _pam_log(LOG_NOTICE,"unknown user %s",username);
138         return PAM_USER_UNKNOWN;
139      }
140      
141      /* Now we know that the username exists, pass on to other modules...
142       * the call to pam_get_user made this obsolete, so is commented out
143       *
144       * pam_set_item(pamh,PAM_USER,(const void *)username);
145       */
146
147      /* is this user an UID 0 account ? */
148      if(pwd->pw_uid) {
149         /* no need to check for wheel */
150         return PAM_IGNORE;
151      }
152      
153      if (ctrl & PAM_USE_UID_ARG) {
154          tpwd = getpwuid(getuid());
155          if (!tpwd) {
156             if (ctrl & PAM_DEBUG_ARG)
157                 _pam_log(LOG_NOTICE,"who is running me ?!");
158             return PAM_SERVICE_ERR;
159          }
160          fromsu = tpwd->pw_name;
161      } else {
162          fromsu = getlogin();
163          if (!fromsu) {
164              if (ctrl & PAM_DEBUG_ARG)
165                 _pam_log(LOG_NOTICE,"who is running me ?!");
166              return PAM_SERVICE_ERR;
167          }
168      }
169      
170      if (!use_group[0]) {
171          if ((grp = getgrnam("wheel")) == NULL) {
172              grp = getgrgid(0);
173          }
174      } else
175          grp = getgrnam(use_group);
176         
177      if (!grp || !grp->gr_mem) {
178         if (ctrl & PAM_DEBUG_ARG) {
179             if (!use_group[0])
180                 _pam_log(LOG_NOTICE,"no members in a GID 0 group");
181             else
182                 _pam_log(LOG_NOTICE,"no members in '%s' group",use_group);
183         }
184         if (ctrl & PAM_DENY_ARG)
185             /* if this was meant to deny access to the members
186              * of this group and the group does not exist, allow
187              * access
188              */
189             return PAM_IGNORE;
190         else
191             return PAM_AUTH_ERR;
192      }
193         
194      if (is_on_list(grp->gr_mem, fromsu)) {
195         if (ctrl & PAM_DEBUG_ARG)
196             _pam_log(LOG_NOTICE,"Access %s to '%s' for '%s'",
197                      (ctrl & PAM_DENY_ARG)?"denied":"granted",
198                      fromsu,username);
199         if (ctrl & PAM_DENY_ARG)
200             return PAM_PERM_DENIED;
201         else
202             if (ctrl & PAM_TRUST_ARG)
203                 return PAM_SUCCESS;
204             else
205                 return PAM_IGNORE;
206      }
207
208      if (ctrl & PAM_DEBUG_ARG)
209         _pam_log(LOG_NOTICE,"Access %s for '%s' to '%s'",
210         (ctrl & PAM_DENY_ARG)?"granted":"denied",fromsu,username);
211      if (ctrl & PAM_DENY_ARG)
212         return PAM_SUCCESS;
213      else
214         return PAM_PERM_DENIED;
215 }
216
217 PAM_EXTERN
218 int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc
219                    ,const char **argv)
220 {
221      return PAM_SUCCESS;
222 }
223
224
225 /* end of module definition */
226
227 PAM_MODULE_ENTRY("pam_wheel");
228
229 /*
230  * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1996, 1997
231  *                                              All rights reserved
232  *
233  * Redistribution and use in source and binary forms, with or without
234  * modification, are permitted provided that the following conditions
235  * are met:
236  * 1. Redistributions of source code must retain the above copyright
237  *    notice, and the entire permission notice in its entirety,
238  *    including the disclaimer of warranties.
239  * 2. Redistributions in binary form must reproduce the above copyright
240  *    notice, this list of conditions and the following disclaimer in the
241  *    documentation and/or other materials provided with the distribution.
242  * 3. The name of the author may not be used to endorse or promote
243  *    products derived from this software without specific prior
244  *    written permission.
245  *
246  * ALTERNATIVELY, this product may be distributed under the terms of
247  * the GNU Public License, in which case the provisions of the GPL are
248  * required INSTEAD OF the above restrictions.  (This clause is
249  * necessary due to a potential bad interaction between the GPL and
250  * the restrictions contained in a BSD-style copyright.)
251  *
252  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
253  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
254  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
255  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
256  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
257  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
258  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
259  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
260  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
261  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
262  * OF THE POSSIBILITY OF SUCH DAMAGE.
263  */