(root)/
Linux-PAM-1.5.3/
modules/
pam_listfile/
pam_listfile.c
       1  /*
       2   * pam_listfile module
       3   *
       4   * by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996.
       5   * log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11
       6   *
       7   * This code began life as the pam_rootok module.
       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 <string.h>
      20  #include <pwd.h>
      21  #include <grp.h>
      22  
      23  #ifdef PAM_DEBUG
      24  #include <assert.h>
      25  #endif
      26  
      27  #include <security/pam_modules.h>
      28  #include <security/_pam_macros.h>
      29  #include <security/pam_modutil.h>
      30  #include <security/pam_ext.h>
      31  #include "pam_inline.h"
      32  
      33  /* --- authentication management functions (only) --- */
      34  
      35  /* Extended Items that are not directly available via pam_get_item() */
      36  #define EI_GROUP (1 << 0)
      37  #define EI_SHELL (1 << 1)
      38  
      39  /* Constants for apply= parameter */
      40  #define APPLY_TYPE_NULL		0
      41  #define APPLY_TYPE_NONE		1
      42  #define APPLY_TYPE_USER		2
      43  #define APPLY_TYPE_GROUP	3
      44  
      45  #define LESSER(a, b) ((a) < (b) ? (a) : (b))
      46  
      47  int
      48  pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
      49  		     int argc, const char **argv)
      50  {
      51      int retval, i, citem=0, extitem=0, onerr=PAM_SERVICE_ERR, sense=2, quiet=0;
      52      const void *void_citemp;
      53      const char *citemp;
      54      char *ifname=NULL;
      55      char aline[256];
      56      char mybuf[256],myval[256],apply_val[256];
      57      struct stat fileinfo;
      58      FILE *inf;
      59      int apply_type;
      60  
      61      /* Stuff for "extended" items */
      62      struct passwd *userinfo;
      63  
      64      apply_type=APPLY_TYPE_NULL;
      65      apply_val[0] = '\0';
      66  
      67      for(i=0; i < argc; i++) {
      68  	{
      69  	    const char *junk;
      70  
      71  	    /* option quiet has no value */
      72  	    if(!strcmp(argv[i],"quiet")) {
      73  		quiet = 1;
      74  		continue;
      75  	    }
      76  
      77  	    memset(mybuf,'\0',sizeof(mybuf));
      78  	    memset(myval,'\0',sizeof(myval));
      79  	    junk = strchr(argv[i], '=');
      80  	    if((junk == NULL) || (junk - argv[i]) >= (int) sizeof(mybuf)) {
      81  		pam_syslog(pamh,LOG_ERR, "Bad option: \"%s\"",
      82  			 argv[i]);
      83  		continue;
      84  	    }
      85  	    strncpy(mybuf, argv[i],
      86  		    LESSER(junk - argv[i], (int)sizeof(mybuf) - 1));
      87  	    strncpy(myval, junk + 1, sizeof(myval) - 1);
      88  	}
      89  	if(!strcmp(mybuf,"onerr"))
      90  	    if(!strcmp(myval,"succeed"))
      91  		onerr = PAM_SUCCESS;
      92  	    else if(!strcmp(myval,"fail"))
      93  		onerr = PAM_SERVICE_ERR;
      94  	    else {
      95  	        if (ifname) free (ifname);
      96  		return PAM_SERVICE_ERR;
      97  	    }
      98  	else if(!strcmp(mybuf,"sense"))
      99  	    if(!strcmp(myval,"allow"))
     100  		sense=0;
     101  	    else if(!strcmp(myval,"deny"))
     102  		sense=1;
     103  	    else {
     104  	        if (ifname) free (ifname);
     105  		return onerr;
     106  	    }
     107  	else if(!strcmp(mybuf,"file")) {
     108  	    if (ifname) free (ifname);
     109  	    ifname = (char *)malloc(strlen(myval)+1);
     110  	    if (!ifname)
     111  		return PAM_BUF_ERR;
     112  	    strcpy(ifname,myval);
     113  	} else if(!strcmp(mybuf,"item"))
     114  	    if(!strcmp(myval,"user"))
     115  		citem = PAM_USER;
     116  	    else if(!strcmp(myval,"tty"))
     117  		citem = PAM_TTY;
     118  	    else if(!strcmp(myval,"rhost"))
     119  		citem = PAM_RHOST;
     120  	    else if(!strcmp(myval,"ruser"))
     121  		citem = PAM_RUSER;
     122  	    else { /* These items are related to the user, but are not
     123  		      directly gettable with pam_get_item */
     124  		citem = PAM_USER;
     125  		if(!strcmp(myval,"group"))
     126  		    extitem = EI_GROUP;
     127  		else if(!strcmp(myval,"shell"))
     128  		    extitem = EI_SHELL;
     129  		else
     130  		    citem = 0;
     131  	    } else if(!strcmp(mybuf,"apply")) {
     132  		apply_type=APPLY_TYPE_NONE;
     133  		if (myval[0]=='@') {
     134  		    apply_type=APPLY_TYPE_GROUP;
     135  		    memcpy(apply_val,myval+1,sizeof(myval)-1);
     136  		} else {
     137  		    apply_type=APPLY_TYPE_USER;
     138  		    memcpy(apply_val,myval,sizeof(myval));
     139  		}
     140  	    } else {
     141  		free(ifname);
     142  		pam_syslog(pamh,LOG_ERR, "Unknown option: %s",mybuf);
     143  		return onerr;
     144  	    }
     145      }
     146  
     147      if(!citem) {
     148  	pam_syslog(pamh,LOG_ERR,
     149  		  "Unknown item or item not specified");
     150  	free(ifname);
     151  	return onerr;
     152      } else if(!ifname) {
     153  	pam_syslog(pamh,LOG_ERR, "List filename not specified");
     154  	return onerr;
     155      } else if(sense == 2) {
     156  	pam_syslog(pamh,LOG_ERR,
     157  		  "Unknown sense or sense not specified");
     158  	free(ifname);
     159  	return onerr;
     160      } else if(
     161  	      (apply_type==APPLY_TYPE_NONE) ||
     162  	      ((apply_type!=APPLY_TYPE_NULL) && (*apply_val=='\0'))
     163                ) {
     164  	pam_syslog(pamh,LOG_ERR,
     165  		  "Invalid usage for apply= parameter");
     166          free (ifname);
     167  	return onerr;
     168      }
     169  
     170      /* Check if it makes sense to use the apply= parameter */
     171      if (apply_type != APPLY_TYPE_NULL) {
     172  	if((citem==PAM_USER) || (citem==PAM_RUSER)) {
     173  	    pam_syslog(pamh,LOG_WARNING,
     174  		      "Non-sense use for apply= parameter");
     175  	    apply_type=APPLY_TYPE_NULL;
     176  	}
     177  	if(extitem && (extitem==EI_GROUP)) {
     178  	    pam_syslog(pamh,LOG_WARNING,
     179  		      "Non-sense use for apply= parameter");
     180  	    apply_type=APPLY_TYPE_NULL;
     181  	}
     182      }
     183  
     184      /* Short-circuit - test if this session apply for this user */
     185      {
     186  	const char *user_name;
     187  	int rval;
     188  
     189  	rval=pam_get_user(pamh,&user_name,NULL);
     190  	if(rval==PAM_SUCCESS && user_name[0]) {
     191  	    /* Got it ? Valid ? */
     192  	    if(apply_type==APPLY_TYPE_USER) {
     193  		if(strcmp(user_name, apply_val)) {
     194  		    /* Does not apply to this user */
     195  #ifdef PAM_DEBUG
     196  		    pam_syslog(pamh,LOG_DEBUG,
     197  			      "don't apply: apply=%s, user=%s",
     198  			     apply_val,user_name);
     199  #endif /* PAM_DEBUG */
     200  		    free(ifname);
     201  		    return PAM_IGNORE;
     202  		}
     203  	    } else if(apply_type==APPLY_TYPE_GROUP) {
     204  		if(!pam_modutil_user_in_group_nam_nam(pamh,user_name,apply_val)) {
     205  		    /* Not a member of apply= group */
     206  #ifdef PAM_DEBUG
     207  		    pam_syslog(pamh,LOG_DEBUG,
     208  
     209  			     "don't apply: %s not a member of group %s",
     210  			     user_name,apply_val);
     211  #endif /* PAM_DEBUG */
     212  		    free(ifname);
     213  		    return PAM_IGNORE;
     214  		}
     215  	    }
     216  	}
     217      }
     218  
     219      retval = pam_get_item(pamh,citem,&void_citemp);
     220      citemp = void_citemp;
     221      if(retval != PAM_SUCCESS) {
     222  	free(ifname);
     223  	return onerr;
     224      }
     225      if((citem == PAM_USER) && !citemp) {
     226  	retval = pam_get_user(pamh,&citemp,NULL);
     227  	if (retval != PAM_SUCCESS) {
     228  	    free(ifname);
     229  	    return PAM_SERVICE_ERR;
     230  	}
     231      }
     232      if((citem == PAM_TTY) && citemp) {
     233          /* Normalize the TTY name. */
     234          const char *str = pam_str_skip_prefix(citemp, "/dev/");
     235          if (str != NULL)
     236              citemp = str;
     237      }
     238  
     239      if(!citemp || (strlen(citemp) == 0)) {
     240  	free(ifname);
     241  	/* The item was NULL - we are sure not to match */
     242  	return sense?PAM_SUCCESS:PAM_AUTH_ERR;
     243      }
     244  
     245      if(extitem) {
     246  	switch(extitem) {
     247  	    case EI_GROUP:
     248  		/* Just ignore, call pam_modutil_in_group... later */
     249  		break;
     250  	    case EI_SHELL:
     251  		/* Assume that we have already gotten PAM_USER in
     252  		   pam_get_item() - a valid assumption since citem
     253  		   gets set to PAM_USER in the extitem switch */
     254  		userinfo = pam_modutil_getpwnam(pamh, citemp);
     255  		if (userinfo == NULL) {
     256  		    pam_syslog(pamh, LOG_NOTICE, "getpwnam(%s) failed",
     257  			     citemp);
     258  		    free(ifname);
     259  		    return onerr;
     260  		}
     261  		citemp = userinfo->pw_shell;
     262  		break;
     263  	    default:
     264  		pam_syslog(pamh,LOG_ERR,
     265  
     266  			 "Internal weirdness, unknown extended item %d",
     267  			 extitem);
     268  		free(ifname);
     269  		return onerr;
     270  	}
     271      }
     272  #ifdef PAM_DEBUG
     273      pam_syslog(pamh,LOG_INFO,
     274  
     275  	     "Got file = %s, item = %d, value = %s, sense = %d",
     276  	     ifname, citem, citemp, sense);
     277  #endif
     278      if(lstat(ifname,&fileinfo)) {
     279  	if(!quiet)
     280  		pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname);
     281  	free(ifname);
     282  	return onerr;
     283      }
     284  
     285      if((fileinfo.st_mode & S_IWOTH)
     286         || !S_ISREG(fileinfo.st_mode)) {
     287  	/* If the file is world writable or is not a
     288  	   normal file, return error */
     289  	pam_syslog(pamh,LOG_ERR,
     290  		 "%s is either world writable or not a normal file",
     291  		 ifname);
     292  	free(ifname);
     293  	return PAM_AUTH_ERR;
     294      }
     295  
     296      inf = fopen(ifname,"r");
     297      if(inf == NULL) { /* Check that we opened it successfully */
     298  	if (onerr == PAM_SERVICE_ERR) {
     299  	    /* Only report if it's an error... */
     300  	    pam_syslog(pamh,LOG_ERR,  "Error opening %s", ifname);
     301  	}
     302  	free(ifname);
     303  	return onerr;
     304      }
     305      /* There should be no more errors from here on */
     306      retval=PAM_AUTH_ERR;
     307      /* This loop assumes that PAM_SUCCESS == 0
     308         and PAM_AUTH_ERR != 0 */
     309  #ifdef PAM_DEBUG
     310      assert(PAM_SUCCESS == 0);
     311      assert(PAM_AUTH_ERR != 0);
     312  #endif
     313      while((fgets(aline,sizeof(aline),inf) != NULL)
     314  	  && retval) {
     315  	const char *a = aline;
     316  
     317  	if(strlen(aline) == 0)
     318  	    continue;
     319  	if(aline[strlen(aline) - 1] == '\n')
     320  	    aline[strlen(aline) - 1] = '\0';
     321  	if(strlen(aline) == 0)
     322  	    continue;
     323  	if(aline[strlen(aline) - 1] == '\r')
     324  	    aline[strlen(aline) - 1] = '\0';
     325  	if(citem == PAM_TTY) {
     326  	    const char *str = pam_str_skip_prefix(a, "/dev/");
     327  	    if (str != NULL)
     328  		a = str;
     329  	}
     330  	if (extitem == EI_GROUP) {
     331  	    retval = !pam_modutil_user_in_group_nam_nam(pamh,
     332  		citemp, aline);
     333  	} else {
     334  	    retval = strcmp(a, citemp);
     335  	}
     336      }
     337  
     338      fclose(inf);
     339      free(ifname);
     340      if ((sense && retval) || (!sense && !retval)) {
     341  #ifdef PAM_DEBUG
     342  	pam_syslog(pamh,LOG_INFO,
     343  		 "Returning PAM_SUCCESS, retval = %d", retval);
     344  #endif
     345  	return PAM_SUCCESS;
     346      }
     347      else {
     348  	const void *service;
     349  	const char *user_name;
     350  #ifdef PAM_DEBUG
     351  	pam_syslog(pamh,LOG_INFO,
     352  		 "Returning PAM_AUTH_ERR, retval = %d", retval);
     353  #endif
     354  	(void) pam_get_item(pamh, PAM_SERVICE, &service);
     355  	(void) pam_get_user(pamh, &user_name, NULL);
     356  	if (!quiet)
     357  	    pam_syslog (pamh, LOG_NOTICE, "Refused user %s for service %s",
     358  	                user_name, (const char *)service);
     359  	return PAM_AUTH_ERR;
     360      }
     361  }
     362  
     363  int
     364  pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
     365  		int argc UNUSED, const char **argv UNUSED)
     366  {
     367      return PAM_SUCCESS;
     368  }
     369  
     370  int
     371  pam_sm_acct_mgmt (pam_handle_t *pamh, int flags,
     372  		  int argc, const char **argv)
     373  {
     374      return pam_sm_authenticate(pamh, flags, argc, argv);
     375  }
     376  
     377  int
     378  pam_sm_open_session (pam_handle_t *pamh, int flags,
     379  		     int argc, const char **argv)
     380  {
     381      return pam_sm_authenticate(pamh, flags, argc, argv);
     382  }
     383  
     384  int
     385  pam_sm_close_session (pam_handle_t *pamh, int flags,
     386  		      int argc, const char **argv)
     387  {
     388      return pam_sm_authenticate(pamh, flags, argc, argv);
     389  }
     390  
     391  int
     392  pam_sm_chauthtok (pam_handle_t *pamh, int flags,
     393  		  int argc, const char **argv)
     394  {
     395      return pam_sm_authenticate(pamh, flags, argc, argv);
     396  }