pam_lastlog.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. /*
  2. * pam_lastlog module
  3. *
  4. * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11
  5. *
  6. * This module does the necessary work to display the last login
  7. * time+date for this user, it then updates this entry for the
  8. * present (login) service.
  9. */
  10. #include "config.h"
  11. #include <fcntl.h>
  12. #include <time.h>
  13. #include <errno.h>
  14. #ifdef HAVE_UTMP_H
  15. # include <utmp.h>
  16. #else
  17. # include <lastlog.h>
  18. #endif
  19. #include <pwd.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <sys/types.h>
  26. #include <sys/time.h>
  27. #include <sys/resource.h>
  28. #include <syslog.h>
  29. #include <unistd.h>
  30. #if defined(hpux) || defined(sunos) || defined(solaris)
  31. # ifndef _PATH_LASTLOG
  32. # define _PATH_LASTLOG "/usr/adm/lastlog"
  33. # endif /* _PATH_LASTLOG */
  34. # ifndef UT_HOSTSIZE
  35. # define UT_HOSTSIZE 16
  36. # endif /* UT_HOSTSIZE */
  37. # ifndef UT_LINESIZE
  38. # define UT_LINESIZE 12
  39. # endif /* UT_LINESIZE */
  40. #endif
  41. #if defined(hpux)
  42. struct lastlog {
  43. time_t ll_time;
  44. char ll_line[UT_LINESIZE];
  45. char ll_host[UT_HOSTSIZE]; /* same as in utmp */
  46. };
  47. #endif /* hpux */
  48. #ifndef _PATH_BTMP
  49. # define _PATH_BTMP "/var/log/btmp"
  50. #endif
  51. #ifndef PATH_LOGIN_DEFS
  52. # define PATH_LOGIN_DEFS "/etc/login.defs"
  53. #endif
  54. /* XXX - time before ignoring lock. Is 1 sec enough? */
  55. #define LASTLOG_IGNORE_LOCK_TIME 1
  56. #define DEFAULT_HOST "" /* "[no.where]" */
  57. #define DEFAULT_TERM "" /* "tt???" */
  58. #define DEFAULT_INACTIVE_DAYS 90
  59. #define MAX_INACTIVE_DAYS 100000
  60. #include <security/pam_modules.h>
  61. #include <security/_pam_macros.h>
  62. #include <security/pam_modutil.h>
  63. #include <security/pam_ext.h>
  64. #include "pam_inline.h"
  65. /* argument parsing */
  66. #define LASTLOG_DATE 01 /* display the date of the last login */
  67. #define LASTLOG_HOST 02 /* display the last host used (if set) */
  68. #define LASTLOG_LINE 04 /* display the last terminal used */
  69. #define LASTLOG_NEVER 010 /* display a welcome message for first login */
  70. #define LASTLOG_DEBUG 020 /* send info to syslog(3) */
  71. #define LASTLOG_QUIET 040 /* keep quiet about things */
  72. #define LASTLOG_WTMP 0100 /* log to wtmp as well as lastlog */
  73. #define LASTLOG_BTMP 0200 /* display failed login info from btmp */
  74. #define LASTLOG_UPDATE 0400 /* update the lastlog and wtmp files (default) */
  75. #define LASTLOG_UNLIMITED 01000 /* unlimited file size (ignore 'fsize' limit) */
  76. static int
  77. _pam_auth_parse(pam_handle_t *pamh, int flags, int argc, const char **argv,
  78. time_t *inactive)
  79. {
  80. int ctrl = 0;
  81. *inactive = DEFAULT_INACTIVE_DAYS;
  82. /* does the application require quiet? */
  83. if (flags & PAM_SILENT) {
  84. ctrl |= LASTLOG_QUIET;
  85. }
  86. /* step through arguments */
  87. for (; argc-- > 0; ++argv) {
  88. const char *str;
  89. char *ep = NULL;
  90. long l;
  91. if (!strcmp(*argv,"debug")) {
  92. ctrl |= LASTLOG_DEBUG;
  93. } else if (!strcmp(*argv,"silent")) {
  94. ctrl |= LASTLOG_QUIET;
  95. } else if ((str = pam_str_skip_prefix(*argv, "inactive=")) != NULL) {
  96. l = strtol(str, &ep, 10);
  97. if (ep != str && l > 0 && l < MAX_INACTIVE_DAYS)
  98. *inactive = l;
  99. else {
  100. pam_syslog(pamh, LOG_ERR, "bad option value: %s", *argv);
  101. }
  102. } else {
  103. pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
  104. }
  105. }
  106. D(("ctrl = %o", ctrl));
  107. return ctrl;
  108. }
  109. static int
  110. _pam_session_parse(pam_handle_t *pamh, int flags, int argc, const char **argv)
  111. {
  112. int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE|LASTLOG_WTMP|LASTLOG_UPDATE);
  113. /* step through arguments */
  114. for (; argc-- > 0; ++argv) {
  115. /* generic options */
  116. if (!strcmp(*argv,"debug")) {
  117. ctrl |= LASTLOG_DEBUG;
  118. } else if (!strcmp(*argv,"nodate")) {
  119. ctrl &= ~LASTLOG_DATE;
  120. } else if (!strcmp(*argv,"noterm")) {
  121. ctrl &= ~LASTLOG_LINE;
  122. } else if (!strcmp(*argv,"nohost")) {
  123. ctrl &= ~LASTLOG_HOST;
  124. } else if (!strcmp(*argv,"silent")) {
  125. ctrl |= LASTLOG_QUIET;
  126. } else if (!strcmp(*argv,"never")) {
  127. ctrl |= LASTLOG_NEVER;
  128. } else if (!strcmp(*argv,"nowtmp")) {
  129. ctrl &= ~LASTLOG_WTMP;
  130. } else if (!strcmp(*argv,"noupdate")) {
  131. ctrl &= ~(LASTLOG_WTMP|LASTLOG_UPDATE);
  132. } else if (!strcmp(*argv,"showfailed")) {
  133. ctrl |= LASTLOG_BTMP;
  134. } else if (!strcmp(*argv,"unlimited")) {
  135. ctrl |= LASTLOG_UNLIMITED;
  136. } else {
  137. pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
  138. }
  139. }
  140. /* does the application require quiet? */
  141. if (flags & PAM_SILENT) {
  142. ctrl |= LASTLOG_QUIET;
  143. ctrl &= ~LASTLOG_BTMP;
  144. }
  145. D(("ctrl = %o", ctrl));
  146. return ctrl;
  147. }
  148. static const char *
  149. get_tty(pam_handle_t *pamh)
  150. {
  151. const void *void_terminal_line = NULL;
  152. const char *terminal_line;
  153. const char *str;
  154. if (pam_get_item(pamh, PAM_TTY, &void_terminal_line) != PAM_SUCCESS
  155. || void_terminal_line == NULL) {
  156. terminal_line = DEFAULT_TERM;
  157. } else {
  158. terminal_line = void_terminal_line;
  159. }
  160. /* strip leading "/dev/" from tty. */
  161. str = pam_str_skip_prefix(terminal_line, "/dev/");
  162. if (str != NULL)
  163. terminal_line = str;
  164. D(("terminal = %s", terminal_line));
  165. return terminal_line;
  166. }
  167. #define MAX_UID_VALUE 0xFFFFFFFFUL
  168. static uid_t
  169. get_lastlog_uid_max(pam_handle_t *pamh)
  170. {
  171. uid_t uid_max = MAX_UID_VALUE;
  172. unsigned long ul;
  173. char *s, *ep;
  174. s = pam_modutil_search_key(pamh, PATH_LOGIN_DEFS, "LASTLOG_UID_MAX");
  175. if (s == NULL)
  176. return uid_max;
  177. ep = s + strlen(s);
  178. while (ep > s && isspace(*(--ep))) {
  179. *ep = '\0';
  180. }
  181. errno = 0;
  182. ul = strtoul(s, &ep, 10);
  183. if (!(ul >= MAX_UID_VALUE
  184. || (uid_t)ul >= MAX_UID_VALUE
  185. || (errno != 0 && ul == 0)
  186. || s == ep
  187. || *ep != '\0')) {
  188. uid_max = (uid_t)ul;
  189. }
  190. free(s);
  191. return uid_max;
  192. }
  193. static int
  194. last_login_open(pam_handle_t *pamh, int announce, uid_t uid)
  195. {
  196. int last_fd;
  197. /* obtain the last login date and all the relevant info */
  198. last_fd = open(_PATH_LASTLOG, announce&LASTLOG_UPDATE ? O_RDWR : O_RDONLY);
  199. if (last_fd < 0) {
  200. if (errno == ENOENT && (announce & LASTLOG_UPDATE)) {
  201. last_fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT,
  202. S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
  203. if (last_fd < 0) {
  204. pam_syslog(pamh, LOG_ERR,
  205. "unable to create %s: %m", _PATH_LASTLOG);
  206. D(("unable to create %s file", _PATH_LASTLOG));
  207. return -1;
  208. }
  209. pam_syslog(pamh, LOG_NOTICE,
  210. "file %s created", _PATH_LASTLOG);
  211. D(("file %s created", _PATH_LASTLOG));
  212. } else {
  213. pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_LASTLOG);
  214. D(("unable to open %s file", _PATH_LASTLOG));
  215. return -1;
  216. }
  217. }
  218. if (lseek(last_fd, sizeof(struct lastlog) * (off_t) uid, SEEK_SET) < 0) {
  219. pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG);
  220. D(("unable to lseek %s file", _PATH_LASTLOG));
  221. close(last_fd);
  222. return -1;
  223. }
  224. return last_fd;
  225. }
  226. static int
  227. last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t *lltime)
  228. {
  229. struct flock last_lock;
  230. struct lastlog last_login;
  231. int retval = PAM_SUCCESS;
  232. char the_time[256];
  233. char *date = NULL;
  234. char *host = NULL;
  235. char *line = NULL;
  236. memset(&last_lock, 0, sizeof(last_lock));
  237. last_lock.l_type = F_RDLCK;
  238. last_lock.l_whence = SEEK_SET;
  239. last_lock.l_start = sizeof(last_login) * (off_t) uid;
  240. last_lock.l_len = sizeof(last_login);
  241. if (fcntl(last_fd, F_SETLK, &last_lock) < 0) {
  242. D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
  243. pam_syslog(pamh, LOG_WARNING,
  244. "file %s is locked/read", _PATH_LASTLOG);
  245. sleep(LASTLOG_IGNORE_LOCK_TIME);
  246. }
  247. if (pam_modutil_read(last_fd, (char *) &last_login,
  248. sizeof(last_login)) != sizeof(last_login)) {
  249. memset(&last_login, 0, sizeof(last_login));
  250. }
  251. last_lock.l_type = F_UNLCK;
  252. (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
  253. *lltime = last_login.ll_time;
  254. if (!last_login.ll_time) {
  255. if (announce & LASTLOG_DEBUG) {
  256. pam_syslog(pamh, LOG_DEBUG,
  257. "first login for user with uid %lu",
  258. (unsigned long int)uid);
  259. }
  260. }
  261. if (!(announce & LASTLOG_QUIET)) {
  262. if (last_login.ll_time) {
  263. /* we want the date? */
  264. if (announce & LASTLOG_DATE) {
  265. struct tm *tm, tm_buf;
  266. time_t ll_time;
  267. ll_time = last_login.ll_time;
  268. if ((tm = localtime_r (&ll_time, &tm_buf)) != NULL) {
  269. strftime (the_time, sizeof (the_time),
  270. /* TRANSLATORS: "strftime options for date of last login" */
  271. _(" %a %b %e %H:%M:%S %Z %Y"), tm);
  272. date = the_time;
  273. }
  274. }
  275. /* we want & have the host? */
  276. if ((announce & LASTLOG_HOST)
  277. && (last_login.ll_host[0] != '\0')) {
  278. /* TRANSLATORS: " from <host>" */
  279. if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
  280. last_login.ll_host) < 0) {
  281. pam_syslog(pamh, LOG_CRIT, "out of memory");
  282. retval = PAM_BUF_ERR;
  283. goto cleanup;
  284. }
  285. }
  286. /* we want and have the terminal? */
  287. if ((announce & LASTLOG_LINE)
  288. && (last_login.ll_line[0] != '\0')) {
  289. /* TRANSLATORS: " on <terminal>" */
  290. if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
  291. last_login.ll_line) < 0) {
  292. pam_syslog(pamh, LOG_CRIT, "out of memory");
  293. retval = PAM_BUF_ERR;
  294. goto cleanup;
  295. }
  296. }
  297. if (date != NULL || host != NULL || line != NULL)
  298. /* TRANSLATORS: "Last login: <date> from <host> on <terminal>" */
  299. retval = pam_info(pamh, _("Last login:%s%s%s"),
  300. date ? date : "",
  301. host ? host : "",
  302. line ? line : "");
  303. } else if (announce & LASTLOG_NEVER) {
  304. D(("this is the first time this user has logged in"));
  305. retval = pam_info(pamh, "%s", _("Welcome to your new account!"));
  306. }
  307. }
  308. /* cleanup */
  309. cleanup:
  310. memset(&last_login, 0, sizeof(last_login));
  311. _pam_overwrite(date);
  312. _pam_overwrite(host);
  313. _pam_drop(host);
  314. _pam_overwrite(line);
  315. _pam_drop(line);
  316. return retval;
  317. }
  318. static int
  319. last_login_write(pam_handle_t *pamh, int announce, int last_fd,
  320. uid_t uid, const char *user)
  321. {
  322. static struct rlimit no_limit = {
  323. RLIM_INFINITY,
  324. RLIM_INFINITY
  325. };
  326. struct rlimit old_limit;
  327. int setrlimit_res;
  328. struct flock last_lock;
  329. struct lastlog last_login;
  330. time_t ll_time;
  331. const void *void_remote_host = NULL;
  332. const char *remote_host;
  333. const char *terminal_line;
  334. int retval = PAM_SUCCESS;
  335. /* rewind */
  336. if (lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET) < 0) {
  337. pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG);
  338. return PAM_SERVICE_ERR;
  339. }
  340. memset(&last_login, 0, sizeof(last_login));
  341. /* set this login date */
  342. D(("set the most recent login time"));
  343. (void) time(&ll_time); /* set the time */
  344. last_login.ll_time = ll_time;
  345. /* set the remote host */
  346. if (pam_get_item(pamh, PAM_RHOST, &void_remote_host) != PAM_SUCCESS
  347. || void_remote_host == NULL) {
  348. remote_host = DEFAULT_HOST;
  349. } else {
  350. remote_host = void_remote_host;
  351. }
  352. /* copy to last_login */
  353. strncat(last_login.ll_host, remote_host, sizeof(last_login.ll_host)-1);
  354. /* set the terminal line */
  355. terminal_line = get_tty(pamh);
  356. /* copy to last_login */
  357. strncat(last_login.ll_line, terminal_line, sizeof(last_login.ll_line)-1);
  358. terminal_line = NULL;
  359. D(("locking lastlog file"));
  360. /* now we try to lock this file-record exclusively; non-blocking */
  361. memset(&last_lock, 0, sizeof(last_lock));
  362. last_lock.l_type = F_WRLCK;
  363. last_lock.l_whence = SEEK_SET;
  364. last_lock.l_start = sizeof(last_login) * (off_t) uid;
  365. last_lock.l_len = sizeof(last_login);
  366. if (fcntl(last_fd, F_SETLK, &last_lock) < 0) {
  367. D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
  368. pam_syslog(pamh, LOG_WARNING, "file %s is locked/write", _PATH_LASTLOG);
  369. sleep(LASTLOG_IGNORE_LOCK_TIME);
  370. }
  371. /*
  372. * Failing to set the 'fsize' limit is not a fatal error. We try to write
  373. * lastlog anyway, under the risk of dying due to a SIGXFSZ.
  374. */
  375. D(("setting limit for 'fsize'"));
  376. if ((announce & LASTLOG_UNLIMITED) == 0) { /* don't set to unlimited */
  377. setrlimit_res = -1;
  378. } else if (getrlimit(RLIMIT_FSIZE, &old_limit) == 0) {
  379. if (old_limit.rlim_cur == RLIM_INFINITY) { /* already unlimited */
  380. setrlimit_res = -1;
  381. } else {
  382. setrlimit_res = setrlimit(RLIMIT_FSIZE, &no_limit);
  383. if (setrlimit_res != 0)
  384. pam_syslog(pamh, LOG_WARNING, "Could not set limit for 'fsize': %m");
  385. }
  386. } else {
  387. setrlimit_res = -1;
  388. if (errno == EINVAL) {
  389. pam_syslog(pamh, LOG_INFO, "Limit for 'fsize' not supported: %m");
  390. } else {
  391. pam_syslog(pamh, LOG_WARNING, "Could not get limit for 'fsize': %m");
  392. }
  393. }
  394. D(("writing to the lastlog file"));
  395. if (pam_modutil_write (last_fd, (char *) &last_login,
  396. sizeof (last_login)) != sizeof(last_login)) {
  397. pam_syslog(pamh, LOG_ERR, "failed to write %s: %m", _PATH_LASTLOG);
  398. retval = PAM_SERVICE_ERR;
  399. }
  400. /*
  401. * Failing to restore the 'fsize' limit is a fatal error.
  402. */
  403. D(("restoring limit for 'fsize'"));
  404. if (setrlimit_res == 0) {
  405. setrlimit_res = setrlimit(RLIMIT_FSIZE, &old_limit);
  406. if (setrlimit_res != 0) {
  407. pam_syslog(pamh, LOG_ERR, "Could not restore limit for 'fsize': %m");
  408. retval = PAM_SERVICE_ERR;
  409. }
  410. }
  411. last_lock.l_type = F_UNLCK;
  412. (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
  413. D(("unlocked"));
  414. if (announce & LASTLOG_WTMP) {
  415. /* write wtmp entry for user */
  416. logwtmp(last_login.ll_line, user, remote_host);
  417. }
  418. /* cleanup */
  419. memset(&last_login, 0, sizeof(last_login));
  420. return retval;
  421. }
  422. static int
  423. last_login_date(pam_handle_t *pamh, int announce, uid_t uid, const char *user, time_t *lltime)
  424. {
  425. int retval;
  426. int last_fd;
  427. if (uid > get_lastlog_uid_max(pamh)) {
  428. return PAM_SUCCESS;
  429. }
  430. /* obtain the last login date and all the relevant info */
  431. last_fd = last_login_open(pamh, announce, uid);
  432. if (last_fd < 0) {
  433. return PAM_SERVICE_ERR;
  434. }
  435. retval = last_login_read(pamh, announce, last_fd, uid, lltime);
  436. if (retval != PAM_SUCCESS)
  437. {
  438. close(last_fd);
  439. D(("error while reading lastlog file"));
  440. return retval;
  441. }
  442. if (announce & LASTLOG_UPDATE) {
  443. retval = last_login_write(pamh, announce, last_fd, uid, user);
  444. }
  445. close(last_fd);
  446. D(("all done with last login"));
  447. return retval;
  448. }
  449. static int
  450. last_login_failed(pam_handle_t *pamh, int announce, const char *user, time_t lltime)
  451. {
  452. int retval;
  453. int fd;
  454. struct utmp ut;
  455. struct utmp utuser;
  456. int failed = 0;
  457. char the_time[256];
  458. char *date = NULL;
  459. char *host = NULL;
  460. char *line = NULL;
  461. if (strlen(user) > UT_NAMESIZE) {
  462. pam_syslog(pamh, LOG_WARNING, "username too long, output might be inaccurate");
  463. }
  464. /* obtain the failed login attempt records from btmp */
  465. fd = open(_PATH_BTMP, O_RDONLY);
  466. if (fd < 0) {
  467. int save_errno = errno;
  468. pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_BTMP);
  469. D(("unable to open %s file", _PATH_BTMP));
  470. if (save_errno == ENOENT)
  471. return PAM_SUCCESS;
  472. else
  473. return PAM_SERVICE_ERR;
  474. }
  475. while ((retval=pam_modutil_read(fd, (void *)&ut,
  476. sizeof(ut))) == sizeof(ut)) {
  477. if (ut.ut_tv.tv_sec >= lltime && strncmp(ut.ut_user, user, UT_NAMESIZE) == 0) {
  478. memcpy(&utuser, &ut, sizeof(utuser));
  479. failed++;
  480. }
  481. }
  482. if (retval != 0)
  483. pam_syslog(pamh, LOG_ERR, "corruption detected in %s", _PATH_BTMP);
  484. retval = PAM_SUCCESS;
  485. if (failed) {
  486. /* we want the date? */
  487. if (announce & LASTLOG_DATE) {
  488. struct tm *tm, tm_buf;
  489. time_t lf_time;
  490. lf_time = utuser.ut_tv.tv_sec;
  491. tm = localtime_r (&lf_time, &tm_buf);
  492. strftime (the_time, sizeof (the_time),
  493. /* TRANSLATORS: "strftime options for date of last login" */
  494. _(" %a %b %e %H:%M:%S %Z %Y"), tm);
  495. date = the_time;
  496. }
  497. /* we want & have the host? */
  498. if ((announce & LASTLOG_HOST)
  499. && (utuser.ut_host[0] != '\0')) {
  500. /* TRANSLATORS: " from <host>" */
  501. if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
  502. utuser.ut_host) < 0) {
  503. pam_syslog(pamh, LOG_CRIT, "out of memory");
  504. retval = PAM_BUF_ERR;
  505. goto cleanup;
  506. }
  507. }
  508. /* we want and have the terminal? */
  509. if ((announce & LASTLOG_LINE)
  510. && (utuser.ut_line[0] != '\0')) {
  511. /* TRANSLATORS: " on <terminal>" */
  512. if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
  513. utuser.ut_line) < 0) {
  514. pam_syslog(pamh, LOG_CRIT, "out of memory");
  515. retval = PAM_BUF_ERR;
  516. goto cleanup;
  517. }
  518. }
  519. if (line != NULL || date != NULL || host != NULL) {
  520. /* TRANSLATORS: "Last failed login: <date> from <host> on <terminal>" */
  521. pam_info(pamh, _("Last failed login:%s%s%s"),
  522. date ? date : "",
  523. host ? host : "",
  524. line ? line : "");
  525. }
  526. _pam_drop(line);
  527. #if defined HAVE_DNGETTEXT && defined ENABLE_NLS
  528. retval = asprintf (&line, dngettext(PACKAGE,
  529. "There was %d failed login attempt since the last successful login.",
  530. "There were %d failed login attempts since the last successful login.",
  531. failed),
  532. failed);
  533. #else
  534. if (failed == 1)
  535. retval = asprintf(&line,
  536. _("There was %d failed login attempt since the last successful login."),
  537. failed);
  538. else
  539. retval = asprintf(&line,
  540. /* TRANSLATORS: only used if dngettext is not supported */
  541. _("There were %d failed login attempts since the last successful login."),
  542. failed);
  543. #endif
  544. if (retval >= 0)
  545. retval = pam_info(pamh, "%s", line);
  546. else {
  547. retval = PAM_BUF_ERR;
  548. line = NULL;
  549. }
  550. }
  551. cleanup:
  552. free(host);
  553. free(line);
  554. close(fd);
  555. D(("all done with btmp"));
  556. return retval;
  557. }
  558. /* --- authentication (locking out inactive users) functions --- */
  559. int
  560. pam_sm_authenticate(pam_handle_t *pamh, int flags,
  561. int argc, const char **argv)
  562. {
  563. int retval, ctrl;
  564. const char *user = NULL;
  565. const struct passwd *pwd;
  566. uid_t uid;
  567. time_t lltime = 0;
  568. time_t inactive_days = 0;
  569. int last_fd;
  570. /*
  571. * Lock out the user if he did not login recently enough.
  572. */
  573. ctrl = _pam_auth_parse(pamh, flags, argc, argv, &inactive_days);
  574. /* which user? */
  575. if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) {
  576. pam_syslog(pamh, LOG_NOTICE, "cannot determine user name");
  577. return PAM_USER_UNKNOWN;
  578. }
  579. /* what uid? */
  580. pwd = pam_modutil_getpwnam (pamh, user);
  581. if (pwd == NULL) {
  582. pam_syslog(pamh, LOG_NOTICE, "user unknown");
  583. return PAM_USER_UNKNOWN;
  584. }
  585. uid = pwd->pw_uid;
  586. pwd = NULL; /* tidy up */
  587. if (uid == 0 || uid > get_lastlog_uid_max(pamh))
  588. return PAM_SUCCESS;
  589. /* obtain the last login date and all the relevant info */
  590. last_fd = last_login_open(pamh, ctrl, uid);
  591. if (last_fd < 0) {
  592. return PAM_IGNORE;
  593. }
  594. retval = last_login_read(pamh, ctrl|LASTLOG_QUIET, last_fd, uid, &lltime);
  595. close(last_fd);
  596. if (retval != PAM_SUCCESS) {
  597. D(("error while reading lastlog file"));
  598. return PAM_IGNORE;
  599. }
  600. if (lltime == 0) { /* user never logged in before */
  601. if (ctrl & LASTLOG_DEBUG)
  602. pam_syslog(pamh, LOG_DEBUG, "user never logged in - pass");
  603. return PAM_SUCCESS;
  604. }
  605. lltime = (time(NULL) - lltime) / (24*60*60);
  606. if (lltime > inactive_days) {
  607. pam_syslog(pamh, LOG_INFO, "user %s inactive for %ld days - denied",
  608. user, (long) lltime);
  609. return PAM_AUTH_ERR;
  610. }
  611. return PAM_SUCCESS;
  612. }
  613. int
  614. pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
  615. int argc UNUSED, const char **argv UNUSED)
  616. {
  617. return PAM_SUCCESS;
  618. }
  619. int
  620. pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
  621. int argc, const char **argv)
  622. {
  623. return pam_sm_authenticate(pamh, flags, argc, argv);
  624. }
  625. /* --- session management functions --- */
  626. int
  627. pam_sm_open_session(pam_handle_t *pamh, int flags,
  628. int argc, const char **argv)
  629. {
  630. int retval, ctrl;
  631. const void *user;
  632. const struct passwd *pwd;
  633. uid_t uid;
  634. time_t lltime = 0;
  635. /*
  636. * this module gets the uid of the PAM_USER. Uses it to display
  637. * last login info and then updates the lastlog for that user.
  638. */
  639. ctrl = _pam_session_parse(pamh, flags, argc, argv);
  640. /* which user? */
  641. retval = pam_get_item(pamh, PAM_USER, &user);
  642. if (retval != PAM_SUCCESS || user == NULL || *(const char *)user == '\0') {
  643. pam_syslog(pamh, LOG_NOTICE, "user unknown");
  644. return PAM_USER_UNKNOWN;
  645. }
  646. /* what uid? */
  647. pwd = pam_modutil_getpwnam (pamh, user);
  648. if (pwd == NULL) {
  649. D(("couldn't identify user %s", user));
  650. return PAM_USER_UNKNOWN;
  651. }
  652. uid = pwd->pw_uid;
  653. pwd = NULL; /* tidy up */
  654. /* process the current login attempt (indicate last) */
  655. retval = last_login_date(pamh, ctrl, uid, user, &lltime);
  656. if ((ctrl & LASTLOG_BTMP) && retval == PAM_SUCCESS) {
  657. retval = last_login_failed(pamh, ctrl, user, lltime);
  658. }
  659. /* indicate success or failure */
  660. uid = -1; /* forget this */
  661. return retval;
  662. }
  663. int
  664. pam_sm_close_session (pam_handle_t *pamh, int flags,
  665. int argc, const char **argv)
  666. {
  667. const char *terminal_line;
  668. if (!(_pam_session_parse(pamh, flags, argc, argv) & LASTLOG_WTMP))
  669. return PAM_SUCCESS;
  670. terminal_line = get_tty(pamh);
  671. /* Wipe out utmp logout entry */
  672. logwtmp(terminal_line, "", "");
  673. return PAM_SUCCESS;
  674. }
  675. /* end of module definition */