pam_item.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /* pam_item.c */
  2. /*
  3. * $Id$
  4. */
  5. #include "pam_private.h"
  6. #include <ctype.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <syslog.h>
  10. #define TRY_SET(X, Y) \
  11. { \
  12. if ((X) != (Y)) { \
  13. char *_TMP_ = _pam_strdup(Y); \
  14. if (_TMP_ == NULL && (Y) != NULL) \
  15. return PAM_BUF_ERR; \
  16. free(X); \
  17. (X) = _TMP_; \
  18. } \
  19. }
  20. /* functions */
  21. int pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
  22. {
  23. int retval;
  24. D(("called"));
  25. IF_NO_PAMH("pam_set_item", pamh, PAM_SYSTEM_ERR);
  26. retval = PAM_SUCCESS;
  27. switch (item_type) {
  28. case PAM_SERVICE:
  29. /* Setting handlers_loaded to 0 will cause the handlers
  30. * to be reloaded on the next call to a service module.
  31. */
  32. pamh->handlers.handlers_loaded = 0;
  33. TRY_SET(pamh->service_name, item);
  34. {
  35. char *tmp;
  36. for (tmp=pamh->service_name; *tmp; ++tmp)
  37. *tmp = tolower(*tmp); /* require lower case */
  38. }
  39. break;
  40. case PAM_USER:
  41. TRY_SET(pamh->user, item);
  42. pamh->former.fail_user = PAM_SUCCESS;
  43. break;
  44. case PAM_USER_PROMPT:
  45. TRY_SET(pamh->prompt, item);
  46. pamh->former.fail_user = PAM_SUCCESS;
  47. break;
  48. case PAM_TTY:
  49. D(("setting tty to %s", item));
  50. TRY_SET(pamh->tty, item);
  51. break;
  52. case PAM_RUSER:
  53. TRY_SET(pamh->ruser, item);
  54. break;
  55. case PAM_RHOST:
  56. TRY_SET(pamh->rhost, item);
  57. break;
  58. case PAM_AUTHTOK:
  59. /*
  60. * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
  61. * modules.
  62. */
  63. if (__PAM_FROM_MODULE(pamh)) {
  64. if (pamh->authtok != item) {
  65. _pam_overwrite(pamh->authtok);
  66. TRY_SET(pamh->authtok, item);
  67. }
  68. } else {
  69. retval = PAM_BAD_ITEM;
  70. }
  71. break;
  72. case PAM_OLDAUTHTOK:
  73. /*
  74. * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
  75. * modules.
  76. */
  77. if (__PAM_FROM_MODULE(pamh)) {
  78. if (pamh->oldauthtok != item) {
  79. _pam_overwrite(pamh->oldauthtok);
  80. TRY_SET(pamh->oldauthtok, item);
  81. }
  82. } else {
  83. retval = PAM_BAD_ITEM;
  84. }
  85. break;
  86. case PAM_CONV: /* want to change the conversation function */
  87. if (item == NULL) {
  88. pam_syslog(pamh, LOG_ERR,
  89. "pam_set_item: attempt to set conv() to NULL");
  90. retval = PAM_PERM_DENIED;
  91. } else {
  92. struct pam_conv *tconv;
  93. if ((tconv=
  94. (struct pam_conv *) malloc(sizeof(struct pam_conv))
  95. ) == NULL) {
  96. pam_syslog(pamh, LOG_CRIT,
  97. "pam_set_item: malloc failed for pam_conv");
  98. retval = PAM_BUF_ERR;
  99. } else {
  100. memcpy(tconv, item, sizeof(struct pam_conv));
  101. _pam_drop(pamh->pam_conversation);
  102. pamh->pam_conversation = tconv;
  103. pamh->former.fail_user = PAM_SUCCESS;
  104. }
  105. }
  106. break;
  107. case PAM_FAIL_DELAY:
  108. pamh->fail_delay.delay_fn_ptr = item;
  109. break;
  110. case PAM_XDISPLAY:
  111. TRY_SET(pamh->xdisplay, item);
  112. break;
  113. case PAM_XAUTHDATA:
  114. if (&pamh->xauth == item)
  115. break;
  116. if (pamh->xauth.namelen) {
  117. _pam_overwrite(pamh->xauth.name);
  118. free(pamh->xauth.name);
  119. }
  120. if (pamh->xauth.datalen) {
  121. _pam_overwrite_n(pamh->xauth.data,
  122. (unsigned int) pamh->xauth.datalen);
  123. free(pamh->xauth.data);
  124. }
  125. pamh->xauth = *((const struct pam_xauth_data *) item);
  126. if ((pamh->xauth.name=_pam_strdup(pamh->xauth.name)) == NULL) {
  127. memset(&pamh->xauth, '\0', sizeof(pamh->xauth));
  128. return PAM_BUF_ERR;
  129. }
  130. if ((pamh->xauth.data=_pam_memdup(pamh->xauth.data,
  131. pamh->xauth.datalen)) == NULL) {
  132. _pam_overwrite(pamh->xauth.name);
  133. free(pamh->xauth.name);
  134. memset(&pamh->xauth, '\0', sizeof(pamh->xauth));
  135. return PAM_BUF_ERR;
  136. }
  137. break;
  138. case PAM_AUTHTOK_TYPE:
  139. TRY_SET(pamh->authtok_type, item);
  140. break;
  141. default:
  142. retval = PAM_BAD_ITEM;
  143. }
  144. return retval;
  145. }
  146. int pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
  147. {
  148. int retval = PAM_SUCCESS;
  149. D(("called."));
  150. IF_NO_PAMH("pam_get_item", pamh, PAM_SYSTEM_ERR);
  151. if (item == NULL) {
  152. pam_syslog(pamh, LOG_ERR,
  153. "pam_get_item: nowhere to place requested item");
  154. return PAM_PERM_DENIED;
  155. }
  156. else
  157. *item = NULL;
  158. switch (item_type) {
  159. case PAM_SERVICE:
  160. *item = pamh->service_name;
  161. break;
  162. case PAM_USER:
  163. D(("returning user=%s", pamh->user));
  164. *item = pamh->user;
  165. break;
  166. case PAM_USER_PROMPT:
  167. D(("returning userprompt=%s", pamh->user));
  168. *item = pamh->prompt;
  169. break;
  170. case PAM_TTY:
  171. D(("returning tty=%s", pamh->tty));
  172. *item = pamh->tty;
  173. break;
  174. case PAM_RUSER:
  175. *item = pamh->ruser;
  176. break;
  177. case PAM_RHOST:
  178. *item = pamh->rhost;
  179. break;
  180. case PAM_AUTHTOK:
  181. /*
  182. * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
  183. * modules.
  184. */
  185. if (__PAM_FROM_MODULE(pamh)) {
  186. *item = pamh->authtok;
  187. } else {
  188. retval = PAM_BAD_ITEM;
  189. }
  190. break;
  191. case PAM_OLDAUTHTOK:
  192. /*
  193. * PAM_AUTHTOK and PAM_OLDAUTHTOK are only accessible from
  194. * modules.
  195. */
  196. if (__PAM_FROM_MODULE(pamh)) {
  197. *item = pamh->oldauthtok;
  198. } else {
  199. retval = PAM_BAD_ITEM;
  200. }
  201. break;
  202. case PAM_CONV:
  203. *item = pamh->pam_conversation;
  204. break;
  205. case PAM_FAIL_DELAY:
  206. *item = pamh->fail_delay.delay_fn_ptr;
  207. break;
  208. case PAM_XDISPLAY:
  209. *item = pamh->xdisplay;
  210. break;
  211. case PAM_XAUTHDATA:
  212. *item = &pamh->xauth;
  213. break;
  214. case PAM_AUTHTOK_TYPE:
  215. *item = pamh->authtok_type;
  216. break;
  217. default:
  218. retval = PAM_BAD_ITEM;
  219. }
  220. return retval;
  221. }
  222. /*
  223. * This function is the 'preferred method to obtain the username'.
  224. */
  225. int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt)
  226. {
  227. const char *use_prompt;
  228. int retval;
  229. struct pam_message msg;
  230. const struct pam_message *pmsg;
  231. struct pam_response *resp;
  232. D(("called."));
  233. IF_NO_PAMH("pam_get_user", pamh, PAM_SYSTEM_ERR);
  234. if (user == NULL) {
  235. /* ensure that the module has supplied a destination */
  236. pam_syslog(pamh, LOG_ERR, "pam_get_user: nowhere to record username");
  237. return PAM_SYSTEM_ERR;
  238. } else
  239. *user = NULL;
  240. if (pamh->pam_conversation == NULL) {
  241. pam_syslog(pamh, LOG_ERR, "pam_get_user: no conv element in pamh");
  242. return PAM_SYSTEM_ERR;
  243. }
  244. if (pamh->user) { /* have one so return it */
  245. *user = pamh->user;
  246. return PAM_SUCCESS;
  247. }
  248. if (pamh->former.fail_user != PAM_SUCCESS)
  249. return pamh->former.fail_user;
  250. /* will need a prompt */
  251. if (prompt != NULL)
  252. use_prompt = prompt;
  253. else if (pamh->prompt != NULL)
  254. use_prompt = pamh->prompt;
  255. else
  256. use_prompt = _("login:");
  257. /* If we are resuming an old conversation, we verify that the prompt
  258. is the same. Anything else is an error. */
  259. if (pamh->former.want_user) {
  260. /* must have a prompt to resume with */
  261. if (! pamh->former.prompt) {
  262. pam_syslog(pamh, LOG_ERR,
  263. "pam_get_user: failed to resume with prompt"
  264. );
  265. return PAM_ABORT;
  266. }
  267. /* must be the same prompt as last time */
  268. if (strcmp(pamh->former.prompt, use_prompt)) {
  269. pam_syslog(pamh, LOG_ERR,
  270. "pam_get_user: resumed with different prompt");
  271. return PAM_ABORT;
  272. }
  273. /* ok, we can resume where we left off last time */
  274. pamh->former.want_user = PAM_FALSE;
  275. _pam_overwrite(pamh->former.prompt);
  276. _pam_drop(pamh->former.prompt);
  277. }
  278. /* converse with application -- prompt user for a username */
  279. pmsg = &msg;
  280. msg.msg_style = PAM_PROMPT_ECHO_ON;
  281. msg.msg = use_prompt;
  282. resp = NULL;
  283. retval = pamh->pam_conversation->
  284. conv(1, &pmsg, &resp, pamh->pam_conversation->appdata_ptr);
  285. switch (retval) {
  286. case PAM_SUCCESS:
  287. case PAM_BUF_ERR:
  288. case PAM_CONV_AGAIN:
  289. case PAM_CONV_ERR:
  290. break;
  291. default:
  292. retval = PAM_CONV_ERR;
  293. }
  294. switch (retval) {
  295. case PAM_CONV_AGAIN:
  296. /* conversation function is waiting for an event - save state */
  297. D(("conversation function is not ready yet"));
  298. pamh->former.want_user = PAM_TRUE;
  299. pamh->former.prompt = _pam_strdup(use_prompt);
  300. break;
  301. case PAM_SUCCESS:
  302. if (resp != NULL && resp->resp != NULL) {
  303. /*
  304. * now we set the PAM_USER item -- this was missing from pre.53
  305. * releases. However, reading the Sun manual, it is part of
  306. * the standard API.
  307. */
  308. retval = pam_set_item(pamh, PAM_USER, resp->resp);
  309. *user = pamh->user;
  310. break;
  311. } else {
  312. /* conversation should have given a response */
  313. D(("pam_get_user: no response provided"));
  314. retval = PAM_CONV_ERR;
  315. }
  316. /* fallthrough */
  317. default:
  318. pamh->former.fail_user = retval;
  319. }
  320. if (resp) {
  321. if (retval != PAM_SUCCESS)
  322. pam_syslog(pamh, LOG_WARNING,
  323. "unexpected response from failed conversation function");
  324. /*
  325. * note 'resp' is allocated by the application and is
  326. * correctly free()'d here
  327. */
  328. _pam_drop_reply(resp, 1);
  329. }
  330. D(("completed"));
  331. return retval; /* pass on any error from conversation */
  332. }