(root)/
Linux-PAM-1.5.3/
libpam/
pam_handlers.c
       1  /* pam_handlers.c -- pam config file parsing and module loading */
       2  
       3  /*
       4   * created by Marc Ewing.
       5   * Currently maintained by Andrew G. Morgan <morgan@kernel.org>
       6   *
       7   */
       8  
       9  #include "pam_private.h"
      10  #include "pam_inline.h"
      11  
      12  #include <stdlib.h>
      13  #include <stdio.h>
      14  #include <string.h>
      15  #include <sys/types.h>
      16  #include <sys/stat.h>
      17  #include <fcntl.h>
      18  #include <unistd.h>
      19  
      20  #define BUF_SIZE                  1024
      21  #define MODULE_CHUNK              4
      22  #define UNKNOWN_MODULE       "<*unknown module*>"
      23  #ifndef _PAM_ISA
      24  #define _PAM_ISA "."
      25  #endif
      26  
      27  static int _pam_assemble_line(FILE *f, char *buf, int buf_len);
      28  
      29  static void _pam_free_handlers_aux(struct handler **hp);
      30  
      31  static int _pam_add_handler(pam_handle_t *pamh
      32  		     , int must_fail, int other, int stack_level, int type
      33  		     , int *actions, const char *mod_path
      34  		     , int argc, char **argv, int argvlen);
      35  
      36  /* Values for module type */
      37  
      38  #define PAM_T_ANY     0
      39  #define PAM_T_AUTH    1
      40  #define PAM_T_SESS    2
      41  #define PAM_T_ACCT    4
      42  #define PAM_T_PASS    8
      43  
      44  static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
      45  				, const char *service /* specific file */
      46  				, int module_type /* specific type */
      47  				, int stack_level /* level of substack */
      48  #ifdef PAM_READ_BOTH_CONFS
      49  				, int not_other
      50  #endif /* PAM_READ_BOTH_CONFS */
      51      );
      52  
      53  static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
      54  				, const char *known_service /* specific file */
      55  				, int requested_module_type /* specific type */
      56  				, int stack_level /* level of substack */
      57  #ifdef PAM_READ_BOTH_CONFS
      58  				, int not_other
      59  #endif /* PAM_READ_BOTH_CONFS */
      60      )
      61  {
      62      char buf[BUF_SIZE];
      63      int x;                    /* read a line from the FILE *f ? */
      64      /*
      65       * read a line from the configuration (FILE *) f
      66       */
      67      while ((x = _pam_assemble_line(f, buf, BUF_SIZE)) > 0) {
      68  	char *tok, *nexttok=NULL;
      69  	const char *this_service;
      70  	const char *mod_path;
      71  	int module_type, actions[_PAM_RETURN_VALUES];
      72  	int other;            /* set if module is for PAM_DEFAULT_SERVICE */
      73  	int res;              /* module added successfully? */
      74  	int handler_type = PAM_HT_MODULE; /* regular handler from a module */
      75  	int argc;
      76  	char **argv;
      77  	int argvlen;
      78  
      79  	D(("_pam_init_handler: LINE: %s", buf));
      80  	if (known_service != NULL) {
      81  	    nexttok = buf;
      82  	    /* No service field: all lines are for the known service. */
      83  	    this_service = known_service;
      84  	} else {
      85  	    this_service = tok = _pam_StrTok(buf, " \n\t", &nexttok);
      86  	}
      87  
      88  #ifdef PAM_READ_BOTH_CONFS
      89  	if (not_other)
      90  	    other = 0;
      91  	else
      92  #endif /* PAM_READ_BOTH_CONFS */
      93  	other = !strcasecmp(this_service, PAM_DEFAULT_SERVICE);
      94  
      95  	/* accept "service name" or PAM_DEFAULT_SERVICE modules */
      96  	if (!strcasecmp(this_service, pamh->service_name) || other) {
      97  	    int pam_include = 0;
      98  	    int substack = 0;
      99  
     100  	    /* This is a service we are looking for */
     101  	    D(("_pam_init_handlers: Found PAM config entry for: %s"
     102  	       , this_service));
     103  
     104  	    tok = _pam_StrTok(NULL, " \n\t", &nexttok);
     105  	    if (tok == NULL) {
     106  	        /* module type does not exist */
     107  	        D(("_pam_init_handlers: empty module type for %s", this_service));
     108  	        pam_syslog(pamh, LOG_ERR,
     109  			   "(%s) empty module type", this_service);
     110  	        module_type = (requested_module_type != PAM_T_ANY) ?
     111  		  requested_module_type : PAM_T_AUTH;	/* most sensitive */
     112  	        handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
     113  	    } else {
     114  		if (tok[0] == '-') { /* do not log module load errors */
     115  		    handler_type = PAM_HT_SILENT_MODULE;
     116  		    ++tok;
     117  		}
     118  		if (!strcasecmp("auth", tok)) {
     119  		    module_type = PAM_T_AUTH;
     120  		} else if (!strcasecmp("session", tok)) {
     121  		    module_type = PAM_T_SESS;
     122  		} else if (!strcasecmp("account", tok)) {
     123  		    module_type = PAM_T_ACCT;
     124  		} else if (!strcasecmp("password", tok)) {
     125  		    module_type = PAM_T_PASS;
     126  		} else {
     127  		    /* Illegal module type */
     128  		    D(("_pam_init_handlers: bad module type: %s", tok));
     129  		    pam_syslog(pamh, LOG_ERR, "(%s) illegal module type: %s",
     130  			    this_service, tok);
     131  		    module_type = (requested_module_type != PAM_T_ANY) ?
     132  			    requested_module_type : PAM_T_AUTH;	/* most sensitive */
     133  		    handler_type = PAM_HT_MUST_FAIL; /* install as normal but fail when dispatched */
     134  		}
     135  	    }
     136  	    D(("Using %s config entry: %s", handler_type?"BAD ":"", tok));
     137  	    if (requested_module_type != PAM_T_ANY &&
     138  	        module_type != requested_module_type) {
     139  		D(("Skipping config entry: %s (requested=%d, found=%d)",
     140  		   tok, requested_module_type, module_type));
     141  		continue;
     142  	    }
     143  
     144  	    /* reset the actions to .._UNDEF's -- this is so that
     145                 we can work out which entries are not yet set (for default). */
     146  	    {
     147  		int i;
     148  		for (i=0; i<_PAM_RETURN_VALUES;
     149  		     actions[i++] = _PAM_ACTION_UNDEF);
     150  	    }
     151  	    tok = _pam_StrTok(NULL, " \n\t", &nexttok);
     152  	    if (tok == NULL) {
     153  		/* no module name given */
     154  		D(("_pam_init_handlers: no control flag supplied"));
     155  		pam_syslog(pamh, LOG_ERR,
     156  			   "(%s) no control flag supplied", this_service);
     157  		_pam_set_default_control(actions, _PAM_ACTION_BAD);
     158  		handler_type = PAM_HT_MUST_FAIL;
     159  	    } else if (!strcasecmp("required", tok)) {
     160  		D(("*PAM_F_REQUIRED*"));
     161  		actions[PAM_SUCCESS] = _PAM_ACTION_OK;
     162  		actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
     163                  actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
     164  		_pam_set_default_control(actions, _PAM_ACTION_BAD);
     165  	    } else if (!strcasecmp("requisite", tok)) {
     166  		D(("*PAM_F_REQUISITE*"));
     167  		actions[PAM_SUCCESS] = _PAM_ACTION_OK;
     168  		actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
     169                  actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
     170  		_pam_set_default_control(actions, _PAM_ACTION_DIE);
     171  	    } else if (!strcasecmp("optional", tok)) {
     172  		D(("*PAM_F_OPTIONAL*"));
     173  		actions[PAM_SUCCESS] = _PAM_ACTION_OK;
     174  		actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
     175  		_pam_set_default_control(actions, _PAM_ACTION_IGNORE);
     176  	    } else if (!strcasecmp("sufficient", tok)) {
     177  		D(("*PAM_F_SUFFICIENT*"));
     178  		actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
     179  		actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
     180  		_pam_set_default_control(actions, _PAM_ACTION_IGNORE);
     181  	    } else if (!strcasecmp("include", tok)) {
     182  		D(("*PAM_F_INCLUDE*"));
     183  		pam_include = 1;
     184  		substack = 0;
     185  	    } else if (!strcasecmp("substack", tok)) {
     186  		D(("*PAM_F_SUBSTACK*"));
     187  		pam_include = 1;
     188  		substack = 1;
     189  	    } else {
     190  		D(("will need to parse %s", tok));
     191  		_pam_parse_control(actions, tok);
     192  		/* by default the default is to treat as failure */
     193  		_pam_set_default_control(actions, _PAM_ACTION_BAD);
     194  	    }
     195  
     196  	    tok = _pam_StrTok(NULL, " \n\t", &nexttok);
     197  	    if (pam_include) {
     198  		if (substack) {
     199  		    res = _pam_add_handler(pamh, PAM_HT_SUBSTACK, other,
     200  				stack_level, module_type, actions, tok,
     201  				0, NULL, 0);
     202  		    if (res != PAM_SUCCESS) {
     203  			pam_syslog(pamh, LOG_ERR, "error adding substack %s", tok);
     204  			D(("failed to load module - aborting"));
     205  			return PAM_ABORT;
     206  		    }
     207  		}
     208  		if (_pam_load_conf_file(pamh, tok, this_service, module_type,
     209  		    stack_level + substack
     210  #ifdef PAM_READ_BOTH_CONFS
     211  					      , !other
     212  #endif /* PAM_READ_BOTH_CONFS */
     213  		    ) == PAM_SUCCESS)
     214  		    continue;
     215  		_pam_set_default_control(actions, _PAM_ACTION_BAD);
     216  		mod_path = NULL;
     217  		handler_type = PAM_HT_MUST_FAIL;
     218  		nexttok = NULL;
     219  	    } else if (tok != NULL) {
     220  		mod_path = tok;
     221  		D(("mod_path = %s",mod_path));
     222  	    } else {
     223  		/* no module name given */
     224  		D(("_pam_init_handlers: no module name supplied"));
     225  		pam_syslog(pamh, LOG_ERR,
     226  		           "(%s) no module name supplied", this_service);
     227  		mod_path = NULL;
     228  		handler_type = PAM_HT_MUST_FAIL;
     229  	    }
     230  
     231  	    /* nexttok points to remaining arguments... */
     232  
     233  	    if (nexttok != NULL) {
     234  		D(("list: %s",nexttok));
     235  	        argvlen = _pam_mkargv(nexttok, &argv, &argc);
     236  		D(("argvlen = %d",argvlen));
     237  	    } else {               /* there are no arguments so fix by hand */
     238  		D(("_pam_init_handlers: empty argument list"));
     239  		argvlen = argc = 0;
     240  		argv = NULL;
     241  	    }
     242  
     243  #ifdef PAM_DEBUG
     244  	    {
     245  		int y;
     246  
     247  		D(("CONF%s: %s%s %d %s %d"
     248  		   , handler_type==PAM_HT_MUST_FAIL?"<*will fail*>":""
     249  		   , this_service, other ? "(backup)":""
     250  		   , module_type
     251  		   , mod_path, argc));
     252  		for (y = 0; y < argc; y++) {
     253  		    D(("CONF: %s", argv[y]));
     254  		}
     255  		for (y = 0; y<_PAM_RETURN_VALUES; ++y) {
     256  		    D(("RETURN %s(%d) -> %d %s",
     257  		       _pam_token_returns[y], y, actions[y],
     258  		       actions[y]>0 ? "jump":
     259  			_pam_token_actions[-actions[y]]));
     260  		}
     261  	    }
     262  #endif
     263  
     264  	    res = _pam_add_handler(pamh, handler_type, other, stack_level
     265  				   , module_type, actions, mod_path
     266  				   , argc, argv, argvlen);
     267  	    if (res != PAM_SUCCESS) {
     268  		pam_syslog(pamh, LOG_ERR, "error loading %s", mod_path);
     269  		D(("failed to load module - aborting"));
     270  		return PAM_ABORT;
     271  	    }
     272  	}
     273      }
     274  
     275      return ( (x < 0) ? PAM_ABORT:PAM_SUCCESS );
     276  }
     277  
     278  static int
     279  _pam_open_config_file(pam_handle_t *pamh
     280  			, const char *service
     281  			, char **path
     282  			, FILE **file)
     283  {
     284      const char *const pamd_dirs[] = { PAM_CONFIG_DF, PAM_CONFIG_DIST_DF
     285  #ifdef VENDORDIR
     286                                 , PAM_CONFIG_DIST2_DF
     287  #endif
     288      };
     289      char *p = NULL;
     290      FILE *f;
     291      size_t i;
     292  
     293      /* Absolute path */
     294      if (service[0] == '/') {
     295  	p = _pam_strdup(service);
     296  	if (p == NULL) {
     297  	    pam_syslog(pamh, LOG_CRIT, "strdup failed");
     298  	    return PAM_BUF_ERR;
     299  	}
     300      } else if (pamh->confdir != NULL) {
     301          if (asprintf (&p, "%s/%s", pamh->confdir, service) < 0) {
     302  	    pam_syslog(pamh, LOG_CRIT, "asprintf failed");
     303  	    return PAM_BUF_ERR;
     304  	}
     305      }
     306  
     307      if (p != NULL) {
     308  	D(("opening %s", p));
     309  	f = fopen(p, "r");
     310  	if (f != NULL) {
     311  	    *path = p;
     312  	    *file = f;
     313  	    return PAM_SUCCESS;
     314  	}
     315  	_pam_drop(p);
     316  	return PAM_ABORT;
     317      }
     318  
     319      for (i = 0; i < PAM_ARRAY_SIZE(pamd_dirs); i++) {
     320  	DIAG_PUSH_IGNORE_FORMAT_NONLITERAL
     321  	if (asprintf (&p, pamd_dirs[i], service) < 0) {
     322  	    pam_syslog(pamh, LOG_CRIT, "asprintf failed");
     323  	    return PAM_BUF_ERR;
     324  	}
     325  	DIAG_POP_IGNORE_FORMAT_NONLITERAL
     326  
     327  	D(("opening %s", p));
     328  	f = fopen(p, "r");
     329  	if (f != NULL) {
     330  	    *path = p;
     331  	    *file = f;
     332  	    return PAM_SUCCESS;
     333  	}
     334  	_pam_drop(p);
     335      }
     336  
     337      return PAM_ABORT;
     338  }
     339  
     340  static int _pam_load_conf_file(pam_handle_t *pamh, const char *config_name
     341  				, const char *service /* specific file */
     342  				, int module_type /* specific type */
     343  				, int stack_level /* level of substack */
     344  #ifdef PAM_READ_BOTH_CONFS
     345  				, int not_other
     346  #endif /* PAM_READ_BOTH_CONFS */
     347      )
     348  {
     349      FILE *f;
     350      char *path = NULL;
     351      int retval = PAM_ABORT;
     352  
     353      D(("_pam_load_conf_file called"));
     354  
     355      if (stack_level >= PAM_SUBSTACK_MAX_LEVEL) {
     356  	D(("maximum level of substacks reached"));
     357  	pam_syslog(pamh, LOG_ERR, "maximum level of substacks reached");
     358  	return PAM_ABORT;
     359      }
     360  
     361      if (config_name == NULL) {
     362  	D(("no config file supplied"));
     363  	pam_syslog(pamh, LOG_ERR, "(%s) no config name supplied", service);
     364  	return PAM_ABORT;
     365      }
     366  
     367      if (_pam_open_config_file(pamh, config_name, &path, &f) == PAM_SUCCESS) {
     368  	retval = _pam_parse_conf_file(pamh, f, service, module_type, stack_level
     369  #ifdef PAM_READ_BOTH_CONFS
     370  					      , not_other
     371  #endif /* PAM_READ_BOTH_CONFS */
     372  	    );
     373  	if (retval != PAM_SUCCESS)
     374  	    pam_syslog(pamh, LOG_ERR,
     375  		       "_pam_load_conf_file: error reading %s: %s",
     376  		       path, pam_strerror(pamh, retval));
     377  	_pam_drop(path);
     378  	fclose(f);
     379      } else {
     380  	D(("unable to open %s", config_name));
     381  	pam_syslog(pamh, LOG_ERR,
     382  		   "_pam_load_conf_file: unable to open config for %s",
     383  		   config_name);
     384      }
     385  
     386      return retval;
     387  }
     388  
     389  /* Parse config file, allocate handler structures, dlopen() */
     390  int _pam_init_handlers(pam_handle_t *pamh)
     391  {
     392      FILE *f;
     393      int retval;
     394  
     395      D(("_pam_init_handlers called"));
     396      IF_NO_PAMH("_pam_init_handlers",pamh,PAM_SYSTEM_ERR);
     397  
     398      /* Return immediately if everything is already loaded */
     399      if (pamh->handlers.handlers_loaded) {
     400  	return PAM_SUCCESS;
     401      }
     402  
     403      D(("_pam_init_handlers: initializing"));
     404  
     405      /* First clean the service structure */
     406  
     407      _pam_free_handlers(pamh);
     408      if (! pamh->handlers.module) {
     409  	if ((pamh->handlers.module =
     410  	     malloc(MODULE_CHUNK * sizeof(struct loaded_module))) == NULL) {
     411  	    pam_syslog(pamh, LOG_CRIT,
     412  		       "_pam_init_handlers: no memory loading module");
     413  	    return PAM_BUF_ERR;
     414  	}
     415  	pamh->handlers.modules_allocated = MODULE_CHUNK;
     416  	pamh->handlers.modules_used = 0;
     417      }
     418  
     419      if (pamh->service_name == NULL) {
     420  	return PAM_BAD_ITEM;                /* XXX - better error? */
     421      }
     422  
     423  #ifdef PAM_LOCKING
     424      /* Is the PAM subsystem locked? */
     425      {
     426  	 int fd_tmp;
     427  
     428  	 if ((fd_tmp = open( PAM_LOCK_FILE, O_RDONLY )) != -1) {
     429  	     pam_syslog(pamh, LOG_ERR,
     430  			"_pam_init_handlers: PAM lockfile ("
     431  			PAM_LOCK_FILE ") exists - aborting");
     432  	      (void) close(fd_tmp);
     433  	      /*
     434  	       * to avoid swamping the system with requests
     435  	       */
     436  	      _pam_start_timer(pamh);
     437  	      pam_fail_delay(pamh, 5000000);
     438  	      _pam_await_timer(pamh, PAM_ABORT);
     439  
     440  	      return PAM_ABORT;
     441  	 }
     442      }
     443  #endif /* PAM_LOCKING */
     444  
     445      /*
     446       * Now parse the config file(s) and add handlers
     447       */
     448      {
     449  	struct stat test_d;
     450  
     451  	/* Is there a PAM_CONFIG_D directory? */
     452  	if (pamh->confdir != NULL ||
     453  	    (stat(PAM_CONFIG_D, &test_d) == 0 && S_ISDIR(test_d.st_mode)) ||
     454  	    (stat(PAM_CONFIG_DIST_D, &test_d) == 0 && S_ISDIR(test_d.st_mode))
     455  #ifdef PAM_CONFIG_DIST2_D
     456  	    || (stat(PAM_CONFIG_DIST2_D, &test_d) == 0
     457  		&& S_ISDIR(test_d.st_mode))
     458  #endif
     459  	   ) {
     460  	    char *path = NULL;
     461  	    int read_something=0;
     462  
     463  	    if (_pam_open_config_file(pamh, pamh->service_name, &path, &f) == PAM_SUCCESS) {
     464  		retval = _pam_parse_conf_file(pamh, f, pamh->service_name,
     465  		    PAM_T_ANY, 0
     466  #ifdef PAM_READ_BOTH_CONFS
     467  					      , 0
     468  #endif /* PAM_READ_BOTH_CONFS */
     469  		    );
     470  		if (retval != PAM_SUCCESS) {
     471  		    pam_syslog(pamh, LOG_ERR,
     472  				    "_pam_init_handlers: error reading %s",
     473  				    path);
     474  		    pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: [%s]",
     475  				    pam_strerror(pamh, retval));
     476  		} else {
     477  		    read_something = 1;
     478  		}
     479  		_pam_drop(path);
     480  		fclose(f);
     481  	    } else {
     482  		D(("unable to open configuration for %s", pamh->service_name));
     483  #ifdef PAM_READ_BOTH_CONFS
     484  		D(("checking %s", PAM_CONFIG));
     485  
     486  		if (pamh->confdir == NULL
     487  		    && (f = fopen(PAM_CONFIG,"r")) != NULL) {
     488  		    retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0, 1);
     489  		    fclose(f);
     490  		} else
     491  #endif /* PAM_READ_BOTH_CONFS */
     492  		retval = PAM_SUCCESS;
     493  		/*
     494  		 * XXX - should we log an error? Some people want to always
     495  		 * use "other"
     496  		 */
     497  	    }
     498  
     499  	    if (retval == PAM_SUCCESS) {
     500  		/* now parse the PAM_DEFAULT_SERVICE */
     501  
     502  		if (_pam_open_config_file(pamh, PAM_DEFAULT_SERVICE, &path, &f) == PAM_SUCCESS) {
     503  		    /* would test magic here? */
     504  		    retval = _pam_parse_conf_file(pamh, f, PAM_DEFAULT_SERVICE,
     505  			PAM_T_ANY, 0
     506  #ifdef PAM_READ_BOTH_CONFS
     507  						  , 0
     508  #endif /* PAM_READ_BOTH_CONFS */
     509  			);
     510  		    if (retval != PAM_SUCCESS) {
     511  			pam_syslog(pamh, LOG_ERR,
     512  					"_pam_init_handlers: error reading %s",
     513  					path);
     514  			pam_syslog(pamh, LOG_ERR,
     515  					"_pam_init_handlers: [%s]",
     516  					pam_strerror(pamh, retval));
     517  		    } else {
     518  			read_something = 1;
     519  		    }
     520  		    _pam_drop(path);
     521  		    fclose(f);
     522  		} else {
     523  		    D(("unable to open %s", PAM_DEFAULT_SERVICE));
     524  		    pam_syslog(pamh, LOG_ERR,
     525  				    "_pam_init_handlers: no default config %s",
     526  				    PAM_DEFAULT_SERVICE);
     527  		}
     528  		if (!read_something) {          /* nothing read successfully */
     529  		    retval = PAM_ABORT;
     530  		}
     531  	    }
     532  	} else {
     533  	    if ((f = fopen(PAM_CONFIG, "r")) == NULL) {
     534  		pam_syslog(pamh, LOG_ERR, "_pam_init_handlers: could not open "
     535  				PAM_CONFIG );
     536  		return PAM_ABORT;
     537  	    }
     538  
     539  	    retval = _pam_parse_conf_file(pamh, f, NULL, PAM_T_ANY, 0
     540  #ifdef PAM_READ_BOTH_CONFS
     541  					  , 0
     542  #endif /* PAM_READ_BOTH_CONFS */
     543  		);
     544  
     545  	    D(("closing configuration file"));
     546  	    fclose(f);
     547  	}
     548      }
     549  
     550      if (retval != PAM_SUCCESS) {
     551  	/* Read error */
     552  	pam_syslog(pamh, LOG_ERR, "error reading PAM configuration file");
     553  	return PAM_ABORT;
     554      }
     555  
     556      pamh->handlers.handlers_loaded = 1;
     557  
     558      D(("_pam_init_handlers exiting"));
     559      return PAM_SUCCESS;
     560  }
     561  
     562  /*
     563   * This is where we read a line of the PAM config file. The line may be
     564   * preceded by lines of comments and also extended with "\\\n"
     565   */
     566  
     567  static int _pam_assemble_line(FILE *f, char *buffer, int buf_len)
     568  {
     569      char *p = buffer;
     570      char *endp = buffer + buf_len;
     571      char *s, *os;
     572      int used = 0;
     573  
     574      /* loop broken with a 'break' when a non-'\\n' ended line is read */
     575  
     576      D(("called."));
     577      for (;;) {
     578  	if (p >= endp) {
     579  	    /* Overflow */
     580  	    D(("_pam_assemble_line: overflow"));
     581  	    return -1;
     582  	}
     583  	if (fgets(p, endp - p, f) == NULL) {
     584  	    if (used) {
     585  		/* Incomplete read */
     586  		return -1;
     587  	    } else {
     588  		/* EOF */
     589  		return 0;
     590  	    }
     591  	}
     592  
     593  	/* skip leading spaces --- line may be blank */
     594  
     595  	s = p + strspn(p, " \n\t");
     596  	if (*s && (*s != '#')) {
     597  	    os = s;
     598  
     599  	    /*
     600  	     * we are only interested in characters before the first '#'
     601  	     * character
     602  	     */
     603  
     604  	    while (*s && *s != '#')
     605  		 ++s;
     606  	    if (*s == '#') {
     607  		 *s = '\0';
     608  		 used += strlen(os);
     609  		 break;                /* the line has been read */
     610  	    }
     611  
     612  	    s = os;
     613  
     614  	    /*
     615  	     * Check for backslash by scanning back from the end of
     616  	     * the entered line, the '\n' has been included since
     617  	     * normally a line is terminated with this
     618  	     * character. fgets() should only return one though!
     619  	     */
     620  
     621  	    s += strlen(s);
     622  	    while (s > os && ((*--s == ' ') || (*s == '\t')
     623  			      || (*s == '\n')));
     624  
     625  	    /* check if it ends with a backslash */
     626  	    if (*s == '\\') {
     627  		*s++ = ' ';             /* replace backslash with ' ' */
     628  		*s = '\0';              /* truncate the line here */
     629  		used += strlen(os);
     630  		p = s;                  /* there is more ... */
     631  	    } else {
     632  		/* End of the line! */
     633  		used += strlen(os);
     634  		break;                  /* this is the complete line */
     635  	    }
     636  
     637  	} else {
     638  	    /* Nothing in this line */
     639  	    /* Don't move p         */
     640  	}
     641      }
     642  
     643      return used;
     644  }
     645  
     646  static char *
     647  extract_modulename(const char *mod_path)
     648  {
     649    const char *p = strrchr (mod_path, '/');
     650    char *dot, *retval;
     651  
     652    if (p == NULL)
     653      p = mod_path;
     654    else
     655      p++;
     656  
     657    if ((retval = _pam_strdup (p)) == NULL)
     658      return NULL;
     659  
     660    dot = strrchr (retval, '.');
     661    if (dot)
     662      *dot = '\0';
     663  
     664    if (*retval == '\0' || strcmp(retval, "?") == 0) {
     665      /* do not allow empty module name or "?" to avoid confusing audit trail */
     666      _pam_drop(retval);
     667      return NULL;
     668    }
     669  
     670    return retval;
     671  }
     672  
     673  static struct loaded_module *
     674  _pam_load_module(pam_handle_t *pamh, const char *mod_path, int handler_type)
     675  {
     676      int x = 0;
     677      int success;
     678      struct loaded_module *mod;
     679  
     680      D(("_pam_load_module: loading module `%s'", mod_path));
     681  
     682      mod = pamh->handlers.module;
     683  
     684      /* First, ensure the module is loaded */
     685      while (x < pamh->handlers.modules_used) {
     686  	if (!strcmp(mod[x].name, mod_path)) {  /* case sensitive ! */
     687  	    break;
     688  	}
     689  	x++;
     690      }
     691      if (x == pamh->handlers.modules_used) {
     692  	/* Not found */
     693  	if (pamh->handlers.modules_allocated == pamh->handlers.modules_used) {
     694  	    /* will need more memory */
     695  	    void *tmp = realloc(pamh->handlers.module,
     696                                 (pamh->handlers.modules_allocated+MODULE_CHUNK)
     697                                 *sizeof(struct loaded_module));
     698  	    if (tmp == NULL) {
     699  		D(("cannot enlarge module pointer memory"));
     700  		pam_syslog(pamh, LOG_CRIT,
     701  				"realloc returned NULL in _pam_load_module");
     702  		return NULL;
     703  	    }
     704  	    pamh->handlers.module = tmp;
     705  	    pamh->handlers.modules_allocated += MODULE_CHUNK;
     706  	}
     707  	mod = &(pamh->handlers.module[x]);
     708  	/* Be pessimistic... */
     709  	success = PAM_ABORT;
     710  
     711  	D(("_pam_load_module: _pam_dlopen(%s)", mod_path));
     712  	mod->dl_handle = _pam_dlopen(mod_path);
     713  	D(("_pam_load_module: _pam_dlopen'ed"));
     714  	D(("_pam_load_module: dlopen'ed"));
     715  	if (mod->dl_handle == NULL) {
     716  	    const char *isa = strstr(mod_path, "$ISA");
     717  	    size_t isa_len = strlen("$ISA");
     718  
     719  	    if (isa != NULL) {
     720  		size_t pam_isa_len = strlen(_PAM_ISA);
     721  		char *mod_full_isa_path =
     722  			malloc(strlen(mod_path) - isa_len + pam_isa_len + 1);
     723  
     724  		if (mod_full_isa_path == NULL) {
     725  		    D(("_pam_load_module: couldn't get memory for mod_path"));
     726  		    pam_syslog(pamh, LOG_CRIT, "no memory for module path");
     727  		    success = PAM_ABORT;
     728  		} else {
     729  		    char *p = mod_full_isa_path;
     730  
     731  		    memcpy(p, mod_path, isa - mod_path);
     732  		    p += isa - mod_path;
     733  		    memcpy(p, _PAM_ISA, pam_isa_len);
     734  		    p += pam_isa_len;
     735  		    strcpy(p, isa + isa_len);
     736  
     737  		    mod->dl_handle = _pam_dlopen(mod_full_isa_path);
     738  		    _pam_drop(mod_full_isa_path);
     739  		}
     740  	    }
     741  	}
     742  	if (mod->dl_handle == NULL) {
     743  	    D(("_pam_load_module: _pam_dlopen(%s) failed", mod_path));
     744  	    if (handler_type != PAM_HT_SILENT_MODULE)
     745  		pam_syslog(pamh, LOG_ERR, "unable to dlopen(%s): %s", mod_path,
     746  		    _pam_dlerror());
     747  	    /* Don't abort yet; static code may be able to find function.
     748  	     * But defaults to abort if nothing found below... */
     749  	} else {
     750  	    D(("module added successfully"));
     751  	    success = PAM_SUCCESS;
     752  	    mod->type = PAM_MT_DYNAMIC_MOD;
     753  	    pamh->handlers.modules_used++;
     754  	}
     755  
     756  	if (success != PAM_SUCCESS) {	         /* add a malformed module */
     757  	    mod->dl_handle = NULL;
     758  	    mod->type = PAM_MT_FAULTY_MOD;
     759  	    pamh->handlers.modules_used++;
     760  	    if (handler_type != PAM_HT_SILENT_MODULE)
     761  		pam_syslog(pamh, LOG_ERR, "adding faulty module: %s", mod_path);
     762  	    success = PAM_SUCCESS;  /* We have successfully added a module */
     763  	}
     764  
     765  	/* indicate its name - later we will search for it by this */
     766  	if ((mod->name = _pam_strdup(mod_path)) == NULL) {
     767  	    D(("_pam_load_module: couldn't get memory for mod_path"));
     768  	    pam_syslog(pamh, LOG_CRIT, "no memory for module path");
     769  	    success = PAM_ABORT;
     770  	}
     771  
     772      } else {                           /* x != pamh->handlers.modules_used */
     773  	mod += x;                                    /* the located module */
     774  	success = PAM_SUCCESS;
     775      }
     776      return success == PAM_SUCCESS ? mod : NULL;
     777  }
     778  
     779  int _pam_add_handler(pam_handle_t *pamh
     780  		     , int handler_type, int other, int stack_level, int type
     781  		     , int *actions, const char *mod_path
     782  		     , int argc, char **argv, int argvlen)
     783  {
     784      struct loaded_module *mod = NULL;
     785      struct handler **handler_p;
     786      struct handler **handler_p2;
     787      struct handlers *the_handlers;
     788      const char *sym, *sym2;
     789      char *mod_full_path;
     790      servicefn func, func2;
     791      int mod_type = PAM_MT_FAULTY_MOD;
     792  
     793      D(("called."));
     794      IF_NO_PAMH("_pam_add_handler",pamh,PAM_SYSTEM_ERR);
     795  
     796      D(("_pam_add_handler: adding type %d, handler_type %d, module `%s'",
     797  	type, handler_type, mod_path));
     798  
     799      if ((handler_type == PAM_HT_MODULE || handler_type == PAM_HT_SILENT_MODULE) &&
     800  	mod_path != NULL) {
     801  	if (mod_path[0] == '/') {
     802  	    mod = _pam_load_module(pamh, mod_path, handler_type);
     803  	} else if (asprintf(&mod_full_path, "%s%s",
     804  			     DEFAULT_MODULE_PATH, mod_path) >= 0) {
     805  	    mod = _pam_load_module(pamh, mod_full_path, handler_type);
     806  	    _pam_drop(mod_full_path);
     807  	} else {
     808  	    pam_syslog(pamh, LOG_CRIT, "cannot malloc full mod path");
     809  	    return PAM_ABORT;
     810  	}
     811  
     812  	if (mod == NULL) {
     813  	    /* if we get here with NULL it means allocation error */
     814  	    return PAM_ABORT;
     815  	}
     816  
     817  	mod_type = mod->type;
     818      }
     819  
     820      if (mod_path == NULL)
     821  	mod_path = UNKNOWN_MODULE;
     822  
     823      /*
     824       * At this point 'mod' points to the stored/loaded module.
     825       */
     826  
     827      /* Now define the handler(s) based on mod->dlhandle and type */
     828  
     829      /* decide which list of handlers to use */
     830      the_handlers = (other) ? &pamh->handlers.other : &pamh->handlers.conf;
     831  
     832      handler_p = handler_p2 = NULL;
     833      func = func2 = NULL;
     834      sym2 = NULL;
     835  
     836      /* point handler_p's at the root addresses of the function stacks */
     837      switch (type) {
     838      case PAM_T_AUTH:
     839  	handler_p = &the_handlers->authenticate;
     840  	sym = "pam_sm_authenticate";
     841  	handler_p2 = &the_handlers->setcred;
     842  	sym2 = "pam_sm_setcred";
     843  	break;
     844      case PAM_T_SESS:
     845  	handler_p = &the_handlers->open_session;
     846  	sym = "pam_sm_open_session";
     847  	handler_p2 = &the_handlers->close_session;
     848  	sym2 = "pam_sm_close_session";
     849  	break;
     850      case PAM_T_ACCT:
     851  	handler_p = &the_handlers->acct_mgmt;
     852  	sym = "pam_sm_acct_mgmt";
     853  	break;
     854      case PAM_T_PASS:
     855  	handler_p = &the_handlers->chauthtok;
     856  	sym = "pam_sm_chauthtok";
     857  	break;
     858      default:
     859  	/* Illegal module type */
     860  	D(("_pam_add_handler: illegal module type %d", type));
     861  	return PAM_ABORT;
     862      }
     863  
     864      /* are the modules reliable? */
     865      if (mod_type != PAM_MT_DYNAMIC_MOD &&
     866  	 mod_type != PAM_MT_FAULTY_MOD) {
     867  	D(("_pam_add_handlers: illegal module library type; %d", mod_type));
     868  	pam_syslog(pamh, LOG_ERR,
     869  			"internal error: module library type not known: %s;%d",
     870  			sym, mod_type);
     871  	return PAM_ABORT;
     872      }
     873  
     874      /* now identify this module's functions - for non-faulty modules */
     875  
     876      if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
     877          !(func = _pam_dlsym(mod->dl_handle, sym)) ) {
     878  	pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym);
     879      }
     880      if (sym2) {
     881  	if ((mod_type == PAM_MT_DYNAMIC_MOD) &&
     882  	    !(func2 = _pam_dlsym(mod->dl_handle, sym2)) ) {
     883  	    pam_syslog(pamh, LOG_ERR, "unable to resolve symbol: %s", sym2);
     884  	}
     885      }
     886  
     887      /* here func (and perhaps func2) point to the appropriate functions */
     888  
     889      /* add new handler to end of existing list */
     890      while (*handler_p != NULL) {
     891  	handler_p = &((*handler_p)->next);
     892      }
     893  
     894      if ((*handler_p = calloc(1, sizeof(struct handler))) == NULL) {
     895  	pam_syslog(pamh, LOG_CRIT, "cannot allocate struct handler #1");
     896  	return (PAM_ABORT);
     897      }
     898  
     899      (*handler_p)->handler_type = handler_type;
     900      (*handler_p)->stack_level = stack_level;
     901      (*handler_p)->func = func;
     902      memcpy((*handler_p)->actions,actions,sizeof((*handler_p)->actions));
     903      (*handler_p)->cached_retval = _PAM_INVALID_RETVAL;
     904      (*handler_p)->cached_retval_p = &((*handler_p)->cached_retval);
     905      (*handler_p)->argc = argc;
     906      (*handler_p)->argv = argv;                       /* not a copy */
     907      if (((*handler_p)->mod_name = extract_modulename(mod_path)) == NULL)
     908  	return PAM_ABORT;
     909  
     910      /* some of the modules have a second calling function */
     911      if (handler_p2) {
     912  	/* add new handler to end of existing list */
     913  	while (*handler_p2) {
     914  	    handler_p2 = &((*handler_p2)->next);
     915  	}
     916  
     917  	if ((*handler_p2 = calloc(1, sizeof(struct handler))) == NULL) {
     918  	    pam_syslog(pamh, LOG_CRIT, "cannot allocate struct handler #2");
     919  	    return (PAM_ABORT);
     920  	}
     921  
     922  	(*handler_p2)->handler_type = handler_type;
     923  	(*handler_p2)->stack_level = stack_level;
     924  	(*handler_p2)->func = func2;
     925  	memcpy((*handler_p2)->actions,actions,sizeof((*handler_p2)->actions));
     926  	(*handler_p2)->cached_retval =  _PAM_INVALID_RETVAL;     /* ignored */
     927  	/* Note, this next entry points to the handler_p value! */
     928  	(*handler_p2)->cached_retval_p = &((*handler_p)->cached_retval);
     929  	(*handler_p2)->argc = argc;
     930  	if (argv) {
     931  	    if (((*handler_p2)->argv = malloc(argvlen)) == NULL) {
     932  		pam_syslog(pamh, LOG_CRIT, "cannot malloc argv for handler #2");
     933  		return (PAM_ABORT);
     934  	    }
     935  	    memcpy((*handler_p2)->argv, argv, argvlen);
     936  	}
     937  	if (((*handler_p2)->mod_name = extract_modulename(mod_path)) == NULL)
     938  	    return PAM_ABORT;
     939      }
     940  
     941      D(("_pam_add_handler: returning successfully"));
     942  
     943      return PAM_SUCCESS;
     944  }
     945  
     946  /* Free various allocated structures and dlclose() the libs */
     947  int _pam_free_handlers(pam_handle_t *pamh)
     948  {
     949      struct loaded_module *mod;
     950  
     951      D(("called."));
     952      IF_NO_PAMH("_pam_free_handlers",pamh,PAM_SYSTEM_ERR);
     953  
     954      mod = pamh->handlers.module;
     955  
     956      /* Close all loaded modules */
     957  
     958      while (pamh->handlers.modules_used) {
     959  	D(("_pam_free_handlers: dlclose(%s)", mod->name));
     960  	free(mod->name);
     961  	if (mod->type == PAM_MT_DYNAMIC_MOD) {
     962  	    _pam_dlclose(mod->dl_handle);
     963  	}
     964  	mod++;
     965  	pamh->handlers.modules_used--;
     966      }
     967  
     968      /* Free all the handlers */
     969  
     970      _pam_free_handlers_aux(&(pamh->handlers.conf.authenticate));
     971      _pam_free_handlers_aux(&(pamh->handlers.conf.setcred));
     972      _pam_free_handlers_aux(&(pamh->handlers.conf.acct_mgmt));
     973      _pam_free_handlers_aux(&(pamh->handlers.conf.open_session));
     974      _pam_free_handlers_aux(&(pamh->handlers.conf.close_session));
     975      _pam_free_handlers_aux(&(pamh->handlers.conf.chauthtok));
     976  
     977      _pam_free_handlers_aux(&(pamh->handlers.other.authenticate));
     978      _pam_free_handlers_aux(&(pamh->handlers.other.setcred));
     979      _pam_free_handlers_aux(&(pamh->handlers.other.acct_mgmt));
     980      _pam_free_handlers_aux(&(pamh->handlers.other.open_session));
     981      _pam_free_handlers_aux(&(pamh->handlers.other.close_session));
     982      _pam_free_handlers_aux(&(pamh->handlers.other.chauthtok));
     983  
     984      /* no more loaded modules */
     985  
     986      _pam_drop(pamh->handlers.module);
     987  
     988      /* Indicate that handlers are not initialized for this pamh */
     989  
     990      pamh->handlers.handlers_loaded = 0;
     991  
     992      return PAM_SUCCESS;
     993  }
     994  
     995  void _pam_start_handlers(pam_handle_t *pamh)
     996  {
     997      D(("called."));
     998      /* NB. There is no check for a NULL pamh here, since no return
     999       * value to communicate the fact!  */
    1000  
    1001      /* Indicate that handlers are not initialized for this pamh */
    1002      pamh->handlers.handlers_loaded = 0;
    1003  
    1004      pamh->handlers.modules_allocated = 0;
    1005      pamh->handlers.modules_used = 0;
    1006      pamh->handlers.module = NULL;
    1007  
    1008      /* initialize the .conf and .other entries */
    1009  
    1010      pamh->handlers.conf.authenticate = NULL;
    1011      pamh->handlers.conf.setcred = NULL;
    1012      pamh->handlers.conf.acct_mgmt = NULL;
    1013      pamh->handlers.conf.open_session = NULL;
    1014      pamh->handlers.conf.close_session = NULL;
    1015      pamh->handlers.conf.chauthtok = NULL;
    1016  
    1017      pamh->handlers.other.authenticate = NULL;
    1018      pamh->handlers.other.setcred = NULL;
    1019      pamh->handlers.other.acct_mgmt = NULL;
    1020      pamh->handlers.other.open_session = NULL;
    1021      pamh->handlers.other.close_session = NULL;
    1022      pamh->handlers.other.chauthtok = NULL;
    1023  }
    1024  
    1025  void _pam_free_handlers_aux(struct handler **hp)
    1026  {
    1027      struct handler *h = *hp;
    1028      struct handler *last;
    1029  
    1030      D(("called."));
    1031      while (h) {
    1032  	last = h;
    1033  	_pam_drop(h->argv);  /* This is all allocated in a single chunk */
    1034  	_pam_drop(h->mod_name);
    1035  	h = h->next;
    1036  	pam_overwrite_object(last);
    1037  	free(last);
    1038      }
    1039  
    1040      *hp = NULL;
    1041  }