pam_wheel.c 8.7 KB

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