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