pam_env.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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. #include "pam_private.h"
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #ifdef sunos
  16. #define memmove(x,y,z) bcopy(y,x,z)
  17. #endif
  18. /* helper functions */
  19. #ifdef PAM_DEBUG
  20. static void _pam_dump_env(pam_handle_t *pamh)
  21. {
  22. int i;
  23. D(("Listing environment of pamh=%p", pamh));
  24. D(("pamh->env = %p", pamh->env));
  25. D(("environment entries used = %d [of %d allocated]"
  26. , pamh->env->requested, pamh->env->entries));
  27. for (i=0; i<pamh->env->requested; ++i) {
  28. _pam_output_debug(">%-3d [%9p]:[%s]"
  29. , i, pamh->env->list[i], pamh->env->list[i]);
  30. }
  31. _pam_output_debug("*NOTE* the last item should be (nil)");
  32. }
  33. #else
  34. #define _pam_dump_env(x)
  35. #endif
  36. /*
  37. * Create the environment
  38. */
  39. int _pam_make_env(pam_handle_t *pamh)
  40. {
  41. D(("called."));
  42. IF_NO_PAMH("_pam_make_env", pamh, PAM_ABORT);
  43. /*
  44. * get structure memory
  45. */
  46. pamh->env = (struct pam_environ *) malloc(sizeof(struct pam_environ));
  47. if (pamh->env == NULL) {
  48. pam_syslog(pamh, LOG_CRIT, "_pam_make_env: out of memory");
  49. return PAM_BUF_ERR;
  50. }
  51. /*
  52. * get list memory
  53. */
  54. pamh->env->list = (char **)calloc( PAM_ENV_CHUNK, sizeof(char *) );
  55. if (pamh->env->list == NULL) {
  56. pam_syslog(pamh, LOG_CRIT, "_pam_make_env: no memory for list");
  57. _pam_drop(pamh->env);
  58. return PAM_BUF_ERR;
  59. }
  60. /*
  61. * fill entries in pamh->env
  62. */
  63. pamh->env->entries = PAM_ENV_CHUNK;
  64. pamh->env->requested = 1;
  65. pamh->env->list[0] = NULL;
  66. _pam_dump_env(pamh); /* only active when debugging */
  67. return PAM_SUCCESS;
  68. }
  69. /*
  70. * purge the environment
  71. */
  72. void _pam_drop_env(pam_handle_t *pamh)
  73. {
  74. D(("called."));
  75. IF_NO_PAMH("_pam_make_env", pamh, /* nothing to return */);
  76. if (pamh->env != NULL) {
  77. int i;
  78. /* we will only purge the pamh->env->requested number of elements */
  79. for (i=pamh->env->requested-1; i-- > 0; ) {
  80. D(("dropping #%3d>%s<", i, pamh->env->list[i]));
  81. _pam_overwrite(pamh->env->list[i]); /* clean */
  82. _pam_drop(pamh->env->list[i]); /* forget */
  83. }
  84. pamh->env->requested = 0;
  85. pamh->env->entries = 0;
  86. _pam_drop(pamh->env->list); /* forget */
  87. _pam_drop(pamh->env); /* forget */
  88. } else {
  89. D(("no environment present in pamh?"));
  90. }
  91. }
  92. /*
  93. * Return the item number of the given variable = first 'length' chars
  94. * of 'name_value'. Since this is a static function, it is safe to
  95. * assume its supplied arguments are well defined.
  96. */
  97. static int _pam_search_env(const struct pam_environ *env
  98. , const char *name_value, int length)
  99. {
  100. int i;
  101. for (i=env->requested-1; i-- > 0; ) {
  102. if (strncmp(name_value,env->list[i],length) == 0
  103. && env->list[i][length] == '=') {
  104. return i; /* Got it! */
  105. }
  106. }
  107. return -1; /* no luck */
  108. }
  109. /*
  110. * externally visible functions
  111. */
  112. /*
  113. * pam_putenv(): Add/replace/delete a PAM-environment variable.
  114. *
  115. * Add/replace:
  116. * name_value = "NAME=VALUE" or "NAME=" (for empty value="\0")
  117. *
  118. * delete:
  119. * name_value = "NAME"
  120. */
  121. int pam_putenv(pam_handle_t *pamh, const char *name_value)
  122. {
  123. int l2eq, item, retval;
  124. D(("called."));
  125. IF_NO_PAMH("pam_putenv", pamh, PAM_ABORT);
  126. if (name_value == NULL) {
  127. pam_syslog(pamh, LOG_ERR, "pam_putenv: no variable indicated");
  128. return PAM_PERM_DENIED;
  129. }
  130. /*
  131. * establish if we are setting or deleting; scan for '='
  132. */
  133. for (l2eq=0; name_value[l2eq] && name_value[l2eq] != '='; ++l2eq);
  134. if (l2eq <= 0) {
  135. pam_syslog(pamh, LOG_ERR, "pam_putenv: bad variable");
  136. return PAM_BAD_ITEM;
  137. }
  138. /*
  139. * Look first for environment.
  140. */
  141. if (pamh->env == NULL || pamh->env->list == NULL) {
  142. pam_syslog(pamh, LOG_ERR, "pam_putenv: no env%s found",
  143. pamh->env == NULL ? "":"-list");
  144. return PAM_ABORT;
  145. }
  146. /* find the item to replace */
  147. item = _pam_search_env(pamh->env, name_value, l2eq);
  148. if (name_value[l2eq]) { /* (re)setting */
  149. if (item == -1) { /* new variable */
  150. D(("adding item: %s", name_value));
  151. /* enough space? */
  152. if (pamh->env->entries <= pamh->env->requested) {
  153. register int i;
  154. register char **tmp;
  155. /* get some new space */
  156. tmp = calloc( pamh->env->entries + PAM_ENV_CHUNK
  157. , sizeof(char *) );
  158. if (tmp == NULL) {
  159. /* nothing has changed - old env intact */
  160. pam_syslog(pamh, LOG_CRIT,
  161. "pam_putenv: cannot grow environment");
  162. return PAM_BUF_ERR;
  163. }
  164. /* copy old env-item pointers/forget old */
  165. for (i=0; i<pamh->env->requested; ++i) {
  166. tmp[i] = pamh->env->list[i];
  167. pamh->env->list[i] = NULL;
  168. }
  169. /* drop old list and replace with new */
  170. _pam_drop(pamh->env->list);
  171. pamh->env->list = tmp;
  172. pamh->env->entries += PAM_ENV_CHUNK;
  173. D(("resized env list"));
  174. _pam_dump_env(pamh); /* only when debugging */
  175. }
  176. item = pamh->env->requested-1; /* old last item (NULL) */
  177. /* add a new NULL entry at end; increase counter */
  178. pamh->env->list[pamh->env->requested++] = NULL;
  179. } else { /* replace old */
  180. D(("replacing item: %s\n with: %s"
  181. , pamh->env->list[item], name_value));
  182. _pam_overwrite(pamh->env->list[item]);
  183. _pam_drop(pamh->env->list[item]);
  184. }
  185. /*
  186. * now we have a place to put the new env-item, insert at 'item'
  187. */
  188. pamh->env->list[item] = _pam_strdup(name_value);
  189. if (pamh->env->list[item] != NULL) {
  190. _pam_dump_env(pamh); /* only when debugging */
  191. return PAM_SUCCESS;
  192. }
  193. /* something went wrong; we should delete the item - fall through */
  194. retval = PAM_BUF_ERR; /* an error occurred */
  195. } else {
  196. retval = PAM_SUCCESS; /* we requested delete */
  197. }
  198. /* getting to here implies we are deleting an item */
  199. if (item < 0) {
  200. pam_syslog(pamh, LOG_ERR,
  201. "pam_putenv: delete non-existent entry; %s", name_value);
  202. return PAM_BAD_ITEM;
  203. }
  204. /*
  205. * remove item: purge memory; reset counter; resize [; display-env]
  206. */
  207. D(("deleting: env#%3d:[%s]", item, pamh->env->list[item]));
  208. _pam_overwrite(pamh->env->list[item]);
  209. _pam_drop(pamh->env->list[item]);
  210. --(pamh->env->requested);
  211. D(("mmove: item[%d]+%d -> item[%d]"
  212. , item+1, ( pamh->env->requested - item ), item));
  213. (void) memmove(&pamh->env->list[item], &pamh->env->list[item+1]
  214. , ( pamh->env->requested - item )*sizeof(char *) );
  215. _pam_dump_env(pamh); /* only when debugging */
  216. /*
  217. * deleted.
  218. */
  219. return retval;
  220. }
  221. /*
  222. * Return the value of the requested environment variable
  223. */
  224. const char *pam_getenv(pam_handle_t *pamh, const char *name)
  225. {
  226. int item;
  227. D(("called."));
  228. IF_NO_PAMH("pam_getenv", pamh, NULL);
  229. if (name == NULL) {
  230. pam_syslog(pamh, LOG_ERR, "pam_getenv: no variable indicated");
  231. return NULL;
  232. }
  233. if (pamh->env == NULL || pamh->env->list == NULL) {
  234. pam_syslog(pamh, LOG_ERR, "pam_getenv: no env%s found",
  235. pamh->env == NULL ? "":"-list" );
  236. return NULL;
  237. }
  238. /* find the requested item */
  239. item = _pam_search_env(pamh->env, name, strlen(name));
  240. if (item != -1) {
  241. D(("env-item: %s, found!", name));
  242. return (pamh->env->list[item] + 1 + strlen(name));
  243. } else {
  244. D(("env-item: %s, not found", name));
  245. return NULL;
  246. }
  247. }
  248. static char **_copy_env(pam_handle_t *pamh)
  249. {
  250. char **dump;
  251. int i = pamh->env->requested; /* reckon size of environment */
  252. char *const *env = pamh->env->list;
  253. D(("now get some memory for dump"));
  254. /* allocate some memory for this (plus the null tail-pointer) */
  255. dump = (char **) calloc(i, sizeof(char *));
  256. D(("dump = %p", dump));
  257. if (dump == NULL) {
  258. return NULL;
  259. }
  260. /* now run through entries and copy the variables over */
  261. dump[--i] = NULL;
  262. while (i-- > 0) {
  263. D(("env[%d]=`%s'", i,env[i]));
  264. dump[i] = _pam_strdup(env[i]);
  265. D(("->dump[%d]=`%s'", i,dump[i]));
  266. if (dump[i] == NULL) {
  267. /* out of memory */
  268. while (dump[++i]) {
  269. _pam_overwrite(dump[i]);
  270. _pam_drop(dump[i]);
  271. }
  272. _pam_drop(dump);
  273. return NULL;
  274. }
  275. }
  276. env = NULL; /* forget now */
  277. /* return transcribed environment */
  278. return dump;
  279. }
  280. char **pam_getenvlist(pam_handle_t *pamh)
  281. {
  282. int i;
  283. D(("called."));
  284. IF_NO_PAMH("pam_getenvlist", pamh, NULL);
  285. if (pamh->env == NULL || pamh->env->list == NULL) {
  286. pam_syslog(pamh, LOG_ERR, "pam_getenvlist: no env%s found",
  287. pamh->env == NULL ? "":"-list" );
  288. return NULL;
  289. }
  290. /* some quick checks */
  291. if (pamh->env->requested > pamh->env->entries) {
  292. pam_syslog(pamh, LOG_ERR, "pam_getenvlist: environment corruption");
  293. _pam_dump_env(pamh); /* only active when debugging */
  294. return NULL;
  295. }
  296. for (i=pamh->env->requested-1; i-- > 0; ) {
  297. if (pamh->env->list[i] == NULL) {
  298. pam_syslog(pamh, LOG_ERR, "pam_getenvlist: environment broken");
  299. _pam_dump_env(pamh); /* only active when debugging */
  300. return NULL; /* somehow we've broken the environment!? */
  301. }
  302. }
  303. /* Seems fine; copy environment */
  304. _pam_dump_env(pamh); /* only active when debugging */
  305. return _copy_env(pamh);
  306. }