(root)/
Linux-PAM-1.5.3/
modules/
pam_wheel/
pam_wheel.c
       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   */