/release/picobsd/tinyware/login/pico-login.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1093 lines · 783 code · 127 blank · 183 comment · 240 complexity · 31f94ace253a9165fd9e00bbccca14d5 MD5 · raw file

  1. /*-
  2. * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. All advertising materials mentioning features or use of this software
  14. * must display the following acknowledgement:
  15. * This product includes software developed by the University of
  16. * California, Berkeley and its contributors.
  17. * 4. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #if 0
  34. static char copyright[] =
  35. "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
  36. The Regents of the University of California. All rights reserved.\n";
  37. #endif
  38. #ifndef lint
  39. #if 0
  40. static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
  41. #endif
  42. static const char rcsid[] =
  43. "$FreeBSD$";
  44. #endif /* not lint */
  45. /*
  46. * login [ name ]
  47. * login -h hostname (for telnetd, etc.)
  48. * login -f name (for pre-authenticated login: datakit, xterm, etc.)
  49. */
  50. #include <sys/copyright.h>
  51. #include <sys/param.h>
  52. #include <sys/stat.h>
  53. #include <sys/socket.h>
  54. #include <sys/time.h>
  55. #include <sys/resource.h>
  56. #include <sys/file.h>
  57. #include <netinet/in.h>
  58. #include <arpa/inet.h>
  59. #include <err.h>
  60. #include <errno.h>
  61. #include <grp.h>
  62. #include <libutil.h>
  63. #include <login_cap.h>
  64. #include <netdb.h>
  65. #include <pwd.h>
  66. #include <setjmp.h>
  67. #include <signal.h>
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <syslog.h>
  72. #include <ttyent.h>
  73. #include <unistd.h>
  74. #include <utmpx.h>
  75. #ifdef USE_PAM
  76. #include <security/pam_appl.h>
  77. #include <security/openpam.h>
  78. #include <sys/wait.h>
  79. #endif /* USE_PAM */
  80. #include "pathnames.h"
  81. void badlogin(char *);
  82. void checknologin(void);
  83. void dolastlog(int);
  84. void getloginname(void);
  85. void motd(const char *);
  86. int rootterm(char *);
  87. void sigint(int);
  88. void sleepexit(int);
  89. void refused(char *,char *,int);
  90. char *stypeof(char *);
  91. void timedout(int);
  92. int login_access(char *, char *);
  93. void login_fbtab(char *, uid_t, gid_t);
  94. #ifdef USE_PAM
  95. static int auth_pam(void);
  96. static int export_pam_environment(void);
  97. static int ok_to_export(const char *);
  98. static pam_handle_t *pamh = NULL;
  99. static char **environ_pam;
  100. #define PAM_END { \
  101. if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
  102. syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \
  103. if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \
  104. syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \
  105. if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \
  106. syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \
  107. }
  108. #endif
  109. static int auth_traditional(void);
  110. static void usage(void);
  111. #define TTYGRPNAME "tty" /* name of group to own ttys */
  112. #define DEFAULT_BACKOFF 3
  113. #define DEFAULT_RETRIES 10
  114. #define DEFAULT_PROMPT "login: "
  115. #define DEFAULT_PASSWD_PROMPT "Password:"
  116. /*
  117. * This bounds the time given to login. Not a define so it can
  118. * be patched on machines where it's too small.
  119. */
  120. u_int timeout = 300;
  121. /* Buffer for signal handling of timeout */
  122. jmp_buf timeout_buf;
  123. struct passwd *pwd;
  124. int failures;
  125. char *term, *envinit[1], *hostname, *tty, *username;
  126. const char *passwd_prompt, *prompt;
  127. char full_hostname[MAXHOSTNAMELEN];
  128. int
  129. main(argc, argv)
  130. int argc;
  131. char *argv[];
  132. {
  133. extern char **environ;
  134. struct group *gr;
  135. struct stat st;
  136. struct utmpx utmp;
  137. int rootok, retries, backoff;
  138. int ask, ch, cnt, fflag, hflag, pflag, quietlog, rootlogin, rval;
  139. int changepass;
  140. time_t now, warntime;
  141. uid_t uid, euid;
  142. gid_t egid;
  143. char *p, *ttyn;
  144. char tbuf[MAXPATHLEN + 2];
  145. char tname[sizeof(_PATH_TTY) + 10];
  146. const char *shell = NULL;
  147. login_cap_t *lc = NULL;
  148. int UT_HOSTSIZE = sizeof(utmp.ut_host);
  149. int UT_NAMESIZE = sizeof(utmp.ut_user);
  150. #ifdef USE_PAM
  151. pid_t pid;
  152. int e;
  153. #endif /* USE_PAM */
  154. (void)signal(SIGQUIT, SIG_IGN);
  155. (void)signal(SIGINT, SIG_IGN);
  156. (void)signal(SIGHUP, SIG_IGN);
  157. if (setjmp(timeout_buf)) {
  158. if (failures)
  159. badlogin(tbuf);
  160. (void)fprintf(stderr, "Login timed out after %d seconds\n",
  161. timeout);
  162. exit(0);
  163. }
  164. (void)signal(SIGALRM, timedout);
  165. (void)alarm(timeout);
  166. (void)setpriority(PRIO_PROCESS, 0, 0);
  167. openlog("login", LOG_ODELAY, LOG_AUTH);
  168. /*
  169. * -p is used by getty to tell login not to destroy the environment
  170. * -f is used to skip a second login authentication
  171. * -h is used by other servers to pass the name of the remote
  172. * host to login so that it may be placed in utmp and wtmp
  173. */
  174. *full_hostname = '\0';
  175. term = NULL;
  176. fflag = hflag = pflag = 0;
  177. uid = getuid();
  178. euid = geteuid();
  179. egid = getegid();
  180. while ((ch = getopt(argc, argv, "fh:p")) != -1)
  181. switch (ch) {
  182. case 'f':
  183. fflag = 1;
  184. break;
  185. case 'h':
  186. if (uid)
  187. errx(1, "-h option: %s", strerror(EPERM));
  188. hflag = 1;
  189. if (strlcpy(full_hostname, optarg,
  190. sizeof(full_hostname)) >= sizeof(full_hostname))
  191. errx(1, "-h option: %s: exceeds maximum "
  192. "hostname size", optarg);
  193. trimdomain(optarg, UT_HOSTSIZE);
  194. if (strlen(optarg) > UT_HOSTSIZE) {
  195. struct addrinfo hints, *res;
  196. int ga_err;
  197. memset(&hints, 0, sizeof(hints));
  198. hints.ai_family = AF_UNSPEC;
  199. ga_err = getaddrinfo(optarg, NULL, &hints,
  200. &res);
  201. if (ga_err == 0) {
  202. char hostbuf[MAXHOSTNAMELEN];
  203. getnameinfo(res->ai_addr,
  204. res->ai_addrlen,
  205. hostbuf,
  206. sizeof(hostbuf), NULL, 0,
  207. NI_NUMERICHOST);
  208. optarg = strdup(hostbuf);
  209. if (optarg == NULL) {
  210. syslog(LOG_NOTICE,
  211. "strdup(): %m");
  212. sleepexit(1);
  213. }
  214. } else
  215. optarg = "invalid hostname";
  216. if (res != NULL)
  217. freeaddrinfo(res);
  218. }
  219. hostname = optarg;
  220. break;
  221. case 'p':
  222. pflag = 1;
  223. break;
  224. case '?':
  225. default:
  226. if (!uid)
  227. syslog(LOG_ERR, "invalid flag %c", ch);
  228. usage();
  229. }
  230. argc -= optind;
  231. argv += optind;
  232. if (*argv) {
  233. username = *argv;
  234. ask = 0;
  235. } else
  236. ask = 1;
  237. for (cnt = getdtablesize(); cnt > 2; cnt--)
  238. (void)close(cnt);
  239. ttyn = ttyname(STDIN_FILENO);
  240. if (ttyn == NULL || *ttyn == '\0') {
  241. (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
  242. ttyn = tname;
  243. }
  244. if ((tty = strrchr(ttyn, '/')) != NULL)
  245. ++tty;
  246. else
  247. tty = ttyn;
  248. /*
  249. * Get "login-retries" & "login-backoff" from default class
  250. */
  251. lc = login_getclass(NULL);
  252. prompt = login_getcapstr(lc, "login_prompt",
  253. DEFAULT_PROMPT, DEFAULT_PROMPT);
  254. passwd_prompt = login_getcapstr(lc, "passwd_prompt",
  255. DEFAULT_PASSWD_PROMPT, DEFAULT_PASSWD_PROMPT);
  256. retries = login_getcapnum(lc, "login-retries", DEFAULT_RETRIES,
  257. DEFAULT_RETRIES);
  258. backoff = login_getcapnum(lc, "login-backoff", DEFAULT_BACKOFF,
  259. DEFAULT_BACKOFF);
  260. login_close(lc);
  261. lc = NULL;
  262. for (cnt = 0;; ask = 1) {
  263. if (ask) {
  264. fflag = 0;
  265. getloginname();
  266. }
  267. rootlogin = 0;
  268. rootok = rootterm(tty); /* Default (auth may change) */
  269. if (strlen(username) > UT_NAMESIZE)
  270. username[UT_NAMESIZE] = '\0';
  271. /*
  272. * Note if trying multiple user names; log failures for
  273. * previous user name, but don't bother logging one failure
  274. * for nonexistent name (mistyped username).
  275. */
  276. if (failures && strcmp(tbuf, username)) {
  277. if (failures > (pwd ? 0 : 1))
  278. badlogin(tbuf);
  279. }
  280. (void)strlcpy(tbuf, username, sizeof(tbuf));
  281. pwd = getpwnam(username);
  282. /*
  283. * if we have a valid account name, and it doesn't have a
  284. * password, or the -f option was specified and the caller
  285. * is root or the caller isn't changing their uid, don't
  286. * authenticate.
  287. */
  288. if (pwd != NULL) {
  289. if (pwd->pw_uid == 0)
  290. rootlogin = 1;
  291. if (fflag && (uid == (uid_t)0 ||
  292. uid == (uid_t)pwd->pw_uid)) {
  293. /* already authenticated */
  294. break;
  295. } else if (pwd->pw_passwd[0] == '\0') {
  296. if (!rootlogin || rootok) {
  297. /* pretend password okay */
  298. rval = 0;
  299. goto ttycheck;
  300. }
  301. }
  302. }
  303. fflag = 0;
  304. (void)setpriority(PRIO_PROCESS, 0, -4);
  305. #ifdef USE_PAM
  306. /*
  307. * Try to authenticate using PAM. If a PAM system error
  308. * occurs, perhaps because of a botched configuration,
  309. * then fall back to using traditional Unix authentication.
  310. */
  311. if ((rval = auth_pam()) == -1)
  312. #endif /* USE_PAM */
  313. rval = auth_traditional();
  314. (void)setpriority(PRIO_PROCESS, 0, 0);
  315. #ifdef USE_PAM
  316. /*
  317. * PAM authentication may have changed "pwd" to the
  318. * entry for the template user. Check again to see if
  319. * this is a root login after all.
  320. */
  321. if (pwd != NULL && pwd->pw_uid == 0)
  322. rootlogin = 1;
  323. #endif /* USE_PAM */
  324. ttycheck:
  325. /*
  326. * If trying to log in as root without Kerberos,
  327. * but with insecure terminal, refuse the login attempt.
  328. */
  329. if (pwd && !rval) {
  330. if (rootlogin && !rootok)
  331. refused(NULL, "NOROOT", 0);
  332. else /* valid password & authenticated */
  333. break;
  334. }
  335. (void)printf("Login incorrect\n");
  336. failures++;
  337. /*
  338. * we allow up to 'retry' (10) tries,
  339. * but after 'backoff' (3) we start backing off
  340. */
  341. if (++cnt > backoff) {
  342. if (cnt >= retries) {
  343. badlogin(username);
  344. sleepexit(1);
  345. }
  346. sleep((u_int)((cnt - backoff) * 5));
  347. }
  348. }
  349. /* committed to login -- turn off timeout */
  350. (void)alarm((u_int)0);
  351. (void)signal(SIGHUP, SIG_DFL);
  352. endpwent();
  353. /*
  354. * Establish the login class.
  355. */
  356. lc = login_getpwclass(pwd);
  357. /* if user not super-user, check for disabled logins */
  358. if (!rootlogin)
  359. auth_checknologin(lc);
  360. quietlog = login_getcapbool(lc, "hushlogin", 0);
  361. /*
  362. * Switching needed for NFS with root access disabled.
  363. *
  364. * XXX: This change fails to modify the additional groups for the
  365. * process, and as such, may restrict rights normally granted
  366. * through those groups.
  367. */
  368. (void)setegid(pwd->pw_gid);
  369. (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
  370. if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
  371. if (login_getcapbool(lc, "requirehome", 0))
  372. refused("Home directory not available", "HOMEDIR", 1);
  373. if (chdir("/") < 0)
  374. refused("Cannot find root directory", "ROOTDIR", 1);
  375. if (!quietlog || *pwd->pw_dir)
  376. printf("No home directory.\nLogging in with home = \"/\".\n");
  377. pwd->pw_dir = "/";
  378. }
  379. (void)seteuid(euid);
  380. (void)setegid(egid);
  381. if (!quietlog)
  382. quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
  383. now = time(NULL);
  384. #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
  385. warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
  386. DEFAULT_WARN);
  387. if (pwd->pw_expire) {
  388. if (now >= pwd->pw_expire) {
  389. refused("Sorry -- your account has expired", "EXPIRED",
  390. 1);
  391. } else if (pwd->pw_expire - now < warntime && !quietlog)
  392. (void)printf("Warning: your account expires on %s",
  393. ctime(&pwd->pw_expire));
  394. }
  395. warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN,
  396. DEFAULT_WARN);
  397. changepass = 0;
  398. if (pwd->pw_change) {
  399. if (now >= pwd->pw_change) {
  400. (void)printf("Sorry -- your password has expired.\n");
  401. changepass = 1;
  402. syslog(LOG_INFO, "%s Password expired - forcing change",
  403. pwd->pw_name);
  404. } else if (pwd->pw_change - now < warntime && !quietlog)
  405. (void)printf("Warning: your password expires on %s",
  406. ctime(&pwd->pw_change));
  407. }
  408. if (lc != NULL) {
  409. if (hostname) {
  410. struct addrinfo hints, *res;
  411. int ga_err;
  412. memset(&hints, 0, sizeof(hints));
  413. hints.ai_family = AF_UNSPEC;
  414. ga_err = getaddrinfo(full_hostname, NULL, &hints,
  415. &res);
  416. if (ga_err == 0) {
  417. char hostbuf[MAXHOSTNAMELEN];
  418. getnameinfo(res->ai_addr, res->ai_addrlen,
  419. hostbuf, sizeof(hostbuf), NULL, 0,
  420. NI_NUMERICHOST);
  421. if ((optarg = strdup(hostbuf)) == NULL) {
  422. syslog(LOG_NOTICE, "strdup(): %m");
  423. sleepexit(1);
  424. }
  425. } else
  426. optarg = NULL;
  427. if (res != NULL)
  428. freeaddrinfo(res);
  429. if (!auth_hostok(lc, full_hostname, optarg))
  430. refused("Permission denied", "HOST", 1);
  431. }
  432. if (!auth_ttyok(lc, tty))
  433. refused("Permission denied", "TTY", 1);
  434. if (!auth_timeok(lc, time(NULL)))
  435. refused("Logins not available right now", "TIME", 1);
  436. }
  437. shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
  438. if (*pwd->pw_shell == '\0')
  439. pwd->pw_shell = _PATH_BSHELL;
  440. if (*shell == '\0') /* Not overridden */
  441. shell = pwd->pw_shell;
  442. if ((shell = strdup(shell)) == NULL) {
  443. syslog(LOG_NOTICE, "strdup(): %m");
  444. sleepexit(1);
  445. }
  446. #ifdef LOGIN_ACCESS
  447. if (login_access(pwd->pw_name, hostname ? full_hostname : tty) == 0)
  448. refused("Permission denied", "ACCESS", 1);
  449. #endif /* LOGIN_ACCESS */
  450. #if 1
  451. ulog_login(tty, username, hostname);
  452. #else
  453. /* Nothing else left to fail -- really log in. */
  454. memset((void *)&utmp, 0, sizeof(utmp));
  455. (void)gettimeofday(&utmp.ut_tv, NULL);
  456. (void)strncpy(utmp.ut_user, username, sizeof(utmp.ut_user));
  457. if (hostname)
  458. (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
  459. (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
  460. login(&utmp);
  461. #endif
  462. dolastlog(quietlog);
  463. /*
  464. * Set device protections, depending on what terminal the
  465. * user is logged in. This feature is used on Suns to give
  466. * console users better privacy.
  467. */
  468. login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
  469. /*
  470. * Clear flags of the tty. None should be set, and when the
  471. * user sets them otherwise, this can cause the chown to fail.
  472. * Since it isn't clear that flags are useful on character
  473. * devices, we just clear them.
  474. */
  475. if (chflags(ttyn, 0) && errno != EOPNOTSUPP)
  476. syslog(LOG_ERR, "chflags(%s): %m", ttyn);
  477. if (chown(ttyn, pwd->pw_uid,
  478. (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
  479. syslog(LOG_ERR, "chown(%s): %m", ttyn);
  480. /*
  481. * Preserve TERM if it happens to be already set.
  482. */
  483. if ((term = getenv("TERM")) != NULL) {
  484. if ((term = strdup(term)) == NULL) {
  485. syslog(LOG_NOTICE,
  486. "strdup(): %m");
  487. sleepexit(1);
  488. }
  489. }
  490. /*
  491. * Exclude cons/vt/ptys only, assume dialup otherwise
  492. * TODO: Make dialup tty determination a library call
  493. * for consistency (finger etc.)
  494. */
  495. if (hostname==NULL && isdialuptty(tty))
  496. syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
  497. #ifdef LOGALL
  498. /*
  499. * Syslog each successful login, so we don't have to watch hundreds
  500. * of wtmp or lastlogin files.
  501. */
  502. if (hostname)
  503. syslog(LOG_INFO, "login from %s on %s as %s",
  504. full_hostname, tty, pwd->pw_name);
  505. else
  506. syslog(LOG_INFO, "login on %s as %s",
  507. tty, pwd->pw_name);
  508. #endif
  509. /*
  510. * If fflag is on, assume caller/authenticator has logged root login.
  511. */
  512. if (rootlogin && fflag == 0)
  513. {
  514. if (hostname)
  515. syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
  516. username, tty, full_hostname);
  517. else
  518. syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
  519. username, tty);
  520. }
  521. /*
  522. * Destroy environment unless user has requested its preservation.
  523. * We need to do this before setusercontext() because that may
  524. * set or reset some environment variables.
  525. */
  526. if (!pflag)
  527. environ = envinit;
  528. /*
  529. * PAM modules might add supplementary groups during pam_setcred().
  530. */
  531. if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
  532. syslog(LOG_ERR, "setusercontext() failed - exiting");
  533. exit(1);
  534. }
  535. #ifdef USE_PAM
  536. if (pamh) {
  537. if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
  538. syslog(LOG_ERR, "pam_open_session: %s",
  539. pam_strerror(pamh, e));
  540. } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED))
  541. != PAM_SUCCESS) {
  542. syslog(LOG_ERR, "pam_setcred: %s",
  543. pam_strerror(pamh, e));
  544. }
  545. /*
  546. * Add any environmental variables that the
  547. * PAM modules may have set.
  548. * Call *after* opening session!
  549. */
  550. if (pamh) {
  551. environ_pam = pam_getenvlist(pamh);
  552. if (environ_pam)
  553. export_pam_environment();
  554. }
  555. /*
  556. * We must fork() before setuid() because we need to call
  557. * pam_close_session() as root.
  558. */
  559. pid = fork();
  560. if (pid < 0) {
  561. err(1, "fork");
  562. PAM_END;
  563. exit(0);
  564. } else if (pid) {
  565. /* parent - wait for child to finish, then cleanup
  566. session */
  567. wait(NULL);
  568. PAM_END;
  569. exit(0);
  570. } else {
  571. if ((e = pam_end(pamh, 0)) != PAM_SUCCESS)
  572. syslog(LOG_ERR, "pam_end: %s",
  573. pam_strerror(pamh, e));
  574. }
  575. }
  576. #endif /* USE_PAM */
  577. /*
  578. * We don't need to be root anymore, so
  579. * set the user and session context
  580. */
  581. if (setlogin(username) != 0) {
  582. syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
  583. exit(1);
  584. }
  585. if (setusercontext(lc, pwd, pwd->pw_uid,
  586. LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
  587. syslog(LOG_ERR, "setusercontext() failed - exiting");
  588. exit(1);
  589. }
  590. (void)setenv("SHELL", pwd->pw_shell, 1);
  591. (void)setenv("HOME", pwd->pw_dir, 1);
  592. if (term != NULL && *term != '\0')
  593. (void)setenv("TERM", term, 1); /* Preset overrides */
  594. else {
  595. (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */
  596. }
  597. (void)setenv("LOGNAME", username, 1);
  598. (void)setenv("USER", username, 1);
  599. (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
  600. if (!quietlog) {
  601. const char *cw;
  602. cw = login_getcapstr(lc, "copyright", NULL, NULL);
  603. if (cw != NULL && access(cw, F_OK) == 0)
  604. motd(cw);
  605. else
  606. (void)printf("%s\n\t%s %s\n",
  607. "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
  608. "The Regents of the University of California. ",
  609. "All rights reserved.");
  610. (void)printf("\n");
  611. cw = login_getcapstr(lc, "welcome", NULL, NULL);
  612. if (cw == NULL || access(cw, F_OK) != 0)
  613. cw = _PATH_MOTDFILE;
  614. motd(cw);
  615. cw = getenv("MAIL"); /* $MAIL may have been set by class */
  616. if (cw != NULL)
  617. strlcpy(tbuf, cw, sizeof(tbuf));
  618. else
  619. snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR,
  620. pwd->pw_name);
  621. if (stat(tbuf, &st) == 0 && st.st_size != 0)
  622. (void)printf("You have %smail.\n",
  623. (st.st_mtime > st.st_atime) ? "new " : "");
  624. }
  625. login_close(lc);
  626. (void)signal(SIGALRM, SIG_DFL);
  627. (void)signal(SIGQUIT, SIG_DFL);
  628. (void)signal(SIGINT, SIG_DFL);
  629. (void)signal(SIGTSTP, SIG_IGN);
  630. /*
  631. * Login shells have a leading '-' in front of argv[0]
  632. */
  633. if (snprintf(tbuf, sizeof(tbuf), "-%s",
  634. (p = strrchr(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell) >=
  635. sizeof(tbuf)) {
  636. syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
  637. username);
  638. errx(1, "shell exceeds maximum pathname size");
  639. }
  640. execlp(shell, tbuf, (char *)0);
  641. err(1, "%s", shell);
  642. }
  643. static int
  644. auth_traditional()
  645. {
  646. int rval;
  647. char *p;
  648. char *ep;
  649. char *salt;
  650. rval = 1;
  651. salt = pwd != NULL ? pwd->pw_passwd : "xx";
  652. p = getpass(passwd_prompt);
  653. ep = crypt(p, salt);
  654. if (pwd) {
  655. if (!p[0] && pwd->pw_passwd[0])
  656. ep = ":";
  657. if (strcmp(ep, pwd->pw_passwd) == 0)
  658. rval = 0;
  659. }
  660. /* clear entered password */
  661. memset(p, 0, strlen(p));
  662. return rval;
  663. }
  664. #ifdef USE_PAM
  665. /*
  666. * Attempt to authenticate the user using PAM. Returns 0 if the user is
  667. * authenticated, or 1 if not authenticated. If some sort of PAM system
  668. * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
  669. * function returns -1. This can be used as an indication that we should
  670. * fall back to a different authentication mechanism.
  671. */
  672. static int
  673. auth_pam()
  674. {
  675. const char *tmpl_user;
  676. const void *item;
  677. int rval;
  678. int e;
  679. static struct pam_conv conv = { openpam_ttyconv, NULL };
  680. if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) {
  681. syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
  682. return -1;
  683. }
  684. if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) {
  685. syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s",
  686. pam_strerror(pamh, e));
  687. return -1;
  688. }
  689. if (hostname != NULL &&
  690. (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) {
  691. syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
  692. pam_strerror(pamh, e));
  693. return -1;
  694. }
  695. e = pam_authenticate(pamh, 0);
  696. switch (e) {
  697. case PAM_SUCCESS:
  698. /*
  699. * With PAM we support the concept of a "template"
  700. * user. The user enters a login name which is
  701. * authenticated by PAM, usually via a remote service
  702. * such as RADIUS or TACACS+. If authentication
  703. * succeeds, a different but related "template" name
  704. * is used for setting the credentials, shell, and
  705. * home directory. The name the user enters need only
  706. * exist on the remote authentication server, but the
  707. * template name must be present in the local password
  708. * database.
  709. *
  710. * This is supported by two various mechanisms in the
  711. * individual modules. However, from the application's
  712. * point of view, the template user is always passed
  713. * back as a changed value of the PAM_USER item.
  714. */
  715. if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
  716. PAM_SUCCESS) {
  717. tmpl_user = (const char *) item;
  718. if (strcmp(username, tmpl_user) != 0)
  719. pwd = getpwnam(tmpl_user);
  720. } else
  721. syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
  722. pam_strerror(pamh, e));
  723. rval = 0;
  724. break;
  725. case PAM_AUTH_ERR:
  726. case PAM_USER_UNKNOWN:
  727. case PAM_MAXTRIES:
  728. rval = 1;
  729. break;
  730. default:
  731. syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e));
  732. rval = -1;
  733. break;
  734. }
  735. if (rval == 0) {
  736. e = pam_acct_mgmt(pamh, 0);
  737. if (e == PAM_NEW_AUTHTOK_REQD) {
  738. e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
  739. if (e != PAM_SUCCESS) {
  740. syslog(LOG_ERR, "pam_chauthtok: %s",
  741. pam_strerror(pamh, e));
  742. rval = 1;
  743. }
  744. } else if (e != PAM_SUCCESS) {
  745. rval = 1;
  746. }
  747. }
  748. if (rval != 0) {
  749. if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
  750. syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
  751. }
  752. pamh = NULL;
  753. }
  754. return rval;
  755. }
  756. static int
  757. export_pam_environment()
  758. {
  759. char **pp;
  760. for (pp = environ_pam; *pp != NULL; pp++) {
  761. if (ok_to_export(*pp))
  762. (void) putenv(*pp);
  763. free(*pp);
  764. }
  765. return PAM_SUCCESS;
  766. }
  767. /*
  768. * Sanity checks on PAM environmental variables:
  769. * - Make sure there is an '=' in the string.
  770. * - Make sure the string doesn't run on too long.
  771. * - Do not export certain variables. This list was taken from the
  772. * Solaris pam_putenv(3) man page.
  773. */
  774. static int
  775. ok_to_export(s)
  776. const char *s;
  777. {
  778. static const char *noexport[] = {
  779. "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
  780. "IFS", "PATH", NULL
  781. };
  782. const char **pp;
  783. size_t n;
  784. if (strlen(s) > 1024 || strchr(s, '=') == NULL)
  785. return 0;
  786. if (strncmp(s, "LD_", 3) == 0)
  787. return 0;
  788. for (pp = noexport; *pp != NULL; pp++) {
  789. n = strlen(*pp);
  790. if (s[n] == '=' && strncmp(s, *pp, n) == 0)
  791. return 0;
  792. }
  793. return 1;
  794. }
  795. #endif /* USE_PAM */
  796. static void
  797. usage()
  798. {
  799. (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
  800. exit(1);
  801. }
  802. /*
  803. * Allow for authentication style and/or kerberos instance
  804. */
  805. #define NBUFSIZ 128 // XXX was UT_NAMESIZE + 64
  806. void
  807. getloginname()
  808. {
  809. int ch;
  810. char *p;
  811. static char nbuf[NBUFSIZ];
  812. for (;;) {
  813. (void)printf("%s", prompt);
  814. for (p = nbuf; (ch = getchar()) != '\n'; ) {
  815. if (ch == EOF) {
  816. badlogin(username);
  817. exit(0);
  818. }
  819. if (p < nbuf + (NBUFSIZ - 1))
  820. *p++ = ch;
  821. }
  822. if (p > nbuf) {
  823. if (nbuf[0] == '-')
  824. (void)fprintf(stderr,
  825. "login names may not start with '-'.\n");
  826. else {
  827. *p = '\0';
  828. username = nbuf;
  829. break;
  830. }
  831. }
  832. }
  833. }
  834. int
  835. rootterm(ttyn)
  836. char *ttyn;
  837. {
  838. struct ttyent *t;
  839. return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
  840. }
  841. volatile int motdinterrupt;
  842. void
  843. sigint(signo)
  844. int signo __unused;
  845. {
  846. motdinterrupt = 1;
  847. }
  848. void
  849. motd(motdfile)
  850. const char *motdfile;
  851. {
  852. int fd, nchars;
  853. sig_t oldint;
  854. char tbuf[256];
  855. if ((fd = open(motdfile, O_RDONLY, 0)) < 0)
  856. return;
  857. motdinterrupt = 0;
  858. oldint = signal(SIGINT, sigint);
  859. while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0 && !motdinterrupt)
  860. (void)write(fileno(stdout), tbuf, nchars);
  861. (void)signal(SIGINT, oldint);
  862. (void)close(fd);
  863. }
  864. /* ARGSUSED */
  865. void
  866. timedout(signo)
  867. int signo;
  868. {
  869. longjmp(timeout_buf, signo);
  870. }
  871. void
  872. dolastlog(quiet)
  873. int quiet;
  874. {
  875. #if 0 /* XXX not implemented after utmp->utmpx change */
  876. struct lastlog ll;
  877. int fd;
  878. if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
  879. (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
  880. if (!quiet) {
  881. if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
  882. ll.ll_time != 0) {
  883. (void)printf("Last login: %.*s ",
  884. 24-5, (char *)ctime(&ll.ll_time));
  885. if (*ll.ll_host != '\0')
  886. (void)printf("from %.*s\n",
  887. (int)sizeof(ll.ll_host),
  888. ll.ll_host);
  889. else
  890. (void)printf("on %.*s\n",
  891. (int)sizeof(ll.ll_line),
  892. ll.ll_line);
  893. }
  894. (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
  895. }
  896. memset((void *)&ll, 0, sizeof(ll));
  897. (void)time(&ll.ll_time);
  898. (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
  899. if (hostname)
  900. (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
  901. (void)write(fd, (char *)&ll, sizeof(ll));
  902. (void)close(fd);
  903. } else {
  904. syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG);
  905. }
  906. #endif
  907. }
  908. void
  909. badlogin(name)
  910. char *name;
  911. {
  912. if (failures == 0)
  913. return;
  914. if (hostname) {
  915. syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
  916. failures, failures > 1 ? "S" : "", full_hostname);
  917. syslog(LOG_AUTHPRIV|LOG_NOTICE,
  918. "%d LOGIN FAILURE%s FROM %s, %s",
  919. failures, failures > 1 ? "S" : "", full_hostname, name);
  920. } else {
  921. syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
  922. failures, failures > 1 ? "S" : "", tty);
  923. syslog(LOG_AUTHPRIV|LOG_NOTICE,
  924. "%d LOGIN FAILURE%s ON %s, %s",
  925. failures, failures > 1 ? "S" : "", tty, name);
  926. }
  927. failures = 0;
  928. }
  929. #undef UNKNOWN
  930. #define UNKNOWN "su"
  931. char *
  932. stypeof(ttyid)
  933. char *ttyid;
  934. {
  935. struct ttyent *t;
  936. if (ttyid != NULL && *ttyid != '\0') {
  937. t = getttynam(ttyid);
  938. if (t != NULL && t->ty_type != NULL)
  939. return (t->ty_type);
  940. }
  941. return (UNKNOWN);
  942. }
  943. void
  944. refused(msg, rtype, lout)
  945. char *msg;
  946. char *rtype;
  947. int lout;
  948. {
  949. if (msg != NULL)
  950. printf("%s.\n", msg);
  951. if (hostname)
  952. syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
  953. pwd->pw_name, rtype, full_hostname, tty);
  954. else
  955. syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
  956. pwd->pw_name, rtype, tty);
  957. if (lout)
  958. sleepexit(1);
  959. }
  960. void
  961. sleepexit(eval)
  962. int eval;
  963. {
  964. (void)sleep(5);
  965. exit(eval);
  966. }