pam_securetty.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * pam_securetty module
  3. *
  4. * by Elliot Lee <sopwith@redhat.com>, Red Hat Software.
  5. * July 25, 1996.
  6. * This code shamelessly ripped from the pam_rootok module.
  7. * Slight modifications AGM. 1996/12/3
  8. */
  9. #include "config.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <unistd.h>
  15. #include <syslog.h>
  16. #include <stdarg.h>
  17. #include <pwd.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <limits.h>
  21. #include <errno.h>
  22. #include <security/pam_modules.h>
  23. #include <security/pam_modutil.h>
  24. #include <security/pam_ext.h>
  25. #include "pam_inline.h"
  26. #define PAM_DEBUG_ARG 0x0001
  27. #define PAM_NOCONSOLE_ARG 0x0002
  28. #define SECURETTY_FILE "/etc/securetty"
  29. #ifdef VENDORDIR
  30. #define SECURETTY2_FILE VENDORDIR"/securetty"
  31. #endif
  32. #define TTY_PREFIX "/dev/"
  33. #define CMDLINE_FILE "/proc/cmdline"
  34. #define CONSOLEACTIVE_FILE "/sys/class/tty/console/active"
  35. static int
  36. _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
  37. {
  38. int ctrl=0;
  39. /* step through arguments */
  40. for (ctrl=0; argc-- > 0; ++argv) {
  41. /* generic options */
  42. if (!strcmp(*argv,"debug"))
  43. ctrl |= PAM_DEBUG_ARG;
  44. else if (!strcmp(*argv, "noconsole"))
  45. ctrl |= PAM_NOCONSOLE_ARG;
  46. else {
  47. pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
  48. }
  49. }
  50. return ctrl;
  51. }
  52. static int
  53. securetty_perform_check (pam_handle_t *pamh, int ctrl,
  54. const char *function_name)
  55. {
  56. int retval = PAM_AUTH_ERR;
  57. const char *securettyfile;
  58. const char *username;
  59. const char *uttyname;
  60. const char *str;
  61. const void *void_uttyname;
  62. char ttyfileline[256];
  63. char ptname[256];
  64. struct stat ttyfileinfo;
  65. struct passwd *user_pwd;
  66. FILE *ttyfile;
  67. /* log a trail for debugging */
  68. if (ctrl & PAM_DEBUG_ARG) {
  69. pam_syslog(pamh, LOG_DEBUG, "pam_securetty called via %s function",
  70. function_name);
  71. }
  72. retval = pam_get_user(pamh, &username, NULL);
  73. if (retval != PAM_SUCCESS) {
  74. pam_syslog(pamh, LOG_NOTICE, "cannot determine user name: %s",
  75. pam_strerror(pamh, retval));
  76. return (retval == PAM_CONV_AGAIN ? PAM_INCOMPLETE : retval);
  77. }
  78. user_pwd = pam_modutil_getpwnam(pamh, username);
  79. if (user_pwd != NULL && user_pwd->pw_uid != 0) {
  80. /* If the user is not root, securetty's does not apply to them */
  81. return PAM_SUCCESS;
  82. }
  83. /* The user is now either root or an invalid / mistyped username */
  84. retval = pam_get_item(pamh, PAM_TTY, &void_uttyname);
  85. uttyname = void_uttyname;
  86. if (retval != PAM_SUCCESS || uttyname == NULL) {
  87. pam_syslog (pamh, LOG_ERR, "cannot determine user's tty");
  88. return PAM_SERVICE_ERR;
  89. }
  90. /* The PAM_TTY item may be prefixed with "/dev/" - skip that */
  91. if ((str = pam_str_skip_prefix(uttyname, TTY_PREFIX)) != NULL)
  92. uttyname = str;
  93. if (stat(SECURETTY_FILE, &ttyfileinfo)) {
  94. #ifdef VENDORDIR
  95. if (errno == ENOENT) {
  96. if (stat(SECURETTY2_FILE, &ttyfileinfo)) {
  97. if (ctrl & PAM_DEBUG_ARG)
  98. pam_syslog(pamh, LOG_DEBUG,
  99. "Couldn't open %s: %m", SECURETTY2_FILE);
  100. return PAM_SUCCESS; /* for compatibility with old securetty handling,
  101. this needs to succeed. But we still log the
  102. error. */
  103. }
  104. securettyfile = SECURETTY2_FILE;
  105. } else {
  106. #endif
  107. if (ctrl & PAM_DEBUG_ARG)
  108. pam_syslog(pamh, LOG_DEBUG, "Couldn't open %s: %m", SECURETTY_FILE);
  109. return PAM_SUCCESS; /* for compatibility with old securetty handling,
  110. this needs to succeed. But we still log the
  111. error. */
  112. #ifdef VENDORDIR
  113. }
  114. #endif
  115. } else {
  116. securettyfile = SECURETTY_FILE;
  117. }
  118. if ((ttyfileinfo.st_mode & S_IWOTH) || !S_ISREG(ttyfileinfo.st_mode)) {
  119. /* If the file is world writable or is not a
  120. normal file, return error */
  121. pam_syslog(pamh, LOG_ERR,
  122. "%s is either world writable or not a normal file",
  123. securettyfile);
  124. return PAM_AUTH_ERR;
  125. }
  126. ttyfile = fopen(securettyfile,"r");
  127. if (ttyfile == NULL) { /* Check that we opened it successfully */
  128. pam_syslog(pamh, LOG_ERR, "Error opening %s: %m", securettyfile);
  129. return PAM_SERVICE_ERR;
  130. }
  131. if (isdigit(uttyname[0])) {
  132. snprintf(ptname, sizeof(ptname), "pts/%s", uttyname);
  133. } else {
  134. ptname[0] = '\0';
  135. }
  136. retval = 1;
  137. while ((fgets(ttyfileline, sizeof(ttyfileline)-1, ttyfile) != NULL)
  138. && retval) {
  139. if (ttyfileline[strlen(ttyfileline) - 1] == '\n')
  140. ttyfileline[strlen(ttyfileline) - 1] = '\0';
  141. retval = ( strcmp(ttyfileline, uttyname)
  142. && (!ptname[0] || strcmp(ptname, uttyname)) );
  143. }
  144. fclose(ttyfile);
  145. if (retval && !(ctrl & PAM_NOCONSOLE_ARG)) {
  146. FILE *cmdlinefile;
  147. /* Allow access from the kernel console, if enabled */
  148. cmdlinefile = fopen(CMDLINE_FILE, "r");
  149. if (cmdlinefile != NULL) {
  150. char line[LINE_MAX], *p;
  151. p = fgets(line, sizeof(line), cmdlinefile);
  152. fclose(cmdlinefile);
  153. for (; p; p = strstr(p+1, "console=")) {
  154. const char *e;
  155. /* Test whether this is a beginning of a word? */
  156. if (p > line && p[-1] != ' ')
  157. continue;
  158. /* Is this our console? */
  159. if ((e = pam_str_skip_prefix_len(p + 8, uttyname, strlen(uttyname))) == NULL)
  160. continue;
  161. /* Is there any garbage after the TTY name? */
  162. if (*e == ',' || *e == ' ' || *e == '\n' || *e == 0) {
  163. retval = 0;
  164. break;
  165. }
  166. }
  167. }
  168. }
  169. if (retval && !(ctrl & PAM_NOCONSOLE_ARG)) {
  170. FILE *consoleactivefile;
  171. /* Allow access from the active console */
  172. consoleactivefile = fopen(CONSOLEACTIVE_FILE, "r");
  173. if (consoleactivefile != NULL) {
  174. char line[LINE_MAX], *p, *n;
  175. line[0] = 0;
  176. p = fgets(line, sizeof(line), consoleactivefile);
  177. fclose(consoleactivefile);
  178. if (p) {
  179. /* remove the newline character at end */
  180. if (line[strlen(line)-1] == '\n')
  181. line[strlen(line)-1] = 0;
  182. for (n = p; n != NULL; p = n+1) {
  183. if ((n = strchr(p, ' ')) != NULL)
  184. *n = '\0';
  185. if (strcmp(p, uttyname) == 0) {
  186. retval = 0;
  187. break;
  188. }
  189. }
  190. }
  191. }
  192. }
  193. if (retval) {
  194. pam_syslog(pamh, LOG_NOTICE, "access denied: tty '%s' is not secure !",
  195. uttyname);
  196. retval = PAM_AUTH_ERR;
  197. if (user_pwd == NULL) {
  198. retval = PAM_USER_UNKNOWN;
  199. }
  200. } else {
  201. if (ctrl & PAM_DEBUG_ARG) {
  202. pam_syslog(pamh, LOG_DEBUG, "access allowed for '%s' on '%s'",
  203. username, uttyname);
  204. }
  205. retval = PAM_SUCCESS;
  206. }
  207. return retval;
  208. }
  209. /* --- authentication management functions --- */
  210. int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, int argc,
  211. const char **argv)
  212. {
  213. int ctrl;
  214. /* parse the arguments */
  215. ctrl = _pam_parse (pamh, argc, argv);
  216. return securetty_perform_check(pamh, ctrl, __FUNCTION__);
  217. }
  218. int
  219. pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
  220. int argc UNUSED, const char **argv UNUSED)
  221. {
  222. return PAM_SUCCESS;
  223. }
  224. /* --- account management functions --- */
  225. int
  226. pam_sm_acct_mgmt (pam_handle_t *pamh, int flags UNUSED,
  227. int argc, const char **argv)
  228. {
  229. int ctrl;
  230. /* parse the arguments */
  231. ctrl = _pam_parse (pamh, argc, argv);
  232. /* take the easy route */
  233. return securetty_perform_check(pamh, ctrl, __FUNCTION__);
  234. }
  235. /* end of module definition */