pam_modutil_sanitize.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * This file implements the following functions:
  3. * pam_modutil_sanitize_helper_fds:
  4. * redirects standard descriptors, closes all other descriptors.
  5. */
  6. #include "pam_modutil_private.h"
  7. #include <security/pam_ext.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <syslog.h>
  11. #include <sys/resource.h>
  12. /*
  13. * Creates a pipe, closes its write end, redirects fd to its read end.
  14. * Returns fd on success, -1 otherwise.
  15. */
  16. static int
  17. redirect_in_pipe(pam_handle_t *pamh, int fd, const char *name)
  18. {
  19. int in[2];
  20. if (pipe(in) < 0) {
  21. pam_syslog(pamh, LOG_ERR, "Could not create pipe: %m");
  22. return -1;
  23. }
  24. close(in[1]);
  25. if (in[0] == fd)
  26. return fd;
  27. if (dup2(in[0], fd) != fd) {
  28. pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", name);
  29. fd = -1;
  30. }
  31. close(in[0]);
  32. return fd;
  33. }
  34. /*
  35. * Opens /dev/null for writing, redirects fd there.
  36. * Returns fd on success, -1 otherwise.
  37. */
  38. static int
  39. redirect_out_null(pam_handle_t *pamh, int fd, const char *name)
  40. {
  41. int null = open("/dev/null", O_WRONLY);
  42. if (null < 0) {
  43. pam_syslog(pamh, LOG_ERR, "open of %s failed: %m", "/dev/null");
  44. return -1;
  45. }
  46. if (null == fd)
  47. return fd;
  48. if (dup2(null, fd) != fd) {
  49. pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", name);
  50. fd = -1;
  51. }
  52. close(null);
  53. return fd;
  54. }
  55. static int
  56. redirect_out(pam_handle_t *pamh, enum pam_modutil_redirect_fd mode,
  57. int fd, const char *name)
  58. {
  59. switch (mode) {
  60. case PAM_MODUTIL_PIPE_FD:
  61. if (redirect_in_pipe(pamh, fd, name) < 0)
  62. return -1;
  63. break;
  64. case PAM_MODUTIL_NULL_FD:
  65. if (redirect_out_null(pamh, fd, name) < 0)
  66. return -1;
  67. break;
  68. case PAM_MODUTIL_IGNORE_FD:
  69. break;
  70. }
  71. return fd;
  72. }
  73. /* Closes all descriptors after stderr. */
  74. static void
  75. close_fds(void)
  76. {
  77. /*
  78. * An arbitrary upper limit for the maximum file descriptor number
  79. * returned by RLIMIT_NOFILE.
  80. */
  81. const int MAX_FD_NO = 65535;
  82. /* The lower limit is the same as for _POSIX_OPEN_MAX. */
  83. const int MIN_FD_NO = 20;
  84. int fd;
  85. struct rlimit rlim;
  86. if (getrlimit(RLIMIT_NOFILE, &rlim) || rlim.rlim_max > (rlim_t)MAX_FD_NO)
  87. fd = MAX_FD_NO;
  88. else if (rlim.rlim_max < (rlim_t)MIN_FD_NO)
  89. fd = MIN_FD_NO;
  90. else
  91. fd = (int)rlim.rlim_max - 1;
  92. for (; fd > STDERR_FILENO; --fd)
  93. close(fd);
  94. }
  95. int
  96. pam_modutil_sanitize_helper_fds(pam_handle_t *pamh,
  97. enum pam_modutil_redirect_fd stdin_mode,
  98. enum pam_modutil_redirect_fd stdout_mode,
  99. enum pam_modutil_redirect_fd stderr_mode)
  100. {
  101. if (stdin_mode != PAM_MODUTIL_IGNORE_FD &&
  102. redirect_in_pipe(pamh, STDIN_FILENO, "stdin") < 0) {
  103. return -1;
  104. }
  105. if (redirect_out(pamh, stdout_mode, STDOUT_FILENO, "stdout") < 0)
  106. return -1;
  107. /*
  108. * If stderr should not be ignored and
  109. * redirect mode for stdout and stderr are the same,
  110. * optimize by redirecting stderr to stdout.
  111. */
  112. if (stderr_mode != PAM_MODUTIL_IGNORE_FD &&
  113. stdout_mode == stderr_mode) {
  114. if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) {
  115. pam_syslog(pamh, LOG_ERR,
  116. "dup2 of %s failed: %m", "stderr");
  117. return -1;
  118. }
  119. } else {
  120. if (redirect_out(pamh, stderr_mode, STDERR_FILENO, "stderr") < 0)
  121. return -1;
  122. }
  123. close_fds();
  124. return 0;
  125. }