pam_stress.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * pam_stress module
  3. *
  4. * created by Andrew Morgan <morgan@linux.kernel.org> 1996/3/12
  5. */
  6. #include "config.h"
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <syslog.h>
  10. #include <stdarg.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. #include <security/pam_modules.h>
  14. #include <security/_pam_macros.h>
  15. #include <security/pam_ext.h>
  16. /* ---------- */
  17. /* an internal function to turn all possible test arguments into bits
  18. of a ctrl number */
  19. /* generic options */
  20. #define PAM_ST_DEBUG 01
  21. #define PAM_ST_NO_WARN 02
  22. #define PAM_ST_USE_PASS1 04
  23. #define PAM_ST_TRY_PASS1 010
  24. #define PAM_ST_ROOTOK 020
  25. /* simulation options */
  26. #define PAM_ST_EXPIRED 040
  27. #define PAM_ST_FAIL_1 0100
  28. #define PAM_ST_FAIL_2 0200
  29. #define PAM_ST_PRELIM 0400
  30. #define PAM_ST_REQUIRE_PWD 01000
  31. /* some syslogging */
  32. static void
  33. _pam_report (const pam_handle_t *pamh, int ctrl, const char *name,
  34. int flags, int argc, const char **argv)
  35. {
  36. if (ctrl & PAM_ST_DEBUG) {
  37. pam_syslog(pamh, LOG_DEBUG, "CALLED: %s", name);
  38. pam_syslog(pamh, LOG_DEBUG, "FLAGS : 0%o%s",
  39. flags, (flags & PAM_SILENT) ? " (silent)":"");
  40. pam_syslog(pamh, LOG_DEBUG, "CTRL = 0%o", ctrl);
  41. pam_syslog(pamh, LOG_DEBUG, "ARGV :");
  42. while (argc--) {
  43. pam_syslog(pamh, LOG_DEBUG, " \"%s\"", *argv++);
  44. }
  45. }
  46. }
  47. static int
  48. _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
  49. {
  50. int ctrl=0;
  51. /* step through arguments */
  52. for (ctrl=0; argc-- > 0; ++argv) {
  53. /* generic options */
  54. if (!strcmp(*argv,"debug"))
  55. ctrl |= PAM_ST_DEBUG;
  56. else if (!strcmp(*argv,"no_warn"))
  57. ctrl |= PAM_ST_NO_WARN;
  58. else if (!strcmp(*argv,"use_first_pass"))
  59. ctrl |= PAM_ST_USE_PASS1;
  60. else if (!strcmp(*argv,"try_first_pass"))
  61. ctrl |= PAM_ST_TRY_PASS1;
  62. else if (!strcmp(*argv,"rootok"))
  63. ctrl |= PAM_ST_ROOTOK;
  64. /* simulation options */
  65. else if (!strcmp(*argv,"expired")) /* signal password needs
  66. renewal */
  67. ctrl |= PAM_ST_EXPIRED;
  68. else if (!strcmp(*argv,"fail_1")) /* instruct fn 1 to fail */
  69. ctrl |= PAM_ST_FAIL_1;
  70. else if (!strcmp(*argv,"fail_2")) /* instruct fn 2 to fail */
  71. ctrl |= PAM_ST_FAIL_2;
  72. else if (!strcmp(*argv,"prelim")) /* instruct pam_sm_setcred
  73. to fail on first call */
  74. ctrl |= PAM_ST_PRELIM;
  75. else if (!strcmp(*argv,"required")) /* module is fussy about the
  76. user being authenticated */
  77. ctrl |= PAM_ST_REQUIRE_PWD;
  78. else {
  79. pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
  80. }
  81. }
  82. return ctrl;
  83. }
  84. static int converse(pam_handle_t *pamh, int nargs
  85. , const struct pam_message **message
  86. , struct pam_response **response)
  87. {
  88. int retval;
  89. const void *void_conv;
  90. const struct pam_conv *conv;
  91. retval = pam_get_item(pamh,PAM_CONV,&void_conv);
  92. conv = void_conv;
  93. if (retval == PAM_SUCCESS && conv) {
  94. retval = conv->conv(nargs, message, response, conv->appdata_ptr);
  95. if (retval != PAM_SUCCESS) {
  96. pam_syslog(pamh, LOG_ERR, "converse returned %d: %s",
  97. retval, pam_strerror(pamh, retval));
  98. }
  99. } else {
  100. pam_syslog(pamh, LOG_ERR, "converse failed to get pam_conv");
  101. if (retval == PAM_SUCCESS)
  102. retval = PAM_BAD_ITEM; /* conv was null */
  103. }
  104. return retval;
  105. }
  106. /* authentication management functions */
  107. static int stress_get_password(pam_handle_t *pamh, int flags
  108. , int ctrl, char **password)
  109. {
  110. const void *pam_pass;
  111. char *pass;
  112. if ( (ctrl & (PAM_ST_TRY_PASS1|PAM_ST_USE_PASS1))
  113. && (pam_get_item(pamh,PAM_AUTHTOK,&pam_pass)
  114. == PAM_SUCCESS)
  115. && (pam_pass != NULL) ) {
  116. if ((pass = strdup(pam_pass)) == NULL)
  117. return PAM_BUF_ERR;
  118. } else if ((ctrl & PAM_ST_USE_PASS1)) {
  119. pam_syslog(pamh, LOG_WARNING, "no forwarded password");
  120. return PAM_PERM_DENIED;
  121. } else { /* we will have to get one */
  122. struct pam_message msg[1];
  123. const struct pam_message *pmsg[1];
  124. struct pam_response *resp;
  125. int retval;
  126. /* set up conversation call */
  127. pmsg[0] = &msg[0];
  128. msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
  129. msg[0].msg = "STRESS Password: ";
  130. resp = NULL;
  131. if ((retval = converse(pamh,1,pmsg,&resp)) != PAM_SUCCESS) {
  132. return retval;
  133. }
  134. if (resp) {
  135. if ((resp[0].resp == NULL) && (ctrl & PAM_ST_DEBUG)) {
  136. pam_syslog(pamh, LOG_DEBUG,
  137. "pam_sm_authenticate: NULL authtok given");
  138. }
  139. if ((flags & PAM_DISALLOW_NULL_AUTHTOK)
  140. && resp[0].resp == NULL) {
  141. free(resp);
  142. return PAM_AUTH_ERR;
  143. }
  144. pass = resp[0].resp; /* remember this! */
  145. resp[0].resp = NULL;
  146. } else {
  147. if (ctrl & PAM_ST_DEBUG) {
  148. pam_syslog(pamh, LOG_DEBUG,
  149. "pam_sm_authenticate: no error reported");
  150. pam_syslog(pamh, LOG_DEBUG,
  151. "getting password, but NULL returned!?");
  152. }
  153. return PAM_CONV_ERR;
  154. }
  155. free(resp);
  156. }
  157. *password = pass; /* this *MUST* be free()'d by this module */
  158. return PAM_SUCCESS;
  159. }
  160. /* function to clean up data items */
  161. static void
  162. wipe_up (pam_handle_t *pamh UNUSED, void *data, int error UNUSED)
  163. {
  164. free(data);
  165. }
  166. int pam_sm_authenticate(pam_handle_t *pamh, int flags,
  167. int argc, const char **argv)
  168. {
  169. const char *username;
  170. int retval=PAM_SUCCESS;
  171. char *pass;
  172. int ctrl;
  173. D(("called."));
  174. ctrl = _pam_parse(pamh, argc, argv);
  175. _pam_report(pamh, ctrl, "pam_sm_authenticate", flags, argc, argv);
  176. /* try to get the username */
  177. retval = pam_get_user(pamh, &username, "username: ");
  178. if (retval != PAM_SUCCESS) {
  179. pam_syslog(pamh, LOG_NOTICE,
  180. "pam_sm_authenticate: cannot determine user name: %s",
  181. pam_strerror(pamh, retval));
  182. return retval;
  183. }
  184. else if (ctrl & PAM_ST_DEBUG) {
  185. pam_syslog(pamh, LOG_DEBUG,
  186. "pam_sm_authenticate: username = %s", username);
  187. }
  188. /* now get the password */
  189. retval = stress_get_password(pamh,flags,ctrl,&pass);
  190. if (retval != PAM_SUCCESS) {
  191. pam_syslog(pamh, LOG_WARNING,
  192. "pam_sm_authenticate: failed to get a password");
  193. return retval;
  194. }
  195. /* try to set password item */
  196. retval = pam_set_item(pamh,PAM_AUTHTOK,pass);
  197. _pam_overwrite(pass); /* clean up local copy of password */
  198. free(pass);
  199. pass = NULL;
  200. if (retval != PAM_SUCCESS) {
  201. pam_syslog(pamh, LOG_WARNING,
  202. "pam_sm_authenticate: failed to store new password");
  203. return retval;
  204. }
  205. /* if we are debugging then we print the password */
  206. if (ctrl & PAM_ST_DEBUG) {
  207. const void *pam_pass;
  208. (void) pam_get_item(pamh,PAM_AUTHTOK,&pam_pass);
  209. pam_syslog(pamh, LOG_DEBUG,
  210. "pam_st_authenticate: password entered is: [%s]",
  211. (const char *)pam_pass);
  212. }
  213. /* if we signal a fail for this function then fail */
  214. if ((ctrl & PAM_ST_FAIL_1) && retval == PAM_SUCCESS)
  215. return PAM_PERM_DENIED;
  216. return retval;
  217. }
  218. int pam_sm_setcred(pam_handle_t *pamh, int flags,
  219. int argc, const char **argv)
  220. {
  221. int ctrl = _pam_parse(pamh, argc, argv);
  222. D(("called. [post parsing]"));
  223. _pam_report(pamh, ctrl, "pam_sm_setcred", flags, argc, argv);
  224. if (ctrl & PAM_ST_FAIL_2)
  225. return PAM_CRED_ERR;
  226. return PAM_SUCCESS;
  227. }
  228. /* account management functions */
  229. int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
  230. int argc, const char **argv)
  231. {
  232. int ctrl = _pam_parse(pamh, argc, argv);
  233. D(("called. [post parsing]"));
  234. _pam_report(pamh, ctrl,"pam_sm_acct_mgmt", flags, argc, argv);
  235. if (ctrl & PAM_ST_FAIL_1)
  236. return PAM_PERM_DENIED;
  237. else if (ctrl & PAM_ST_EXPIRED) {
  238. int retval;
  239. void *text = strdup("yes");
  240. if (!text)
  241. return PAM_BUF_ERR;
  242. retval = pam_set_data(pamh,"stress_new_pwd",text,wipe_up);
  243. if (retval != PAM_SUCCESS) {
  244. pam_syslog(pamh, LOG_DEBUG,
  245. "pam_sm_acct_mgmt: failed setting stress_new_pwd");
  246. free(text);
  247. return retval;
  248. }
  249. if (ctrl & PAM_ST_DEBUG) {
  250. pam_syslog(pamh, LOG_DEBUG,
  251. "pam_sm_acct_mgmt: need a new password");
  252. }
  253. return PAM_NEW_AUTHTOK_REQD;
  254. }
  255. return PAM_SUCCESS;
  256. }
  257. int pam_sm_open_session(pam_handle_t *pamh, int flags,
  258. int argc, const char **argv)
  259. {
  260. const void *username, *service;
  261. int ctrl = _pam_parse(pamh, argc, argv);
  262. D(("called. [post parsing]"));
  263. _pam_report(pamh, ctrl,"pam_sm_open_session", flags, argc, argv);
  264. if ((pam_get_item(pamh, PAM_USER, &username)
  265. != PAM_SUCCESS || !username)
  266. || (pam_get_item(pamh, PAM_SERVICE, &service)
  267. != PAM_SUCCESS || !service)) {
  268. pam_syslog(pamh, LOG_WARNING, "pam_sm_open_session: for whom?");
  269. return PAM_SESSION_ERR;
  270. }
  271. pam_syslog(pamh, LOG_NOTICE, "opened [%s] session for user [%s]",
  272. (const char *)service, (const char *)username);
  273. if (ctrl & PAM_ST_FAIL_1)
  274. return PAM_SESSION_ERR;
  275. return PAM_SUCCESS;
  276. }
  277. int pam_sm_close_session(pam_handle_t *pamh, int flags,
  278. int argc, const char **argv)
  279. {
  280. const void *username, *service;
  281. int ctrl = _pam_parse(pamh, argc, argv);
  282. D(("called. [post parsing]"));
  283. _pam_report(pamh, ctrl,"pam_sm_close_session", flags, argc, argv);
  284. if ((pam_get_item(pamh, PAM_USER, &username)
  285. != PAM_SUCCESS || !username)
  286. || (pam_get_item(pamh, PAM_SERVICE, &service)
  287. != PAM_SUCCESS || !service)) {
  288. pam_syslog(pamh, LOG_WARNING, "pam_sm_close_session: for whom?");
  289. return PAM_SESSION_ERR;
  290. }
  291. pam_syslog(pamh, LOG_NOTICE, "closed [%s] session for user [%s]",
  292. (const char *)service, (const char *)username);
  293. if (ctrl & PAM_ST_FAIL_2)
  294. return PAM_SESSION_ERR;
  295. return PAM_SUCCESS;
  296. }
  297. int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
  298. int argc, const char **argv)
  299. {
  300. int retval;
  301. int ctrl = _pam_parse(pamh, argc, argv);
  302. D(("called. [post parsing]"));
  303. _pam_report(pamh, ctrl,"pam_sm_chauthtok", flags, argc, argv);
  304. /* this function should be called twice by the Linux-PAM library */
  305. if (flags & PAM_PRELIM_CHECK) { /* first call */
  306. if (ctrl & PAM_ST_DEBUG) {
  307. pam_syslog(pamh, LOG_DEBUG, "pam_sm_chauthtok: prelim check");
  308. }
  309. if (ctrl & PAM_ST_PRELIM)
  310. return PAM_TRY_AGAIN;
  311. return PAM_SUCCESS;
  312. } else if (flags & PAM_UPDATE_AUTHTOK) { /* second call */
  313. struct pam_message msg[3];
  314. const struct pam_message *pmsg[3];
  315. struct pam_response *resp;
  316. const void *text;
  317. char *txt=NULL;
  318. int i;
  319. if (ctrl & PAM_ST_DEBUG) {
  320. pam_syslog(pamh, LOG_DEBUG, "pam_sm_chauthtok: alter password");
  321. }
  322. if (ctrl & PAM_ST_FAIL_1)
  323. return PAM_AUTHTOK_LOCK_BUSY;
  324. if ( !(ctrl & PAM_ST_EXPIRED)
  325. && (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
  326. && (pam_get_data(pamh,"stress_new_pwd", &text)
  327. != PAM_SUCCESS || strcmp(text,"yes"))) {
  328. return PAM_SUCCESS; /* the token has not expired */
  329. }
  330. /* the password should be changed */
  331. if ((ctrl & PAM_ST_REQUIRE_PWD)
  332. && !(getuid() == 0 && (ctrl & PAM_ST_ROOTOK))
  333. ) { /* first get old one? */
  334. char *pass;
  335. if (ctrl & PAM_ST_DEBUG) {
  336. pam_syslog(pamh, LOG_DEBUG,
  337. "pam_sm_chauthtok: getting old password");
  338. }
  339. retval = stress_get_password(pamh,flags,ctrl,&pass);
  340. if (retval != PAM_SUCCESS) {
  341. pam_syslog(pamh, LOG_DEBUG,
  342. "pam_sm_chauthtok: no password obtained");
  343. return retval;
  344. }
  345. retval = pam_set_item(pamh, PAM_OLDAUTHTOK, pass);
  346. _pam_overwrite(pass);
  347. free(pass);
  348. pass = NULL;
  349. if (retval != PAM_SUCCESS) {
  350. pam_syslog(pamh, LOG_DEBUG,
  351. "pam_sm_chauthtok: could not set OLDAUTHTOK");
  352. return retval;
  353. }
  354. }
  355. /* set up for conversation */
  356. if (!(flags & PAM_SILENT)) {
  357. const void *username;
  358. if ( pam_get_item(pamh, PAM_USER, &username)
  359. || username == NULL ) {
  360. pam_syslog(pamh, LOG_ERR, "no username set");
  361. return PAM_USER_UNKNOWN;
  362. }
  363. pmsg[0] = &msg[0];
  364. msg[0].msg_style = PAM_TEXT_INFO;
  365. if (asprintf(&txt, "Changing STRESS password for %s.",
  366. (const char *)username) < 0) {
  367. pam_syslog(pamh, LOG_CRIT, "out of memory");
  368. return PAM_BUF_ERR;
  369. }
  370. msg[0].msg = txt;
  371. i = 1;
  372. } else {
  373. i = 0;
  374. }
  375. pmsg[i] = &msg[i];
  376. msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
  377. msg[i++].msg = "Enter new STRESS password: ";
  378. pmsg[i] = &msg[i];
  379. msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
  380. msg[i++].msg = "Retype new STRESS password: ";
  381. resp = NULL;
  382. retval = converse(pamh,i,pmsg,&resp);
  383. if (txt) {
  384. free(txt);
  385. txt = NULL; /* clean up */
  386. }
  387. if (retval != PAM_SUCCESS) {
  388. return retval;
  389. }
  390. if (resp == NULL) {
  391. pam_syslog(pamh, LOG_ERR,
  392. "pam_sm_chauthtok: no response from conv");
  393. return PAM_CONV_ERR;
  394. }
  395. /* store the password */
  396. if (resp[i-2].resp && resp[i-1].resp) {
  397. if (strcmp(resp[i-2].resp,resp[i-1].resp)) {
  398. /* passwords are not the same; forget and return error */
  399. _pam_drop_reply(resp, i);
  400. if (!(flags & PAM_SILENT) && !(ctrl & PAM_ST_NO_WARN)) {
  401. pmsg[0] = &msg[0];
  402. msg[0].msg_style = PAM_ERROR_MSG;
  403. msg[0].msg = "Verification mis-typed; "
  404. "password unchanged";
  405. resp = NULL;
  406. (void) converse(pamh,1,pmsg,&resp);
  407. if (resp) {
  408. _pam_drop_reply(resp, 1);
  409. }
  410. }
  411. return PAM_AUTHTOK_ERR;
  412. }
  413. if (pam_get_item(pamh,PAM_AUTHTOK,&text)
  414. == PAM_SUCCESS) {
  415. (void) pam_set_item(pamh,PAM_OLDAUTHTOK,text);
  416. text = NULL;
  417. }
  418. (void) pam_set_item(pamh,PAM_AUTHTOK,resp[0].resp);
  419. } else {
  420. pam_syslog(pamh, LOG_DEBUG,
  421. "pam_sm_chauthtok: problem with resp");
  422. retval = PAM_SYSTEM_ERR;
  423. }
  424. _pam_drop_reply(resp, i); /* clean up the passwords */
  425. } else {
  426. pam_syslog(pamh, LOG_ERR,
  427. "pam_sm_chauthtok: this must be a Linux-PAM error");
  428. return PAM_SYSTEM_ERR;
  429. }
  430. return retval;
  431. }