(root)/
Linux-PAM-1.5.3/
libpam/
pam_env.c
       1  /*
       2   * pam_env.c
       3   *
       4   * Copyright (c) Andrew G. Morgan <morgan@parc.power.net> 1996,1997
       5   * All rights reserved.
       6   *
       7   * This file was written from a "hint" provided by the people at SUN.
       8   * and the X/Open XSSO draft of March 1997.
       9   *
      10   * $Id$
      11   */
      12  
      13  #include "pam_private.h"
      14  #include "pam_inline.h"
      15  
      16  #include <string.h>
      17  #include <stdlib.h>
      18  
      19  #ifdef sunos
      20  #define memmove(x,y,z) bcopy(y,x,z)
      21  #endif
      22  
      23  /* helper functions */
      24  
      25  #ifdef PAM_DEBUG
      26  static void _pam_dump_env(pam_handle_t *pamh)
      27  {
      28      int i;
      29  
      30      D(("Listing environment of pamh=%p", pamh));
      31      D(("pamh->env = %p", pamh->env));
      32      D(("environment entries used = %d [of %d allocated]"
      33         , pamh->env->requested, pamh->env->entries));
      34  
      35      for (i=0; i<pamh->env->requested; ++i) {
      36  	_pam_output_debug(">%-3d [%9p]:[%s]"
      37  			  , i, pamh->env->list[i], pamh->env->list[i]);
      38      }
      39      _pam_output_debug("*NOTE* the last item should be (nil)");
      40  }
      41  #else
      42  #define _pam_dump_env(x)
      43  #endif
      44  
      45  /*
      46   * Create the environment
      47   */
      48  
      49  int _pam_make_env(pam_handle_t *pamh)
      50  {
      51      D(("called."));
      52  
      53      IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
      54  
      55      /*
      56       * get structure memory
      57       */
      58  
      59      pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
      60      if (pamh->env == NULL) {
      61  	pam_syslog(pamh, LOG_CRIT, "_pam_make_env: out of memory");
      62  	return PAM_BUF_ERR;
      63      }
      64  
      65      /*
      66       * get list memory
      67       */
      68  
      69      pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
      70      if (pamh->env->list == NULL) {
      71  	pam_syslog(pamh, LOG_CRIT, "_pam_make_env: no memory for list");
      72  	_pam_drop(pamh->env);
      73  	return PAM_BUF_ERR;
      74      }
      75  
      76      /*
      77       * fill entries in pamh->env
      78       */
      79  
      80      pamh->env->entries = PAM_ENV_CHUNK;
      81      pamh->env->requested = 1;
      82      pamh->env->list[0] = NULL;
      83  
      84      _pam_dump_env(pamh);                    /* only active when debugging */
      85  
      86      return PAM_SUCCESS;
      87  }
      88  
      89  /*
      90   * purge the environment
      91   */
      92  
      93  void _pam_drop_env(pam_handle_t *pamh)
      94  {
      95      D(("called."));
      96      IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
      97  
      98      if (pamh->env != NULL) {
      99  	int i;
     100  	/* we will only purge the pamh->env->requested number of elements */
     101  
     102  	for (i=pamh->env->requested-1; i-- > 0; ) {
     103  	    D(("dropping #%3d>%s<", i, pamh->env->list[i]));
     104  	    pam_overwrite_string(pamh->env->list[i]);   /* clean */
     105  	    _pam_drop(pamh->env->list[i]);              /* forget */
     106  	}
     107  	pamh->env->requested = 0;
     108  	pamh->env->entries = 0;
     109  	_pam_drop(pamh->env->list);                     /* forget */
     110  	_pam_drop(pamh->env);                           /* forget */
     111      } else {
     112  	D(("no environment present in pamh?"));
     113      }
     114  }
     115  
     116  /*
     117   * Return the item number of the given variable = first 'length' chars
     118   * of 'name_value'. Since this is a static function, it is safe to
     119   * assume its supplied arguments are well defined.
     120   */
     121  
     122  static int _pam_search_env(const struct pam_environ *env
     123  			   , const char *name_value, int length)
     124  {
     125      int i;
     126  
     127      for (i=env->requested-1; i-- > 0; ) {
     128  	if (strncmp(name_value,env->list[i],length) == 0
     129  	    && env->list[i][length] == '=') {
     130  
     131  	    return i;                                   /* Got it! */
     132  
     133  	}
     134      }
     135  
     136      return -1;                                          /* no luck */
     137  }
     138  
     139  /*
     140   * externally visible functions
     141   */
     142  
     143  /*
     144   *  pam_putenv(): Add/replace/delete a PAM-environment variable.
     145   *
     146   *  Add/replace:
     147   *      name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
     148   *
     149   *  delete:
     150   *      name_value = "NAME"
     151   */
     152  
     153  int pam_putenv(pam_handle_t *pamh, const char *name_value)
     154  {
     155      int l2eq, item, retval;
     156  
     157      D(("called."));
     158      IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
     159  
     160      if (name_value == NULL) {
     161  	pam_syslog(pamh, LOG_ERR, "pam_putenv: no variable indicated");
     162  	return PAM_PERM_DENIED;
     163      }
     164  
     165      /*
     166       * establish if we are setting or deleting; scan for '='
     167       */
     168  
     169      for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
     170      if (l2eq <= 0) {
     171  	pam_syslog(pamh, LOG_ERR, "pam_putenv: bad variable");
     172  	return PAM_BAD_ITEM;
     173      }
     174  
     175      /*
     176       *  Look first for environment.
     177       */
     178  
     179      if (pamh->env == NULL || pamh->env->list == NULL) {
     180  	pam_syslog(pamh, LOG_ERR, "pam_putenv: no env%s found",
     181  		       pamh->env == NULL ? "":"-list");
     182  	return PAM_ABORT;
     183      }
     184  
     185      /* find the item to replace */
     186  
     187      item = _pam_search_env(pamh->env, name_value, l2eq);
     188  
     189      if (name_value[l2eq]) {                     /* (re)setting */
     190  
     191  	if (item == -1) {                      /* new variable */
     192  	    D(("adding item: %s", name_value));
     193  	    /* enough space? */
     194  	    if (pamh->env->entries <= pamh->env->requested) {
     195  		register int i;
     196  		register char **tmp;
     197  
     198  		/* get some new space */
     199  		tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
     200  				     , sizeof(char *) );
     201  		if (tmp == NULL) {
     202  		    /* nothing has changed - old env intact */
     203  		    pam_syslog(pamh, LOG_CRIT,
     204  			       "pam_putenv: cannot grow environment");
     205  		    return PAM_BUF_ERR;
     206  		}
     207  
     208  		/* copy old env-item pointers/forget old */
     209  		for (i=0; i<pamh->env->requested; ++i) {
     210  		    tmp[i] = pamh->env->list[i];
     211  		    pamh->env->list[i] = NULL;
     212  		}
     213  
     214  		/* drop old list and replace with new */
     215  		_pam_drop(pamh->env->list);
     216  		pamh->env->list = tmp;
     217  		pamh->env->entries += PAM_ENV_CHUNK;
     218  
     219  		D(("resized env list"));
     220  		_pam_dump_env(pamh);              /* only when debugging */
     221  	    }
     222  
     223  	    item = pamh->env->requested-1;        /* old last item (NULL) */
     224  
     225  	    /* add a new NULL entry at end; increase counter */
     226  	    pamh->env->list[pamh->env->requested++] = NULL;
     227  
     228  	} else {                                /* replace old */
     229  	    D(("replacing item: %s\n          with: %s"
     230  	       , pamh->env->list[item], name_value));
     231  	    pam_overwrite_string(pamh->env->list[item]);
     232  	    _pam_drop(pamh->env->list[item]);
     233  	}
     234  
     235  	/*
     236  	 * now we have a place to put the new env-item, insert at 'item'
     237  	 */
     238  
     239  	pamh->env->list[item] = _pam_strdup(name_value);
     240  	if (pamh->env->list[item] != NULL) {
     241  	    _pam_dump_env(pamh);                   /* only when debugging */
     242  	    return PAM_SUCCESS;
     243  	}
     244  
     245  	/* something went wrong; we should delete the item - fall through */
     246  
     247  	retval = PAM_BUF_ERR;                        /* an error occurred */
     248      } else {
     249  	retval = PAM_SUCCESS;                      /* we requested delete */
     250      }
     251  
     252      /* getting to here implies we are deleting an item */
     253  
     254      if (item < 0) {
     255  	pam_syslog(pamh, LOG_ERR,
     256  		   "pam_putenv: delete non-existent entry; %s", name_value);
     257  	return PAM_BAD_ITEM;
     258      }
     259  
     260      /*
     261       * remove item: purge memory; reset counter; resize [; display-env]
     262       */
     263  
     264      D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
     265      pam_overwrite_string(pamh->env->list[item]);
     266      _pam_drop(pamh->env->list[item]);
     267      --(pamh->env->requested);
     268      D(("mmove: item[%d]+%d -> item[%d]"
     269         , item+1, ( pamh->env->requested - item ), item));
     270      (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
     271  		   , ( pamh->env->requested - item )*sizeof(char *) );
     272  
     273      _pam_dump_env(pamh);                   /* only when debugging */
     274  
     275      /*
     276       * deleted.
     277       */
     278  
     279      return retval;
     280  }
     281  
     282  /*
     283   *  Return the value of the requested environment variable
     284   */
     285  
     286  const char *pam_getenv(pam_handle_t *pamh, const char *name)
     287  {
     288      int item;
     289  
     290      D(("called."));
     291      IF_NO_PAMH("pam_getenv", pamh, NULL);
     292  
     293      if (name == NULL) {
     294  	pam_syslog(pamh, LOG_ERR, "pam_getenv: no variable indicated");
     295  	return NULL;
     296      }
     297  
     298      if (pamh->env == NULL || pamh->env->list == NULL) {
     299  	pam_syslog(pamh, LOG_ERR, "pam_getenv: no env%s found",
     300  		   pamh->env == NULL ? "":"-list" );
     301  	return NULL;
     302      }
     303  
     304      /* find the requested item */
     305  
     306      item = _pam_search_env(pamh->env, name, strlen(name));
     307      if (item != -1) {
     308  
     309  	D(("env-item: %s, found!", name));
     310  	return (pamh->env->list[item] + 1 + strlen(name));
     311  
     312      } else {
     313  
     314  	D(("env-item: %s, not found", name));
     315  	return NULL;
     316  
     317      }
     318  }
     319  
     320  static char **_copy_env(pam_handle_t *pamh)
     321  {
     322      char **dump;
     323      int i = pamh->env->requested;          /* reckon size of environment */
     324      char *const *env = pamh->env->list;
     325  
     326      D(("now get some memory for dump"));
     327  
     328      /* allocate some memory for this (plus the null tail-pointer) */
     329      dump = (char **) calloc(i, sizeof(char *));
     330      D(("dump = %p", dump));
     331      if (dump == NULL) {
     332  	return NULL;
     333      }
     334  
     335      /* now run through entries and copy the variables over */
     336      dump[--i] = NULL;
     337      while (i-- > 0) {
     338  	D(("env[%d]=`%s'", i,env[i]));
     339  	dump[i] = _pam_strdup(env[i]);
     340  	D(("->dump[%d]=`%s'", i,dump[i]));
     341  	if (dump[i] == NULL) {
     342  	    /* out of memory */
     343  
     344  	    while (dump[++i]) {
     345  		pam_overwrite_string(dump[i]);
     346  		_pam_drop(dump[i]);
     347  	    }
     348  	    _pam_drop(dump);
     349  	    return NULL;
     350  	}
     351      }
     352  
     353      env = NULL;                             /* forget now */
     354  
     355      /* return transcribed environment */
     356      return dump;
     357  }
     358  
     359  char **pam_getenvlist(pam_handle_t *pamh)
     360  {
     361      int i;
     362  
     363      D(("called."));
     364      IF_NO_PAMH("pam_getenvlist", pamh, NULL);
     365  
     366      if (pamh->env == NULL || pamh->env->list == NULL) {
     367  	pam_syslog(pamh, LOG_ERR, "pam_getenvlist: no env%s found",
     368  		   pamh->env == NULL ? "":"-list" );
     369  	return NULL;
     370      }
     371  
     372      /* some quick checks */
     373  
     374      if (pamh->env->requested > pamh->env->entries) {
     375  	pam_syslog(pamh, LOG_ERR, "pam_getenvlist: environment corruption");
     376  	_pam_dump_env(pamh);                 /* only active when debugging */
     377  	return NULL;
     378      }
     379  
     380      for (i=pamh->env->requested-1; i-- > 0; ) {
     381  	if (pamh->env->list[i] == NULL) {
     382  	    pam_syslog(pamh, LOG_ERR, "pam_getenvlist: environment broken");
     383  	    _pam_dump_env(pamh);              /* only active when debugging */
     384  	    return NULL;          /* somehow we've broken the environment!? */
     385  	}
     386      }
     387  
     388      /* Seems fine; copy environment */
     389  
     390      _pam_dump_env(pamh);                    /* only active when debugging */
     391  
     392      return _copy_env(pamh);
     393  }