support.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /*
  2. * Copyright information at end of file.
  3. */
  4. #include "config.h"
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <stdarg.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <malloc.h>
  11. #include <pwd.h>
  12. #include <shadow.h>
  13. #include <limits.h>
  14. #include <utmp.h>
  15. #include <errno.h>
  16. #include <signal.h>
  17. #include <ctype.h>
  18. #include <syslog.h>
  19. #include <sys/resource.h>
  20. #ifdef HAVE_RPCSVC_YPCLNT_H
  21. #include <rpcsvc/ypclnt.h>
  22. #endif
  23. #include <security/_pam_macros.h>
  24. #include <security/pam_modules.h>
  25. #include <security/pam_ext.h>
  26. #include <security/pam_modutil.h>
  27. #include "pam_cc_compat.h"
  28. #include "pam_inline.h"
  29. #include "support.h"
  30. #include "passverify.h"
  31. /* this is a front-end for module-application conversations */
  32. int _make_remark(pam_handle_t * pamh, unsigned long long ctrl,
  33. int type, const char *text)
  34. {
  35. int retval = PAM_SUCCESS;
  36. if (off(UNIX__QUIET, ctrl)) {
  37. retval = pam_prompt(pamh, type, NULL, "%s", text);
  38. }
  39. return retval;
  40. }
  41. /*
  42. * set the control flags for the UNIX module.
  43. */
  44. unsigned long long _set_ctrl(pam_handle_t *pamh, int flags, int *remember,
  45. int *rounds, int *pass_min_len, int argc,
  46. const char **argv)
  47. {
  48. unsigned long long ctrl;
  49. char *val;
  50. int j;
  51. D(("called."));
  52. ctrl = UNIX_DEFAULTS; /* the default selection of options */
  53. /* set some flags manually */
  54. if (getuid() == 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
  55. D(("IAMROOT"));
  56. set(UNIX__IAMROOT, ctrl);
  57. }
  58. if (flags & PAM_UPDATE_AUTHTOK) {
  59. D(("UPDATE_AUTHTOK"));
  60. set(UNIX__UPDATE, ctrl);
  61. }
  62. if (flags & PAM_PRELIM_CHECK) {
  63. D(("PRELIM_CHECK"));
  64. set(UNIX__PRELIM, ctrl);
  65. }
  66. if (flags & PAM_SILENT) {
  67. D(("SILENT"));
  68. set(UNIX__QUIET, ctrl);
  69. }
  70. /* preset encryption method with value from /etc/login.defs */
  71. val = pam_modutil_search_key(pamh, LOGIN_DEFS, "ENCRYPT_METHOD");
  72. if (val) {
  73. for (j = 0; j < UNIX_CTRLS_; ++j) {
  74. if (unix_args[j].token && unix_args[j].is_hash_algo
  75. && !strncasecmp(val, unix_args[j].token, strlen(unix_args[j].token))) {
  76. break;
  77. }
  78. }
  79. if (j >= UNIX_CTRLS_) {
  80. pam_syslog(pamh, LOG_WARNING, "unrecognized ENCRYPT_METHOD value [%s]", val);
  81. } else {
  82. ctrl &= unix_args[j].mask; /* for turning things off */
  83. ctrl |= unix_args[j].flag; /* for turning things on */
  84. }
  85. free (val);
  86. /* read number of rounds for crypt algo */
  87. if (rounds && (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl))) {
  88. val = pam_modutil_search_key(pamh, LOGIN_DEFS, "SHA_CRYPT_MAX_ROUNDS");
  89. if (val) {
  90. *rounds = strtol(val, NULL, 10);
  91. set(UNIX_ALGO_ROUNDS, ctrl);
  92. free (val);
  93. }
  94. }
  95. }
  96. /* now parse the arguments to this module */
  97. for (; argc-- > 0; ++argv) {
  98. const char *str = NULL;
  99. D(("pam_unix arg: %s", *argv));
  100. for (j = 0; j < UNIX_CTRLS_; ++j) {
  101. if (unix_args[j].token
  102. && (str = pam_str_skip_prefix_len(*argv,
  103. unix_args[j].token,
  104. strlen(unix_args[j].token))) != NULL) {
  105. break;
  106. }
  107. }
  108. if (str == NULL) {
  109. pam_syslog(pamh, LOG_ERR,
  110. "unrecognized option [%s]", *argv);
  111. } else {
  112. /* special cases */
  113. if (j == UNIX_REMEMBER_PASSWD) {
  114. if (remember == NULL) {
  115. pam_syslog(pamh, LOG_ERR,
  116. "option remember not allowed for this module type");
  117. continue;
  118. }
  119. *remember = strtol(str, NULL, 10);
  120. if ((*remember == INT_MIN) || (*remember == INT_MAX))
  121. *remember = -1;
  122. if (*remember > 400)
  123. *remember = 400;
  124. } else if (j == UNIX_MIN_PASS_LEN) {
  125. if (pass_min_len == NULL) {
  126. pam_syslog(pamh, LOG_ERR,
  127. "option minlen not allowed for this module type");
  128. continue;
  129. }
  130. *pass_min_len = atoi(str);
  131. } else if (j == UNIX_ALGO_ROUNDS) {
  132. if (rounds == NULL) {
  133. pam_syslog(pamh, LOG_ERR,
  134. "option rounds not allowed for this module type");
  135. continue;
  136. }
  137. *rounds = strtol(str, NULL, 10);
  138. }
  139. ctrl &= unix_args[j].mask; /* for turning things off */
  140. ctrl |= unix_args[j].flag; /* for turning things on */
  141. }
  142. }
  143. if (UNIX_DES_CRYPT(ctrl)
  144. && pass_min_len && *pass_min_len > 8)
  145. {
  146. pam_syslog (pamh, LOG_NOTICE, "Password minlen reset to 8 characters");
  147. *pass_min_len = 8;
  148. }
  149. if (flags & PAM_DISALLOW_NULL_AUTHTOK) {
  150. D(("DISALLOW_NULL_AUTHTOK"));
  151. set(UNIX__NONULL, ctrl);
  152. }
  153. /* Set default rounds for blowfish, gost-yescrypt and yescrypt */
  154. if (off(UNIX_ALGO_ROUNDS, ctrl) && rounds != NULL) {
  155. if (on(UNIX_BLOWFISH_PASS, ctrl) ||
  156. on(UNIX_GOST_YESCRYPT_PASS, ctrl) ||
  157. on(UNIX_YESCRYPT_PASS, ctrl)) {
  158. *rounds = 5;
  159. set(UNIX_ALGO_ROUNDS, ctrl);
  160. }
  161. }
  162. /* Enforce sane "rounds" values */
  163. if (on(UNIX_ALGO_ROUNDS, ctrl)) {
  164. if (on(UNIX_GOST_YESCRYPT_PASS, ctrl) ||
  165. on(UNIX_YESCRYPT_PASS, ctrl)) {
  166. if (*rounds < 3 || *rounds > 11)
  167. *rounds = 5;
  168. } else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
  169. if (*rounds < 4 || *rounds > 31)
  170. *rounds = 5;
  171. } else if (on(UNIX_SHA256_PASS, ctrl) || on(UNIX_SHA512_PASS, ctrl)) {
  172. if ((*rounds < 1000) || (*rounds == INT_MAX)) {
  173. /* don't care about bogus values */
  174. *rounds = 0;
  175. unset(UNIX_ALGO_ROUNDS, ctrl);
  176. } else if (*rounds >= 10000000) {
  177. *rounds = 9999999;
  178. }
  179. }
  180. }
  181. /* auditing is a more sensitive version of debug */
  182. if (on(UNIX_AUDIT, ctrl)) {
  183. set(UNIX_DEBUG, ctrl);
  184. }
  185. /* return the set of flags */
  186. D(("done."));
  187. return ctrl;
  188. }
  189. /* ************************************************************** *
  190. * Useful non-trivial functions *
  191. * ************************************************************** */
  192. /*
  193. * the following is used to keep track of the number of times a user fails
  194. * to authenticate themself.
  195. */
  196. #define FAIL_PREFIX "-UN*X-FAIL-"
  197. #define UNIX_MAX_RETRIES 3
  198. struct _pam_failed_auth {
  199. char *user; /* user that's failed to be authenticated */
  200. char *name; /* attempt from user with name */
  201. int uid; /* uid of calling user */
  202. int euid; /* euid of calling process */
  203. int count; /* number of failures so far */
  204. };
  205. #ifndef PAM_DATA_REPLACE
  206. #error "Need to get an updated libpam 0.52 or better"
  207. #endif
  208. static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err)
  209. {
  210. int quiet;
  211. const void *service = NULL;
  212. const void *ruser = NULL;
  213. const void *rhost = NULL;
  214. const void *tty = NULL;
  215. struct _pam_failed_auth *failure;
  216. D(("called"));
  217. quiet = err & PAM_DATA_SILENT; /* should we log something? */
  218. err &= PAM_DATA_REPLACE; /* are we just replacing data? */
  219. failure = (struct _pam_failed_auth *) fl;
  220. if (failure != NULL) {
  221. if (!quiet && !err) { /* under advisement from Sun,may go away */
  222. /* log the number of authentication failures */
  223. if (failure->count > 1) {
  224. (void) pam_get_item(pamh, PAM_SERVICE,
  225. &service);
  226. (void) pam_get_item(pamh, PAM_RUSER,
  227. &ruser);
  228. (void) pam_get_item(pamh, PAM_RHOST,
  229. &rhost);
  230. (void) pam_get_item(pamh, PAM_TTY,
  231. &tty);
  232. pam_syslog(pamh, LOG_NOTICE,
  233. "%d more authentication failure%s; "
  234. "logname=%s uid=%d euid=%d "
  235. "tty=%s ruser=%s rhost=%s "
  236. "%s%s",
  237. failure->count - 1, failure->count == 2 ? "" : "s",
  238. failure->name, failure->uid, failure->euid,
  239. tty ? (const char *)tty : "", ruser ? (const char *)ruser : "",
  240. rhost ? (const char *)rhost : "",
  241. (failure->user && failure->user[0] != '\0')
  242. ? " user=" : "", failure->user
  243. );
  244. if (failure->count > UNIX_MAX_RETRIES) {
  245. pam_syslog(pamh, LOG_NOTICE,
  246. "service(%s) ignoring max retries; %d > %d",
  247. service == NULL ? "**unknown**" : (const char *)service,
  248. failure->count,
  249. UNIX_MAX_RETRIES);
  250. }
  251. }
  252. }
  253. _pam_delete(failure->user); /* tidy up */
  254. _pam_delete(failure->name); /* tidy up */
  255. free(failure);
  256. }
  257. }
  258. /*
  259. * _unix_getpwnam() searches only /etc/passwd and NIS to find user information
  260. */
  261. static void _unix_cleanup(pam_handle_t *pamh UNUSED, void *data, int error_status UNUSED)
  262. {
  263. free(data);
  264. }
  265. int _unix_getpwnam(pam_handle_t *pamh, const char *name,
  266. int files, int nis, struct passwd **ret)
  267. {
  268. FILE *passwd;
  269. char buf[16384];
  270. int matched = 0, buflen;
  271. char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p;
  272. memset(buf, 0, sizeof(buf));
  273. if (!matched && files) {
  274. int userlen = strlen(name);
  275. passwd = fopen("/etc/passwd", "r");
  276. if (passwd != NULL) {
  277. while (fgets(buf, sizeof(buf), passwd) != NULL) {
  278. if ((buf[userlen] == ':') &&
  279. (strncmp(name, buf, userlen) == 0)) {
  280. p = buf + strlen(buf) - 1;
  281. while (isspace(*p) && (p >= buf)) {
  282. *p-- = '\0';
  283. }
  284. matched = 1;
  285. break;
  286. }
  287. }
  288. fclose(passwd);
  289. }
  290. }
  291. #if defined(HAVE_YP_GET_DEFAULT_DOMAIN) && defined (HAVE_YP_BIND) && defined (HAVE_YP_MATCH) && defined (HAVE_YP_UNBIND)
  292. if (!matched && nis) {
  293. char *userinfo = NULL, *domain = NULL;
  294. int len = 0, i;
  295. len = yp_get_default_domain(&domain);
  296. if (len == YPERR_SUCCESS) {
  297. len = yp_bind(domain);
  298. }
  299. if (len == YPERR_SUCCESS) {
  300. i = yp_match(domain, "passwd.byname", name,
  301. strlen(name), &userinfo, &len);
  302. yp_unbind(domain);
  303. if ((i == YPERR_SUCCESS) && ((size_t)len < sizeof(buf))) {
  304. strncpy(buf, userinfo, sizeof(buf) - 1);
  305. buf[sizeof(buf) - 1] = '\0';
  306. matched = 1;
  307. }
  308. }
  309. }
  310. #else
  311. /* we don't have NIS support, make compiler happy. */
  312. (void) nis;
  313. #endif
  314. if (matched && (ret != NULL)) {
  315. *ret = NULL;
  316. slogin = buf;
  317. spasswd = strchr(slogin, ':');
  318. if (spasswd == NULL) {
  319. return matched;
  320. }
  321. *spasswd++ = '\0';
  322. suid = strchr(spasswd, ':');
  323. if (suid == NULL) {
  324. return matched;
  325. }
  326. *suid++ = '\0';
  327. sgid = strchr(suid, ':');
  328. if (sgid == NULL) {
  329. return matched;
  330. }
  331. *sgid++ = '\0';
  332. sgecos = strchr(sgid, ':');
  333. if (sgecos == NULL) {
  334. return matched;
  335. }
  336. *sgecos++ = '\0';
  337. shome = strchr(sgecos, ':');
  338. if (shome == NULL) {
  339. return matched;
  340. }
  341. *shome++ = '\0';
  342. sshell = strchr(shome, ':');
  343. if (sshell == NULL) {
  344. return matched;
  345. }
  346. *sshell++ = '\0';
  347. buflen = sizeof(struct passwd) +
  348. strlen(slogin) + 1 +
  349. strlen(spasswd) + 1 +
  350. strlen(sgecos) + 1 +
  351. strlen(shome) + 1 +
  352. strlen(sshell) + 1;
  353. *ret = malloc(buflen);
  354. if (*ret == NULL) {
  355. return matched;
  356. }
  357. memset(*ret, '\0', buflen);
  358. (*ret)->pw_uid = strtol(suid, &p, 10);
  359. if ((strlen(suid) == 0) || (*p != '\0')) {
  360. free(*ret);
  361. *ret = NULL;
  362. return matched;
  363. }
  364. (*ret)->pw_gid = strtol(sgid, &p, 10);
  365. if ((strlen(sgid) == 0) || (*p != '\0')) {
  366. free(*ret);
  367. *ret = NULL;
  368. return matched;
  369. }
  370. p = ((char*)(*ret)) + sizeof(struct passwd);
  371. (*ret)->pw_name = strcpy(p, slogin);
  372. p += strlen(p) + 1;
  373. (*ret)->pw_passwd = strcpy(p, spasswd);
  374. p += strlen(p) + 1;
  375. (*ret)->pw_gecos = strcpy(p, sgecos);
  376. p += strlen(p) + 1;
  377. (*ret)->pw_dir = strcpy(p, shome);
  378. p += strlen(p) + 1;
  379. (*ret)->pw_shell = strcpy(p, sshell);
  380. snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name);
  381. if (pam_set_data(pamh, buf,
  382. *ret, _unix_cleanup) != PAM_SUCCESS) {
  383. free(*ret);
  384. *ret = NULL;
  385. }
  386. }
  387. return matched;
  388. }
  389. /*
  390. * _unix_comsefromsource() is a quick check to see if information about a given
  391. * user comes from a particular source (just files and nis for now)
  392. *
  393. */
  394. int _unix_comesfromsource(pam_handle_t *pamh,
  395. const char *name, int files, int nis)
  396. {
  397. return _unix_getpwnam(pamh, name, files, nis, NULL);
  398. }
  399. /*
  400. * verify the password of a user
  401. */
  402. #include <sys/types.h>
  403. #include <sys/wait.h>
  404. static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
  405. unsigned long long ctrl, const char *user)
  406. {
  407. int retval, child, fds[2];
  408. struct sigaction newsa, oldsa;
  409. D(("called."));
  410. /* create a pipe for the password */
  411. if (pipe(fds) != 0) {
  412. D(("could not make pipe"));
  413. return PAM_AUTH_ERR;
  414. }
  415. if (off(UNIX_NOREAP, ctrl)) {
  416. /*
  417. * This code arranges that the demise of the child does not cause
  418. * the application to receive a signal it is not expecting - which
  419. * may kill the application or worse.
  420. *
  421. * The "noreap" module argument is provided so that the admin can
  422. * override this behavior.
  423. */
  424. memset(&newsa, '\0', sizeof(newsa));
  425. newsa.sa_handler = SIG_DFL;
  426. sigaction(SIGCHLD, &newsa, &oldsa);
  427. }
  428. /* fork */
  429. child = fork();
  430. if (child == 0) {
  431. static char *envp[] = { NULL };
  432. const char *args[] = { NULL, NULL, NULL, NULL };
  433. /* XXX - should really tidy up PAM here too */
  434. /* reopen stdin as pipe */
  435. if (dup2(fds[0], STDIN_FILENO) != STDIN_FILENO) {
  436. pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdin");
  437. _exit(PAM_AUTHINFO_UNAVAIL);
  438. }
  439. if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_IGNORE_FD,
  440. PAM_MODUTIL_PIPE_FD,
  441. PAM_MODUTIL_PIPE_FD) < 0) {
  442. _exit(PAM_AUTHINFO_UNAVAIL);
  443. }
  444. if (geteuid() == 0) {
  445. /* must set the real uid to 0 so the helper will not error
  446. out if pam is called from setuid binary (su, sudo...) */
  447. if (setuid(0) == -1) {
  448. D(("setuid failed"));
  449. _exit(PAM_AUTHINFO_UNAVAIL);
  450. }
  451. }
  452. /* exec binary helper */
  453. args[0] = CHKPWD_HELPER;
  454. args[1] = user;
  455. if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */
  456. args[2]="nullok";
  457. } else {
  458. args[2]="nonull";
  459. }
  460. DIAG_PUSH_IGNORE_CAST_QUAL;
  461. execve(CHKPWD_HELPER, (char *const *) args, envp);
  462. DIAG_POP_IGNORE_CAST_QUAL;
  463. /* should not get here: exit with error */
  464. D(("helper binary is not available"));
  465. _exit(PAM_AUTHINFO_UNAVAIL);
  466. } else if (child > 0) {
  467. /* wait for child */
  468. /* if the stored password is NULL */
  469. int rc=0;
  470. if (passwd != NULL) { /* send the password to the child */
  471. int len = strlen(passwd);
  472. if (len > PAM_MAX_RESP_SIZE)
  473. len = PAM_MAX_RESP_SIZE;
  474. if (write(fds[1], passwd, len) == -1 ||
  475. write(fds[1], "", 1) == -1) {
  476. pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m");
  477. retval = PAM_AUTH_ERR;
  478. }
  479. passwd = NULL;
  480. } else { /* blank password */
  481. if (write(fds[1], "", 1) == -1) {
  482. pam_syslog (pamh, LOG_ERR, "Cannot send password to helper: %m");
  483. retval = PAM_AUTH_ERR;
  484. }
  485. }
  486. close(fds[0]); /* close here to avoid possible SIGPIPE above */
  487. close(fds[1]);
  488. /* wait for helper to complete: */
  489. while ((rc=waitpid(child, &retval, 0)) < 0 && errno == EINTR);
  490. if (rc<0) {
  491. pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc);
  492. retval = PAM_AUTH_ERR;
  493. } else if (!WIFEXITED(retval)) {
  494. pam_syslog(pamh, LOG_ERR, "unix_chkpwd abnormal exit: %d", retval);
  495. retval = PAM_AUTH_ERR;
  496. } else {
  497. retval = WEXITSTATUS(retval);
  498. }
  499. } else {
  500. D(("fork failed"));
  501. close(fds[0]);
  502. close(fds[1]);
  503. retval = PAM_AUTH_ERR;
  504. }
  505. if (off(UNIX_NOREAP, ctrl)) {
  506. sigaction(SIGCHLD, &oldsa, NULL); /* restore old signal handler */
  507. }
  508. D(("returning %d", retval));
  509. return retval;
  510. }
  511. /*
  512. * _unix_blankpasswd() is a quick check for a blank password
  513. *
  514. * returns TRUE if user does not have a password
  515. * - to avoid prompting for one in such cases (CG)
  516. */
  517. int
  518. _unix_blankpasswd (pam_handle_t *pamh, unsigned long long ctrl, const char *name)
  519. {
  520. struct passwd *pwd = NULL;
  521. char *salt = NULL;
  522. int daysleft;
  523. int retval;
  524. int blank = 0;
  525. int execloop;
  526. int nonexistent_check = 1;
  527. D(("called"));
  528. /*
  529. * This function does not have to be too smart if something goes
  530. * wrong, return FALSE and let this case to be treated somewhere
  531. * else (CG)
  532. */
  533. if (on(UNIX_NULLRESETOK, ctrl)) {
  534. retval = _unix_verify_user(pamh, ctrl, name, &daysleft);
  535. if (retval == PAM_NEW_AUTHTOK_REQD) {
  536. /* password reset is enforced, allow authentication with empty password */
  537. pam_syslog(pamh, LOG_DEBUG, "user [%s] has expired blank password, enabling nullok", name);
  538. set(UNIX__NULLOK, ctrl);
  539. }
  540. }
  541. if (on(UNIX__NONULL, ctrl))
  542. return 0; /* will fail but don't let on yet */
  543. /* UNIX passwords area */
  544. /*
  545. * Execute this loop twice: one checking the password hash of an existing
  546. * user and another one for a non-existing user. This way the runtimes
  547. * are equal, making it more difficult to differentiate existing from
  548. * non-existing users.
  549. */
  550. for (execloop = 0; execloop < 2; ++execloop) {
  551. retval = get_pwd_hash(pamh, name, &pwd, &salt);
  552. if (retval == PAM_UNIX_RUN_HELPER) {
  553. if (_unix_run_helper_binary(pamh, NULL, ctrl, name) == PAM_SUCCESS)
  554. blank = nonexistent_check;
  555. } else if (retval == PAM_USER_UNKNOWN) {
  556. name = "root";
  557. nonexistent_check = 0;
  558. continue;
  559. } else if (salt != NULL) {
  560. if (strlen(salt) == 0)
  561. blank = nonexistent_check;
  562. }
  563. name = "pam_unix_non_existent:";
  564. /* non-existent user check will not affect the blank value */
  565. }
  566. /* tidy up */
  567. if (salt)
  568. _pam_delete(salt);
  569. return blank;
  570. }
  571. int _unix_verify_password(pam_handle_t * pamh, const char *name
  572. ,const char *p, unsigned long long ctrl)
  573. {
  574. struct passwd *pwd = NULL;
  575. char *salt = NULL;
  576. char *data_name;
  577. char pw[PAM_MAX_RESP_SIZE + 1];
  578. int retval;
  579. D(("called"));
  580. #ifdef HAVE_PAM_FAIL_DELAY
  581. if (off(UNIX_NODELAY, ctrl)) {
  582. D(("setting delay"));
  583. (void) pam_fail_delay(pamh, 2000000); /* 2 sec delay for on failure */
  584. }
  585. #endif
  586. /* locate the entry for this user */
  587. D(("locating user's record"));
  588. retval = get_pwd_hash(pamh, name, &pwd, &salt);
  589. data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name));
  590. if (data_name == NULL) {
  591. pam_syslog(pamh, LOG_CRIT, "no memory for data-name");
  592. } else {
  593. strcpy(data_name, FAIL_PREFIX);
  594. strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name);
  595. }
  596. if (p != NULL && strlen(p) > PAM_MAX_RESP_SIZE) {
  597. memset(pw, 0, sizeof(pw));
  598. p = strncpy(pw, p, sizeof(pw) - 1);
  599. }
  600. if (retval != PAM_SUCCESS) {
  601. if (retval == PAM_UNIX_RUN_HELPER) {
  602. D(("running helper binary"));
  603. retval = _unix_run_helper_binary(pamh, p, ctrl, name);
  604. } else {
  605. D(("user's record unavailable"));
  606. p = NULL;
  607. if (on(UNIX_AUDIT, ctrl)) {
  608. /* this might be a typo and the user has given a password
  609. instead of a username. Careful with this. */
  610. pam_syslog(pamh, LOG_NOTICE,
  611. "check pass; user (%s) unknown", name);
  612. } else {
  613. name = NULL;
  614. if (on(UNIX_DEBUG, ctrl) || pwd == NULL) {
  615. pam_syslog(pamh, LOG_NOTICE,
  616. "check pass; user unknown");
  617. } else {
  618. /* don't log failure as another pam module can succeed */
  619. goto cleanup;
  620. }
  621. }
  622. }
  623. } else {
  624. retval = verify_pwd_hash(pamh, p, salt, off(UNIX__NONULL, ctrl));
  625. }
  626. if (retval == PAM_SUCCESS) {
  627. if (data_name) /* reset failures */
  628. pam_set_data(pamh, data_name, NULL, _cleanup_failures);
  629. } else {
  630. if (data_name != NULL) {
  631. struct _pam_failed_auth *new = NULL;
  632. const struct _pam_failed_auth *old = NULL;
  633. /* get a failure recorder */
  634. new = (struct _pam_failed_auth *)
  635. malloc(sizeof(struct _pam_failed_auth));
  636. if (new != NULL) {
  637. const char *login_name;
  638. const void *void_old;
  639. login_name = pam_modutil_getlogin(pamh);
  640. if (login_name == NULL) {
  641. login_name = "";
  642. }
  643. new->user = strdup(name ? name : "");
  644. new->uid = getuid();
  645. new->euid = geteuid();
  646. new->name = strdup(login_name);
  647. /* any previous failures for this user ? */
  648. if (pam_get_data(pamh, data_name, &void_old)
  649. == PAM_SUCCESS)
  650. old = void_old;
  651. else
  652. old = NULL;
  653. if (old != NULL) {
  654. new->count = old->count + 1;
  655. if (new->count >= UNIX_MAX_RETRIES) {
  656. retval = PAM_MAXTRIES;
  657. }
  658. } else {
  659. const void *service=NULL;
  660. const void *ruser=NULL;
  661. const void *rhost=NULL;
  662. const void *tty=NULL;
  663. (void) pam_get_item(pamh, PAM_SERVICE,
  664. &service);
  665. (void) pam_get_item(pamh, PAM_RUSER,
  666. &ruser);
  667. (void) pam_get_item(pamh, PAM_RHOST,
  668. &rhost);
  669. (void) pam_get_item(pamh, PAM_TTY,
  670. &tty);
  671. pam_syslog(pamh, LOG_NOTICE,
  672. "authentication failure; "
  673. "logname=%s uid=%d euid=%d "
  674. "tty=%s ruser=%s rhost=%s "
  675. "%s%s",
  676. new->name, new->uid, new->euid,
  677. tty ? (const char *)tty : "",
  678. ruser ? (const char *)ruser : "",
  679. rhost ? (const char *)rhost : "",
  680. (new->user && new->user[0] != '\0')
  681. ? " user=" : "",
  682. new->user
  683. );
  684. new->count = 1;
  685. }
  686. pam_set_data(pamh, data_name, new, _cleanup_failures);
  687. } else {
  688. pam_syslog(pamh, LOG_CRIT,
  689. "no memory for failure recorder");
  690. }
  691. }
  692. }
  693. cleanup:
  694. memset(pw, 0, sizeof(pw)); /* clear memory of the password */
  695. if (data_name)
  696. _pam_delete(data_name);
  697. if (salt)
  698. _pam_delete(salt);
  699. D(("done [%d].", retval));
  700. return retval;
  701. }
  702. int
  703. _unix_verify_user(pam_handle_t *pamh,
  704. unsigned long long ctrl,
  705. const char *name,
  706. int *daysleft)
  707. {
  708. int retval;
  709. struct spwd *spent;
  710. struct passwd *pwent;
  711. retval = get_account_info(pamh, name, &pwent, &spent);
  712. if (retval == PAM_USER_UNKNOWN) {
  713. pam_syslog(pamh, LOG_ERR,
  714. "could not identify user (from getpwnam(%s))",
  715. name);
  716. return retval;
  717. }
  718. if (retval == PAM_SUCCESS && spent == NULL)
  719. return PAM_SUCCESS;
  720. if (retval == PAM_UNIX_RUN_HELPER) {
  721. retval = _unix_run_verify_binary(pamh, ctrl, name, daysleft);
  722. if (retval == PAM_AUTHINFO_UNAVAIL &&
  723. on(UNIX_BROKEN_SHADOW, ctrl))
  724. return PAM_SUCCESS;
  725. } else if (retval != PAM_SUCCESS) {
  726. if (on(UNIX_BROKEN_SHADOW,ctrl))
  727. return PAM_SUCCESS;
  728. else
  729. return retval;
  730. } else
  731. retval = check_shadow_expiry(pamh, spent, daysleft);
  732. return retval;
  733. }
  734. /* ****************************************************************** *
  735. * Copyright (c) Jan Rękorajski 1999.
  736. * Copyright (c) Andrew G. Morgan 1996-8.
  737. * Copyright (c) Alex O. Yuriev, 1996.
  738. * Copyright (c) Cristian Gafton 1996.
  739. * Copyright (c) Red Hat, Inc. 2007.
  740. *
  741. * Redistribution and use in source and binary forms, with or without
  742. * modification, are permitted provided that the following conditions
  743. * are met:
  744. * 1. Redistributions of source code must retain the above copyright
  745. * notice, and the entire permission notice in its entirety,
  746. * including the disclaimer of warranties.
  747. * 2. Redistributions in binary form must reproduce the above copyright
  748. * notice, this list of conditions and the following disclaimer in the
  749. * documentation and/or other materials provided with the distribution.
  750. * 3. The name of the author may not be used to endorse or promote
  751. * products derived from this software without specific prior
  752. * written permission.
  753. *
  754. * ALTERNATIVELY, this product may be distributed under the terms of
  755. * the GNU Public License, in which case the provisions of the GPL are
  756. * required INSTEAD OF the above restrictions. (This clause is
  757. * necessary due to a potential bad interaction between the GPL and
  758. * the restrictions contained in a BSD-style copyright.)
  759. *
  760. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  761. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  762. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  763. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  764. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  765. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  766. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  767. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  768. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  769. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  770. * OF THE POSSIBILITY OF SUCH DAMAGE.
  771. */