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