aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/login
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/login')
-rw-r--r--usr.bin/login/Makefile34
-rw-r--r--usr.bin/login/Makefile.depend17
-rw-r--r--usr.bin/login/Makefile.depend.options5
-rw-r--r--usr.bin/login/README10
-rw-r--r--usr.bin/login/fbtab3
-rw-r--r--usr.bin/login/login.1161
-rw-r--r--usr.bin/login/login.access45
-rw-r--r--usr.bin/login/login.c1034
-rw-r--r--usr.bin/login/login.conf326
-rw-r--r--usr.bin/login/login.h37
-rw-r--r--usr.bin/login/login_audit.c203
-rw-r--r--usr.bin/login/login_fbtab.c139
-rw-r--r--usr.bin/login/motd.template20
-rw-r--r--usr.bin/login/pathnames.h37
14 files changed, 2071 insertions, 0 deletions
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile
new file mode 100644
index 000000000000..b88796e97691
--- /dev/null
+++ b/usr.bin/login/Makefile
@@ -0,0 +1,34 @@
+.include <src.opts.mk>
+.include <src.tools.mk>
+
+PACKAGE= runtime
+
+CONFS= fbtab login.conf motd.template login.access
+PROG= login
+SRCS= login.c login_fbtab.c
+CFLAGS+=-DLOGALL
+LIBADD= util pam
+
+WARNS?= 5
+
+.if ${MK_AUDIT} != "no"
+SRCS+= login_audit.c
+CFLAGS+= -DUSE_BSM_AUDIT
+LIBADD+= bsm
+.endif
+
+.if ${MK_SETUID_LOGIN} != "no"
+BINOWN= root
+BINMODE=4555
+PRECIOUSPROG=
+.endif
+
+.include <bsd.endian.mk>
+afterinstallconfig:
+ ${CAP_MKDB_CMD} ${CAP_MKDB_ENDIAN} ${DESTDIR}/etc/login.conf
+.if defined(NO_ROOT) && defined(METALOG)
+ echo ".${DISTBASE}/etc/login.conf.db type=file mode=0644 uname=root gname=wheel" | \
+ cat -l >> ${METALOG}
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/login/Makefile.depend b/usr.bin/login/Makefile.depend
new file mode 100644
index 000000000000..dcba122adac8
--- /dev/null
+++ b/usr.bin/login/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libpam/libpam \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.bin/login/Makefile.depend.options b/usr.bin/login/Makefile.depend.options
new file mode 100644
index 000000000000..87c69612fea8
--- /dev/null
+++ b/usr.bin/login/Makefile.depend.options
@@ -0,0 +1,5 @@
+# This file is not autogenerated - take care!
+
+DIRDEPS_OPTIONS= AUDIT
+
+.include <dirdeps-options.mk>
diff --git a/usr.bin/login/README b/usr.bin/login/README
new file mode 100644
index 000000000000..ede4366f91f7
--- /dev/null
+++ b/usr.bin/login/README
@@ -0,0 +1,10 @@
+This login has additional functionalities. They are all based on (part of)
+Wietse Venema's logdaemon package.
+
+
+The following defines can be used:
+
+- LOGALL to log all logins
+
+
+-Guido
diff --git a/usr.bin/login/fbtab b/usr.bin/login/fbtab
new file mode 100644
index 000000000000..ba2544eca9eb
--- /dev/null
+++ b/usr.bin/login/fbtab
@@ -0,0 +1,3 @@
+#
+#/dev/ttyv0 0600 /dev/console
+#/dev/ttyv0 0600 /dev/pcaudio:/dev/pcaudioctl
diff --git a/usr.bin/login/login.1 b/usr.bin/login/login.1
new file mode 100644
index 000000000000..5dbe307e5dd3
--- /dev/null
+++ b/usr.bin/login/login.1
@@ -0,0 +1,161 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd December 14, 2025
+.Dt LOGIN 1
+.Os
+.Sh NAME
+.Nm login
+.Nd log into the computer
+.Sh SYNOPSIS
+.Nm
+.Op Fl fp
+.Op Fl h Ar hostname
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility logs users (and pseudo-users) into the computer system.
+.Pp
+If no user is specified, or if a user is specified and authentication
+of the user fails,
+.Nm
+prompts for a user name.
+Authentication of users is configurable via
+.Xr pam 8 .
+Password authentication is the default.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl f
+When a user name is specified, this option indicates that proper
+authentication has already been done and that no password need be
+requested.
+This option may only be used by the super-user or when an already
+logged in user is logging in as themselves.
+.It Fl h
+Specify the host from which the connection was received.
+It is used by various daemons such as
+.Nm telnetd .
+This option may only be used by the super-user.
+.It Fl p
+By default,
+.Nm
+discards any previous environment.
+The
+.Fl p
+option disables this behavior.
+.El
+.Pp
+Login access can be controlled via
+.Xr login.access 5
+or the login class in
+.Xr login.conf 5 ,
+which provides
+allow and deny records based on time, tty and remote host name.
+.Pp
+If the file
+.Pa /etc/fbtab
+exists,
+.Nm
+changes the protection and ownership of certain devices specified in this
+file.
+.Pp
+Immediately after logging a user in,
+.Nm
+displays the date and time the user last
+logged in, the message of the day as well as other information.
+If the file
+.Pa .hushlogin
+exists in the user's home directory, all of these messages are suppressed.
+This is to simplify logins for non-human users, such as
+.Xr uucp 1 .
+.Pp
+The
+.Nm
+utility enters information into the environment (see
+.Xr environ 7 )
+specifying the user's home directory (HOME), command interpreter (SHELL),
+search path (PATH), terminal type (TERM) and user name (both LOGNAME and
+USER).
+Other environment variables may be set due to entries in the login
+class capabilities database, for the login class assigned in the
+user's system passwd record.
+The login class also controls the maximum and current process resource
+limits granted to a login, process priorities and many other aspects of
+a user's login environment.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Pp
+The
+.Nm
+utility will submit an audit record when login succeeds or fails.
+Failure to determine the current auditing state will
+result in an error exit from
+.Nm .
+.Sh FILES
+.Bl -tag -width ".Pa /etc/security/audit_control" -compact
+.It Pa /etc/fbtab
+changes device protections
+.It Pa /etc/login.conf
+login class capabilities database
+.It Pa /var/run/motd
+message-of-the-day
+.It Pa /var/mail/user
+system mailboxes
+.It Pa \&.hushlogin
+makes login quieter
+.It Pa /etc/pam.d/login
+.Xr pam 8
+configuration file
+.It Pa /etc/security/audit_user
+user flags for auditing
+.It Pa /etc/security/audit_control
+global flags for auditing
+.El
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr chpass 1 ,
+.Xr csh 1 ,
+.Xr newgrp 1 ,
+.Xr passwd 1 ,
+.Xr rlogin 1 ,
+.Xr getpass 3 ,
+.Xr fbtab 5 ,
+.Xr login.access 5 ,
+.Xr login.conf 5 ,
+.Xr environ 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/usr.bin/login/login.access b/usr.bin/login/login.access
new file mode 100644
index 000000000000..05609df8355e
--- /dev/null
+++ b/usr.bin/login/login.access
@@ -0,0 +1,45 @@
+#
+# Login access control table.
+#
+# When someone logs in, the table is scanned for the first entry that
+# matches the (user, host) combination, or, in case of non-networked
+# logins, the first entry that matches the (user, tty) combination. The
+# permissions field of that table entry determines whether the login will
+# be accepted or refused.
+#
+# Format of the login access control table is three fields separated by a
+# ":" character:
+#
+# permission : users : origins
+#
+# The first field should be a "+" (access granted) or "-" (access denied)
+# character. The second field should be a list of one or more login names,
+# group names, or ALL (always matches). The third field should be a list
+# of one or more tty names (for non-networked logins), host names, domain
+# names (begin with "."), host addresses, internet network numbers (end
+# with "."), ALL (always matches) or LOCAL (matches any string that does
+# not contain a "." character). If you run NIS you can use @netgroupname
+# in host or user patterns.
+#
+# The EXCEPT operator makes it possible to write very compact rules.
+#
+# The group file is searched only when a name does not match that of the
+# logged-in user. Only groups are matched in which users are explicitly
+# listed: the program does not look at a user's primary group id value.
+#
+##############################################################################
+#
+# Disallow console logins to all but a few accounts.
+#
+#-:ALL EXCEPT wheel shutdown sync:console
+#
+# Disallow non-local logins to privileged accounts (group wheel).
+#
+#-:wheel:ALL EXCEPT LOCAL .win.tue.nl
+#
+# Some accounts are not allowed to login from anywhere:
+#
+#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL
+#
+# All other accounts are allowed to login from anywhere.
+#
diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c
new file mode 100644
index 000000000000..6a0c6a5b6bbc
--- /dev/null
+++ b/usr.bin/login/login.c
@@ -0,0 +1,1034 @@
+/*-
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+/*
+ * login [ name ]
+ * login -h hostname (for telnetd, etc.)
+ * login -f name (for pre-authenticated login: datakit, xterm, etc.)
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <login_cap.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ttyent.h>
+#include <unistd.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+
+#include "login.h"
+#include "pathnames.h"
+
+static int auth_pam(void);
+static void bail(int, int);
+static void bail_internal(int, int, int);
+static int export(const char *);
+static void export_pam_environment(void);
+static int motd(const char *);
+static void badlogin(char *);
+static char *getloginname(void);
+static void pam_syslog(const char *);
+static void pam_cleanup(void);
+static void refused(const char *, const char *, int);
+static const char *stypeof(char *);
+static void sigint(int);
+static void timedout(int);
+static void bail_sig(int);
+static void usage(void);
+
+#define TTYGRPNAME "tty" /* group to own ttys */
+#define DEFAULT_BACKOFF 3
+#define DEFAULT_RETRIES 10
+#define DEFAULT_PROMPT "login: "
+#define DEFAULT_PASSWD_PROMPT "Password:"
+#define TERM_UNKNOWN "su"
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+#define NO_SLEEP_EXIT 0
+#define SLEEP_EXIT 5
+
+/*
+ * This bounds the time given to login. Not a define so it can
+ * be patched on machines where it's too small.
+ */
+static u_int timeout = 300;
+
+/* Buffer for signal handling of timeout */
+static jmp_buf timeout_buf;
+
+char pwbuf[1024];
+struct passwd pwres;
+struct passwd *pwd;
+static int failures;
+
+static char *envinit[1]; /* empty environment list */
+
+/*
+ * Command line flags and arguments
+ */
+static int fflag; /* -f: do not perform authentication */
+static int hflag; /* -h: login from remote host */
+static char *hostname; /* hostname from command line */
+static int pflag; /* -p: preserve environment */
+
+/*
+ * User name
+ */
+static char *username; /* user name */
+static char *olduser; /* previous user name */
+
+/*
+ * Prompts
+ */
+static char default_prompt[] = DEFAULT_PROMPT;
+static const char *prompt;
+static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
+static const char *passwd_prompt;
+
+static char *tty;
+
+/*
+ * PAM data
+ */
+static pam_handle_t *pamh = NULL;
+static struct pam_conv pamc = { openpam_ttyconv, NULL };
+static int pam_err;
+static int pam_silent = PAM_SILENT;
+static int pam_cred_established;
+static int pam_session_established;
+
+int
+main(int argc, char *argv[])
+{
+ struct group *gr;
+ struct stat st;
+ int retries, backoff;
+ int ask, ch, cnt, quietlog, rootlogin, rval;
+ uid_t uid, euid;
+ gid_t egid;
+ char *term;
+ char *p, *ttyn;
+ char tname[sizeof(_PATH_TTY) + 10];
+ char *arg0;
+ const char *tp;
+ const char *shell = NULL;
+ login_cap_t *lc = NULL;
+ login_cap_t *lc_user = NULL;
+ pid_t pid;
+ sigset_t mask, omask;
+ struct sigaction sa;
+#ifdef USE_BSM_AUDIT
+ char auditsuccess = 1;
+#endif
+
+ sa.sa_flags = SA_RESTART;
+ (void)sigfillset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ (void)sigaction(SIGQUIT, &sa, NULL);
+ (void)sigaction(SIGINT, &sa, NULL);
+ (void)sigaction(SIGHUP, &sa, NULL);
+ if (setjmp(timeout_buf)) {
+ if (failures)
+ badlogin(username);
+ (void)fprintf(stderr, "Login timed out after %d seconds\n",
+ timeout);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+ sa.sa_handler = timedout;
+ (void)sigaction(SIGALRM, &sa, NULL);
+ (void)alarm(timeout);
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+
+ openlog("login", LOG_CONS, LOG_AUTH);
+
+ uid = getuid();
+ euid = geteuid();
+ egid = getegid();
+
+ while ((ch = getopt(argc, argv, "fh:p")) != -1)
+ switch (ch) {
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ if (uid != 0)
+ errx(1, "-h option: %s", strerror(EPERM));
+ if (strlen(optarg) >= MAXHOSTNAMELEN)
+ errx(1, "-h option: %s: exceeds maximum "
+ "hostname size", optarg);
+ hflag = 1;
+ hostname = optarg;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case '?':
+ default:
+ if (uid == 0)
+ syslog(LOG_ERR, "invalid flag %c", ch);
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ username = strdup(*argv);
+ if (username == NULL)
+ err(1, "strdup()");
+ ask = 0;
+ } else {
+ ask = 1;
+ }
+
+ setproctitle("-%s", getprogname());
+
+ closefrom(3);
+
+ /*
+ * Get current TTY
+ */
+ ttyn = ttyname(STDIN_FILENO);
+ if (ttyn == NULL || *ttyn == '\0') {
+ (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
+ ttyn = tname;
+ }
+ if (strncmp(ttyn, _PATH_DEV, sizeof _PATH_DEV - 1) == 0)
+ tty = ttyn + sizeof _PATH_DEV - 1;
+ else
+ tty = ttyn;
+
+ /*
+ * Get "login-retries" & "login-backoff" from default class
+ */
+ lc = login_getclass(NULL);
+ prompt = login_getcapstr(lc, "login_prompt",
+ default_prompt, default_prompt);
+ passwd_prompt = login_getcapstr(lc, "passwd_prompt",
+ default_passwd_prompt, default_passwd_prompt);
+ retries = login_getcapnum(lc, "login-retries",
+ DEFAULT_RETRIES, DEFAULT_RETRIES);
+ backoff = login_getcapnum(lc, "login-backoff",
+ DEFAULT_BACKOFF, DEFAULT_BACKOFF);
+ login_close(lc);
+ lc = NULL;
+
+ /*
+ * Try to authenticate the user until we succeed or time out.
+ */
+ for (cnt = 0;; ask = 1) {
+ if (ask) {
+ fflag = 0;
+ if (olduser != NULL)
+ free(olduser);
+ olduser = username;
+ username = getloginname();
+ }
+ rootlogin = 0;
+
+ /*
+ * Note if trying multiple user names; log failures for
+ * previous user name, but don't bother logging one failure
+ * for nonexistent name (mistyped username).
+ */
+ if (failures && strcmp(olduser, username) != 0) {
+ if (failures > (pwd ? 0 : 1))
+ badlogin(olduser);
+ }
+
+ /*
+ * Load the PAM policy and set some variables
+ */
+ pam_err = pam_start("login", username, &pamc, &pamh);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_start()");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_err = pam_set_item(pamh, PAM_TTY, tty);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_set_item(PAM_TTY)");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_set_item(PAM_RHOST)");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+
+ (void)getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd);
+ if (pwd != NULL && pwd->pw_uid == 0)
+ rootlogin = 1;
+
+ /*
+ * If the -f option was specified and the caller is
+ * root or the caller isn't changing their uid, don't
+ * authenticate.
+ */
+ if (pwd != NULL && fflag &&
+ (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
+ /* already authenticated */
+ rval = 0;
+#ifdef USE_BSM_AUDIT
+ auditsuccess = 0; /* opened a terminal window only */
+#endif
+ } else {
+ fflag = 0;
+ (void)setpriority(PRIO_PROCESS, 0, -4);
+ rval = auth_pam();
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+ }
+
+ if (pwd != NULL && rval == 0)
+ break;
+
+ pam_cleanup();
+
+ /*
+ * We are not exiting here, but this corresponds to a failed
+ * login event, so set exitstatus to 1.
+ */
+#ifdef USE_BSM_AUDIT
+ au_login_fail("Login incorrect", 1);
+#endif
+
+ (void)printf("Login incorrect\n");
+ failures++;
+
+ pwd = NULL;
+
+ /*
+ * Allow up to 'retry' (10) attempts, but start
+ * backing off after 'backoff' (3) attempts.
+ */
+ if (++cnt > backoff) {
+ if (cnt >= retries) {
+ badlogin(username);
+ bail(SLEEP_EXIT, 1);
+ }
+ sleep((u_int)((cnt - backoff) * 5));
+ }
+ }
+
+ /* committed to login -- turn off timeout */
+ (void)alarm((u_int)0);
+
+ (void)sigemptyset(&mask);
+ (void)sigaddset(&mask, SIGHUP);
+ (void)sigaddset(&mask, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &mask, &omask);
+ sa.sa_handler = bail_sig;
+ (void)sigaction(SIGHUP, &sa, NULL);
+ (void)sigaction(SIGTERM, &sa, NULL);
+
+ endpwent();
+
+#ifdef USE_BSM_AUDIT
+ /* Audit successful login. */
+ if (auditsuccess)
+ au_login_success();
+#endif
+
+ /*
+ * This needs to happen before login_getpwclass to support
+ * home directories on GSS-API authenticated NFS where the
+ * kerberos credentials need to be saved so that the kernel
+ * can authenticate to the NFS server.
+ */
+ pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_setcred()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_cred_established = 1;
+
+ /*
+ * Establish the login class.
+ */
+ lc = login_getpwclass(pwd);
+ lc_user = login_getuserclass(pwd);
+
+ if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
+ quietlog = login_getcapbool(lc, "hushlogin", 0);
+
+ /*
+ * Switching needed for NFS with root access disabled.
+ *
+ * XXX: This change fails to modify the additional groups for the
+ * process, and as such, may restrict rights normally granted
+ * through those groups.
+ */
+ (void)setegid(pwd->pw_gid);
+ (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
+ if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
+ if (login_getcapbool(lc, "requirehome", 0))
+ refused("Home directory not available", "HOMEDIR", 1);
+ if (chdir("/") < 0)
+ refused("Cannot find root directory", "ROOTDIR", 1);
+ if (!quietlog || *pwd->pw_dir)
+ printf("No home directory.\nLogging in with home = \"/\".\n");
+ pwd->pw_dir = strdup("/");
+ if (pwd->pw_dir == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+ }
+ (void)seteuid(euid);
+ (void)setegid(egid);
+ if (!quietlog) {
+ quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
+ if (!quietlog)
+ pam_silent = 0;
+ }
+
+ shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = strdup(_PATH_BSHELL);
+ if (pwd->pw_shell == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+ if (*shell == '\0') /* Not overridden */
+ shell = pwd->pw_shell;
+ if ((shell = strdup(shell)) == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+
+ /*
+ * Set device protections, depending on what terminal the
+ * user is logged in. This feature is used on Suns to give
+ * console users better privacy.
+ */
+ login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
+
+ /*
+ * Clear flags of the tty. None should be set, and when the
+ * user sets them otherwise, this can cause the chown to fail.
+ * Since it isn't clear that flags are useful on character
+ * devices, we just clear them.
+ *
+ * We don't log in the case of EOPNOTSUPP because dev might be
+ * on NFS, which doesn't support chflags.
+ *
+ * We don't log in the EROFS because that means that /dev is on
+ * a read only file system and we assume that the permissions there
+ * are sane.
+ */
+ if (ttyn != tname && chflags(ttyn, 0))
+ if (errno != EOPNOTSUPP && errno != EROFS)
+ syslog(LOG_ERR, "chflags(%s): %m", ttyn);
+ if (ttyn != tname && chown(ttyn, pwd->pw_uid,
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
+ if (errno != EROFS)
+ syslog(LOG_ERR, "chown(%s): %m", ttyn);
+
+#ifdef LOGALL
+ /*
+ * Syslog each successful login, so we don't have to watch
+ * hundreds of wtmp or lastlogin files.
+ */
+ if (hflag)
+ syslog(LOG_INFO, "login from %s on %s as %s",
+ hostname, tty, pwd->pw_name);
+ else
+ syslog(LOG_INFO, "login on %s as %s",
+ tty, pwd->pw_name);
+#endif
+
+ /*
+ * If fflag is on, assume caller/authenticator has logged root
+ * login.
+ */
+ if (rootlogin && fflag == 0) {
+ if (hflag)
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
+ username, tty, hostname);
+ else
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
+ username, tty);
+ }
+
+ /*
+ * Destroy environment unless user has requested its
+ * preservation - but preserve TERM in all cases
+ */
+ term = getenv("TERM");
+ if (!pflag)
+ environ = envinit;
+ if (term != NULL)
+ setenv("TERM", term, 0);
+
+ /*
+ * PAM modules might add supplementary groups during pam_setcred().
+ */
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+
+ pam_err = pam_setcred(pamh, pam_silent|PAM_REINITIALIZE_CRED);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_setcred()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+
+ pam_err = pam_open_session(pamh, pam_silent);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_open_session()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_session_established = 1;
+
+ /*
+ * We must fork() before setuid() because we need to call
+ * pam_close_session() as root.
+ */
+ pid = fork();
+ if (pid < 0) {
+ err(1, "fork");
+ } else if (pid != 0) {
+ /*
+ * Parent: wait for child to finish, then clean up
+ * session.
+ *
+ * If we get SIGHUP or SIGTERM, clean up the session
+ * and exit right away. This will make the terminal
+ * inaccessible and send SIGHUP to the foreground
+ * process group.
+ */
+ int status;
+ setproctitle("-%s [pam]", getprogname());
+ (void)sigprocmask(SIG_SETMASK, &omask, NULL);
+ waitpid(pid, &status, 0);
+ (void)sigprocmask(SIG_BLOCK, &mask, NULL);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+
+ /*
+ * NOTICE: We are now in the child process!
+ */
+
+ /*
+ * Add any environment variables the PAM modules may have set.
+ */
+ export_pam_environment();
+
+ /*
+ * We're done with PAM now; our parent will deal with the rest.
+ */
+ pam_end(pamh, 0);
+ pamh = NULL;
+
+ /*
+ * We don't need to be root anymore, so set the login name and
+ * the UID.
+ */
+ if (setlogin(username) != 0) {
+ syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ if (setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ exit(1);
+ }
+
+ (void)setenv("SHELL", pwd->pw_shell, 1);
+ (void)setenv("HOME", pwd->pw_dir, 1);
+ /* Overwrite "term" from login.conf(5) for any known TERM */
+ if (term == NULL && (tp = stypeof(tty)) != NULL)
+ (void)setenv("TERM", tp, 1);
+ else
+ (void)setenv("TERM", TERM_UNKNOWN, 0);
+ (void)setenv("LOGNAME", username, 1);
+ (void)setenv("USER", username, 1);
+ (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
+
+ if (!quietlog) {
+ const char *cw;
+
+ cw = login_getcapstr(lc, "welcome", NULL, NULL);
+ if (cw != NULL && access(cw, F_OK) == 0)
+ motd(cw);
+ else
+ motd(_PATH_MOTDFILE);
+
+ if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
+ login_getcapbool(lc, "nocheckmail", 0) == 0) {
+ char *cx;
+
+ /* $MAIL may have been set by class. */
+ cx = getenv("MAIL");
+ if (cx == NULL) {
+ asprintf(&cx, "%s/%s",
+ _PATH_MAILDIR, pwd->pw_name);
+ }
+ if (cx && stat(cx, &st) == 0 && st.st_size != 0)
+ (void)printf("You have %smail.\n",
+ (st.st_mtime > st.st_atime) ? "new " : "");
+ if (getenv("MAIL") == NULL)
+ free(cx);
+ }
+ }
+
+ login_close(lc_user);
+ login_close(lc);
+
+ sa.sa_handler = SIG_DFL;
+ (void)sigaction(SIGALRM, &sa, NULL);
+ (void)sigaction(SIGQUIT, &sa, NULL);
+ (void)sigaction(SIGINT, &sa, NULL);
+ (void)sigaction(SIGTERM, &sa, NULL);
+ (void)sigaction(SIGHUP, &sa, NULL);
+ sa.sa_handler = SIG_IGN;
+ (void)sigaction(SIGTSTP, &sa, NULL);
+ (void)sigprocmask(SIG_SETMASK, &omask, NULL);
+
+ /*
+ * Login shells have a leading '-' in front of argv[0]
+ */
+ p = strrchr(pwd->pw_shell, '/');
+ if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
+ syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
+ username);
+ errx(1, "shell exceeds maximum pathname size");
+ } else if (arg0 == NULL) {
+ err(1, "asprintf()");
+ }
+
+ execlp(shell, arg0, (char *)0);
+ err(1, "%s", shell);
+
+ /*
+ * That's it, folks!
+ */
+}
+
+/*
+ * Attempt to authenticate the user using PAM. Returns 0 if the user is
+ * authenticated, or 1 if not authenticated. If some sort of PAM system
+ * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
+ * function returns -1. This can be used as an indication that we should
+ * fall back to a different authentication mechanism.
+ */
+static int
+auth_pam(void)
+{
+ const char *tmpl_user;
+ const void *item;
+ int rval;
+
+ pam_err = pam_authenticate(pamh, pam_silent);
+ switch (pam_err) {
+
+ case PAM_SUCCESS:
+ /*
+ * With PAM we support the concept of a "template"
+ * user. The user enters a login name which is
+ * authenticated by PAM, usually via a remote service
+ * such as RADIUS or TACACS+. If authentication
+ * succeeds, a different but related "template" name
+ * is used for setting the credentials, shell, and
+ * home directory. The name the user enters need only
+ * exist on the remote authentication server, but the
+ * template name must be present in the local password
+ * database.
+ *
+ * This is supported by two various mechanisms in the
+ * individual modules. However, from the application's
+ * point of view, the template user is always passed
+ * back as a changed value of the PAM_USER item.
+ */
+ pam_err = pam_get_item(pamh, PAM_USER, &item);
+ if (pam_err == PAM_SUCCESS) {
+ tmpl_user = (const char *)item;
+ if (strcmp(username, tmpl_user) != 0) {
+ (void)getpwnam_r(tmpl_user, &pwres, pwbuf,
+ sizeof(pwbuf), &pwd);
+ }
+ } else {
+ pam_syslog("pam_get_item(PAM_USER)");
+ }
+ rval = 0;
+ break;
+
+ case PAM_AUTH_ERR:
+ case PAM_USER_UNKNOWN:
+ case PAM_MAXTRIES:
+ rval = 1;
+ break;
+
+ default:
+ pam_syslog("pam_authenticate()");
+ rval = -1;
+ break;
+ }
+
+ if (rval == 0) {
+ pam_err = pam_acct_mgmt(pamh, pam_silent);
+ switch (pam_err) {
+ case PAM_SUCCESS:
+ break;
+ case PAM_NEW_AUTHTOK_REQD:
+ pam_err = pam_chauthtok(pamh,
+ pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_chauthtok()");
+ rval = 1;
+ }
+ break;
+ default:
+ pam_syslog("pam_acct_mgmt()");
+ rval = 1;
+ break;
+ }
+ }
+
+ if (rval != 0) {
+ pam_end(pamh, pam_err);
+ pamh = NULL;
+ }
+ return (rval);
+}
+
+/*
+ * Export any environment variables PAM modules may have set
+ */
+static void
+export_pam_environment(void)
+{
+ char **pam_env;
+ char **pp;
+
+ pam_env = pam_getenvlist(pamh);
+ if (pam_env != NULL) {
+ for (pp = pam_env; *pp != NULL; pp++) {
+ (void)export(*pp);
+ free(*pp);
+ }
+ }
+}
+
+/*
+ * Perform sanity checks on an environment variable:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ * Then export it.
+ */
+static int
+export(const char *s)
+{
+ static const char *noexport[] = {
+ "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ char *p;
+ const char **pp;
+ size_t n;
+ int rv;
+
+ if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
+ return (0);
+ if (strncmp(s, "LD_", 3) == 0)
+ return (0);
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return (0);
+ }
+ *p = '\0';
+ rv = setenv(s, p + 1, 1);
+ *p = '=';
+ if (rv == -1)
+ return (0);
+ return (1);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
+ exit(1);
+}
+
+/*
+ * Prompt user and read login name from stdin.
+ */
+static char *
+getloginname(void)
+{
+ char *nbuf, *p;
+ int ch;
+
+ nbuf = malloc(MAXLOGNAME);
+ if (nbuf == NULL)
+ err(1, "malloc()");
+ do {
+ (void)printf("%s", prompt);
+ for (p = nbuf; (ch = getchar()) != '\n'; ) {
+ if (ch == EOF) {
+ badlogin(username);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+ if (p < nbuf + MAXLOGNAME - 1)
+ *p++ = ch;
+ }
+ } while (p == nbuf);
+
+ *p = '\0';
+ if (nbuf[0] == '-') {
+ pam_silent = 0;
+ memmove(nbuf, nbuf + 1, strlen(nbuf));
+ } else {
+ pam_silent = PAM_SILENT;
+ }
+ return nbuf;
+}
+
+/*
+ * SIGINT handler for motd().
+ */
+static volatile int motdinterrupt;
+static void
+sigint(int signo __unused)
+{
+ motdinterrupt = 1;
+}
+
+/*
+ * Display the contents of a file (such as /etc/motd).
+ */
+static int
+motd(const char *motdfile)
+{
+ struct sigaction newint, oldint;
+ FILE *f;
+ int ch;
+
+ if ((f = fopen(motdfile, "r")) == NULL)
+ return (-1);
+ motdinterrupt = 0;
+ newint.sa_handler = sigint;
+ newint.sa_flags = 0;
+ sigfillset(&newint.sa_mask);
+ sigaction(SIGINT, &newint, &oldint);
+ while ((ch = fgetc(f)) != EOF && !motdinterrupt)
+ putchar(ch);
+ sigaction(SIGINT, &oldint, NULL);
+ if (ch != EOF || ferror(f)) {
+ fclose(f);
+ return (-1);
+ }
+ fclose(f);
+ return (0);
+}
+
+/*
+ * SIGALRM handler, to enforce login prompt timeout.
+ *
+ * XXX This can potentially confuse the hell out of PAM. We should
+ * XXX instead implement a conversation function that returns
+ * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
+ * XXX handler just set a flag.
+ */
+static void
+timedout(int signo __unused)
+{
+
+ longjmp(timeout_buf, signo);
+}
+
+static void
+badlogin(char *name)
+{
+
+ if (failures == 0)
+ return;
+ if (hflag) {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
+ failures, failures > 1 ? "S" : "", hostname);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s FROM %s, %s",
+ failures, failures > 1 ? "S" : "", hostname, name);
+ } else {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
+ failures, failures > 1 ? "S" : "", tty);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s ON %s, %s",
+ failures, failures > 1 ? "S" : "", tty, name);
+ }
+ failures = 0;
+}
+
+const char *
+stypeof(char *ttyid)
+{
+ struct ttyent *t;
+
+ if (ttyid != NULL && *ttyid != '\0') {
+ t = getttynam(ttyid);
+ if (t != NULL && t->ty_type != NULL)
+ return (t->ty_type);
+ }
+ return (NULL);
+}
+
+static void
+refused(const char *msg, const char *rtype, int lout)
+{
+
+ if (msg != NULL)
+ printf("%s.\n", msg);
+ if (hflag)
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
+ pwd->pw_name, rtype, hostname, tty);
+ else
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
+ pwd->pw_name, rtype, tty);
+ if (lout)
+ bail(SLEEP_EXIT, 1);
+}
+
+/*
+ * Log a PAM error
+ */
+static void
+pam_syslog(const char *msg)
+{
+ syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
+}
+
+/*
+ * Shut down PAM
+ */
+static void
+pam_cleanup(void)
+{
+
+ if (pamh != NULL) {
+ if (pam_session_established) {
+ pam_err = pam_close_session(pamh, 0);
+ if (pam_err != PAM_SUCCESS)
+ pam_syslog("pam_close_session()");
+ }
+ pam_session_established = 0;
+ if (pam_cred_established) {
+ pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
+ if (pam_err != PAM_SUCCESS)
+ pam_syslog("pam_setcred()");
+ }
+ pam_cred_established = 0;
+ pam_end(pamh, pam_err);
+ pamh = NULL;
+ }
+}
+
+static void
+bail_internal(int sec, int eval, int signo)
+{
+ struct sigaction sa;
+
+ pam_cleanup();
+#ifdef USE_BSM_AUDIT
+ if (pwd != NULL)
+ audit_logout();
+#endif
+ (void)sleep(sec);
+ if (signo == 0)
+ exit(eval);
+ else {
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = 0;
+ (void)sigemptyset(&sa.sa_mask);
+ (void)sigaction(signo, &sa, NULL);
+ (void)sigaddset(&sa.sa_mask, signo);
+ (void)sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
+ raise(signo);
+ exit(128 + signo);
+ }
+}
+
+/*
+ * Exit, optionally after sleeping a few seconds
+ */
+static void
+bail(int sec, int eval)
+{
+ bail_internal(sec, eval, 0);
+}
+
+/*
+ * Exit because of a signal.
+ * This is not async-signal safe, so only call async-signal safe functions
+ * while the signal is unmasked.
+ */
+static void
+bail_sig(int signo)
+{
+ bail_internal(NO_SLEEP_EXIT, 0, signo);
+}
diff --git a/usr.bin/login/login.conf b/usr.bin/login/login.conf
new file mode 100644
index 000000000000..267b0f1ad826
--- /dev/null
+++ b/usr.bin/login/login.conf
@@ -0,0 +1,326 @@
+# login.conf - login class capabilities database.
+#
+# Remember to rebuild the database after each change to this file:
+#
+# cap_mkdb /etc/login.conf
+#
+# This file controls resource limits, accounting limits and
+# default user environment settings.
+#
+#
+
+# Default settings effectively disable resource limits, see the
+# examples below for a starting point to enable them.
+
+# defaults
+# These settings are used by login(1) by default for classless users
+# Note that entries like "cputime" set both "cputime-cur" and "cputime-max"
+#
+# Note that since a colon ':' is used to separate capability entries,
+# a \c escape sequence must be used to embed a literal colon in the
+# value or name of a capability (see the ``CGETNUM AND CGETSTR SYNTAX
+# AND SEMANTICS'' section of getcap(3) for more escape sequences).
+
+default:\
+ :passwd_format=sha512:\
+ :welcome=/var/run/motd:\
+ :setenv=BLOCKSIZE=K:\
+ :mail=/var/mail/$:\
+ :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\
+ :nologin=/var/run/nologin:\
+ :cputime=unlimited:\
+ :datasize=unlimited:\
+ :stacksize=unlimited:\
+ :memorylocked=64K:\
+ :memoryuse=unlimited:\
+ :filesize=unlimited:\
+ :coredumpsize=unlimited:\
+ :openfiles=unlimited:\
+ :maxproc=unlimited:\
+ :sbsize=unlimited:\
+ :vmemoryuse=unlimited:\
+ :swapuse=unlimited:\
+ :pseudoterminals=unlimited:\
+ :kqueues=unlimited:\
+ :umtxp=unlimited:\
+ :pipebuf=unlimited:\
+ :priority=0:\
+ :umask=022:\
+ :charset=UTF-8:\
+ :lang=C.UTF-8:
+
+#
+# A collection of common class names - forward them all to 'default'
+# (login would normally do this anyway, but having a class name
+# here suppresses the diagnostic)
+#
+standard:\
+ :tc=default:
+xuser:\
+ :tc=default:
+staff:\
+ :tc=default:
+
+# This PATH may be clobbered by individual applications. Notably, by default,
+# rc(8), service(8), and cron(8) will all override it with a default PATH that
+# may not include /usr/local/sbin and /usr/local/bin when starting services or
+# jobs.
+daemon:\
+ :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin:\
+ :mail@:\
+ :memorylocked=128M:\
+ :tc=default:
+news:\
+ :tc=default:
+dialer:\
+ :tc=default:
+
+#
+# Root can always login
+#
+# N.B. login_getpwclass(3) will use this entry for the root account,
+# in preference to 'default'.
+root:\
+ :ignorenologin:\
+ :memorylocked=unlimited:\
+ :tc=default:
+
+#
+# Russian Users Accounts. Setup proper environment variables.
+#
+russian|Russian Users Accounts:\
+ :charset=UTF-8:\
+ :lang=ru_RU.UTF-8:\
+ :tc=default:
+
+
+######################################################################
+######################################################################
+##
+## Example entries
+##
+######################################################################
+######################################################################
+
+## Example defaults
+## These settings are used by login(1) by default for classless users
+## Note that entries like "cputime" set both "cputime-cur" and "cputime-max"
+#
+#default:\
+# :cputime=infinity:\
+# :datasize-cur=22M:\
+# :stacksize-cur=8M:\
+# :memorylocked-cur=10M:\
+# :memoryuse-cur=30M:\
+# :filesize=infinity:\
+# :coredumpsize=infinity:\
+# :maxproc-cur=64:\
+# :openfiles-cur=64:\
+# :priority=0:\
+# :requirehome@:\
+# :umask=022:\
+# :tc=auth-defaults:
+#
+#
+##
+## standard - standard user defaults
+##
+#standard:\
+# :welcome=/var/run/motd:\
+# :setenv=BLOCKSIZE=K:\
+# :mail=/var/mail/$:\
+# :path=~/bin /bin /usr/bin /usr/local/bin:\
+# :manpath=/usr/share/man /usr/local/man:\
+# :nologin=/var/run/nologin:\
+# :cputime=1h30m:\
+# :datasize=8M:\
+# :vmemoryuse=100M:\
+# :stacksize=2M:\
+# :memorylocked=4M:\
+# :memoryuse=8M:\
+# :filesize=8M:\
+# :coredumpsize=8M:\
+# :openfiles=24:\
+# :maxproc=32:\
+# :priority=0:\
+# :requirehome:\
+# :passwordtime=90d:\
+# :umask=002:\
+# :tc=default:
+#
+#
+##
+## users of X (needs more resources!)
+##
+#xuser:\
+# :manpath=/usr/share/man /usr/local/man:\
+# :cputime=4h:\
+# :datasize=12M:\
+# :vmemoryuse=infinity:\
+# :stacksize=4M:\
+# :filesize=8M:\
+# :memoryuse=16M:\
+# :openfiles=32:\
+# :maxproc=48:\
+# :tc=standard:
+#
+#
+##
+## Staff users - few restrictions and allow login anytime
+##
+#staff:\
+# :ignorenologin:\
+# :requirehome@:\
+# :accounted@:\
+# :path=~/bin /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin:\
+# :umask=022:\
+# :tc=standard:
+#
+#
+##
+## root - fallback for root logins
+##
+#root:\
+# :path=~/bin /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin:\
+# :cputime=infinity:\
+# :datasize=infinity:\
+# :stacksize=infinity:\
+# :memorylocked=infinity:\
+# :memoryuse=infinity:\
+# :filesize=infinity:\
+# :coredumpsize=infinity:\
+# :openfiles=infinity:\
+# :maxproc=infinity:\
+# :memoryuse-cur=32M:\
+# :maxproc-cur=64:\
+# :openfiles-cur=1024:\
+# :priority=0:\
+# :requirehome@:\
+# :umask=022:\
+# :tc=auth-root-defaults:
+#
+#
+##
+## Settings used by /etc/rc
+##
+#daemon:\
+# :coredumpsize@:\
+# :coredumpsize-cur=0:\
+# :datasize=infinity:\
+# :datasize-cur@:\
+# :maxproc=512:\
+# :maxproc-cur@:\
+# :memoryuse-cur=64M:\
+# :memorylocked-cur=64M:\
+# :openfiles=1024:\
+# :openfiles-cur@:\
+# :stacksize=16M:\
+# :stacksize-cur@:\
+# :tc=default:
+#
+#
+##
+## Settings used by news subsystem
+##
+#news:\
+# :path=/usr/local/news/bin /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin:\
+# :cputime=infinity:\
+# :filesize=128M:\
+# :datasize-cur=64M:\
+# :stacksize-cur=32M:\
+# :coredumpsize-cur=0:\
+# :maxmemorysize-cur=128M:\
+# :memorylocked=32M:\
+# :maxproc=128:\
+# :openfiles=256:\
+# :tc=default:
+#
+#
+##
+## The dialer class should be used for a dialup PPP account
+## Welcome messages/news suppressed
+##
+#dialer:\
+# :hushlogin:\
+# :requirehome@:\
+# :cputime=unlimited:\
+# :filesize=2M:\
+# :datasize=2M:\
+# :stacksize=4M:\
+# :coredumpsize=0:\
+# :memoryuse=4M:\
+# :memorylocked=1M:\
+# :maxproc=16:\
+# :openfiles=32:\
+# :tc=standard:
+#
+#
+##
+## Site full-time 24/7 PPP connection
+## - no time accounting, restricted to access via dialin lines
+##
+#site:\
+# :passwordtime@:\
+# :refreshtime@:\
+# :refreshperiod@:\
+# :sessionlimit@:\
+# :autodelete@:\
+# :expireperiod@:\
+# :graceexpire@:\
+# :gracetime@:\
+# :warnexpire@:\
+# :warnpassword@:\
+# :idletime@:\
+# :sessiontime@:\
+# :daytime@:\
+# :weektime@:\
+# :monthtime@:\
+# :warntime@:\
+# :accounted@:\
+# :tc=dialer:\
+# :tc=staff:
+#
+#
+##
+## Example standard accounting entries for subscriber levels
+##
+#
+#subscriber|Subscribers:\
+# :accounted:\
+# :refreshtime=180d:\
+# :refreshperiod@:\
+# :sessionlimit@:\
+# :autodelete=30d:\
+# :expireperiod=180d:\
+# :graceexpire=7d:\
+# :gracetime=10m:\
+# :warnexpire=7d:\
+# :warnpassword=7d:\
+# :idletime=30m:\
+# :sessiontime=4h:\
+# :daytime=6h:\
+# :weektime=40h:\
+# :monthtime=120h:\
+# :warntime=4h:\
+# :tc=standard:
+#
+#
+##
+## Subscriber accounts. These accounts have their login times
+## accounted and have access limits applied.
+##
+#subppp|PPP Subscriber Accounts:\
+# :tc=dialer:\
+# :tc=subscriber:
+#
+#
+#subshell|Shell Subscriber Accounts:\
+# :tc=subscriber:
+#
+##
+## If you want some of the accounts to use traditional UNIX DES based
+## password hashes.
+##
+#des_users:\
+# :passwd_format=des:\
+# :tc=default:
diff --git a/usr.bin/login/login.h b/usr.bin/login/login.h
new file mode 100644
index 000000000000..11760428d5ae
--- /dev/null
+++ b/usr.bin/login/login.h
@@ -0,0 +1,37 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2001 FreeBSD, Inc
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+void login_fbtab(char *, uid_t, gid_t);
+
+#ifdef USE_BSM_AUDIT
+void au_login_success(void);
+void au_login_fail(const char *errmsg, int na);
+void audit_logout(void);
+#endif
+
+extern char **environ;
+extern struct passwd *pwd;
diff --git a/usr.bin/login/login_audit.c b/usr.bin/login/login_audit.c
new file mode 100644
index 000000000000..1f2ec4d80cc9
--- /dev/null
+++ b/usr.bin/login/login_audit.c
@@ -0,0 +1,203 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2005 Apple Computer, Inc.
+ * All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "login.h"
+
+/*
+ * Audit data
+ */
+static au_tid_t tid;
+
+/*
+ * The following tokens are included in the audit record for a successful
+ * login: header, subject, return.
+ */
+void
+au_login_success(void)
+{
+ token_t *tok;
+ int aufd;
+ au_mask_t aumask;
+ auditinfo_t auinfo;
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+ pid_t pid = getpid();
+ int au_cond;
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(au_cond)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ /* Compute and set the user's preselection mask. */
+ if (au_user_mask(pwd->pw_name, &aumask) == -1)
+ errx(1, "could not calculate audit mask");
+
+ /* Set the audit info for the user. */
+ auinfo.ai_auid = uid;
+ auinfo.ai_asid = pid;
+ bcopy(&tid, &auinfo.ai_termid, sizeof(auinfo.ai_termid));
+ bcopy(&aumask, &auinfo.ai_mask, sizeof(auinfo.ai_mask));
+ if (setaudit(&auinfo) != 0)
+ err(1, "setaudit failed");
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "audit error: au_open() failed");
+
+ if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, gid, pid,
+ pid, &tid)) == NULL)
+ errx(1, "audit error: au_to_subject32() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(0, 0)) == NULL)
+ errx(1, "audit error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_login) == -1)
+ errx(1, "audit record was not committed.");
+}
+
+/*
+ * The following tokens are included in the audit record for failed
+ * login attempts: header, subject, text, return.
+ */
+void
+au_login_fail(const char *errmsg, int na)
+{
+ token_t *tok;
+ int aufd;
+ int au_cond;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid = getpid();
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(au_cond)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "audit error: au_open() failed");
+
+ if (na) {
+ /*
+ * Non attributable event. Assuming that login is not called
+ * within a user's session => auid,asid == -1.
+ */
+ if ((tok = au_to_subject32(-1, geteuid(), getegid(), -1, -1,
+ pid, -1, &tid)) == NULL)
+ errx(1, "audit error: au_to_subject32() failed");
+ } else {
+ /* We know the subject -- so use its value instead. */
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+ if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid,
+ gid, pid, pid, &tid)) == NULL)
+ errx(1, "audit error: au_to_subject32() failed");
+ }
+ au_write(aufd, tok);
+
+ /* Include the error message. */
+ if ((tok = au_to_text(errmsg)) == NULL)
+ errx(1, "audit error: au_to_text() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(1, errno)) == NULL)
+ errx(1, "audit error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_login) == -1)
+ errx(1, "audit error: au_close() was not committed");
+}
+
+/*
+ * The following tokens are included in the audit record for a logout:
+ * header, subject, return.
+ */
+void
+audit_logout(void)
+{
+ token_t *tok;
+ int aufd;
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+ pid_t pid = getpid();
+ int au_cond;
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(au_cond)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "audit error: au_open() failed");
+
+ /* The subject that is created (euid, egid of the current process). */
+ if ((tok = au_to_subject32(uid, geteuid(), getegid(), uid, gid, pid,
+ pid, &tid)) == NULL)
+ errx(1, "audit error: au_to_subject32() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(0, 0)) == NULL)
+ errx(1, "audit error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_logout) == -1)
+ errx(1, "audit record was not committed.");
+}
diff --git a/usr.bin/login/login_fbtab.c b/usr.bin/login/login_fbtab.c
new file mode 100644
index 000000000000..5c846534d0c4
--- /dev/null
+++ b/usr.bin/login/login_fbtab.c
@@ -0,0 +1,139 @@
+/************************************************************************
+* Copyright 1995 by Wietse Venema. All rights reserved.
+*
+* This material was originally written and compiled by Wietse Venema at
+* Eindhoven University of Technology, The Netherlands, in 1990, 1991,
+* 1992, 1993, 1994 and 1995.
+*
+* Redistribution and use in source and binary forms are permitted
+* provided that this entire copyright notice is duplicated in all such
+* copies.
+*
+* This software is provided "as is" and without any expressed or implied
+* warranties, including, without limitation, the implied warranties of
+* merchantibility and fitness for any particular purpose.
+************************************************************************/
+/*
+ SYNOPSIS
+ void login_fbtab(tty, uid, gid)
+ char *tty;
+ uid_t uid;
+ gid_t gid;
+
+ DESCRIPTION
+ This module implements device security as described in the
+ SunOS 4.1.x fbtab(5) and SunOS 5.x logindevperm(4) manual
+ pages. The program first looks for /etc/fbtab. If that file
+ cannot be opened it attempts to process /etc/logindevperm.
+ We expect entries with the following format:
+
+ Comments start with a # and extend to the end of the line.
+
+ Blank lines or lines with only a comment are ignored.
+
+ All other lines consist of three fields delimited by
+ whitespace: a login device (/dev/console), an octal
+ permission number (0600), and a ":"-delimited list of
+ devices (/dev/kbd:/dev/mouse). All device names are
+ absolute paths. A path that ends in "*" refers to all
+ directory entries except "." and "..".
+
+ If the tty argument (relative path) matches a login device
+ name (absolute path), the permissions of the devices in the
+ ":"-delimited list are set as specified in the second
+ field, and their ownership is changed to that of the uid
+ and gid arguments.
+
+ DIAGNOSTICS
+ Problems are reported via the syslog daemon with severity
+ LOG_ERR.
+
+ BUGS
+ This module uses strtok(3), which may cause conflicts with other
+ uses of that same routine.
+
+ AUTHOR
+ Wietse Venema (wietse@wzv.win.tue.nl)
+ Eindhoven University of Technology
+ The Netherlands
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "login.h"
+#include "pathnames.h"
+
+static void login_protect(const char *, char *, int, uid_t, gid_t);
+
+#define WSPACE " \t\n"
+
+/* login_fbtab - apply protections specified in /etc/fbtab or logindevperm */
+
+void
+login_fbtab(char *tty, uid_t uid, gid_t gid)
+{
+ FILE *fp;
+ char buf[BUFSIZ];
+ char *devname;
+ char *cp;
+ int prot;
+ const char *table;
+
+ if ((fp = fopen(table = _PATH_FBTAB, "r")) == NULL
+ && (fp = fopen(table = _PATH_LOGINDEVPERM, "r")) == NULL)
+ return;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if ((cp = strchr(buf, '#')))
+ *cp = 0; /* strip comment */
+ if ((cp = devname = strtok(buf, WSPACE)) == NULL)
+ continue; /* empty or comment */
+ if (strncmp(devname, _PATH_DEV, sizeof _PATH_DEV - 1) != 0
+ || (cp = strtok(NULL, WSPACE)) == NULL
+ || *cp != '0'
+ || sscanf(cp, "%o", &prot) == 0
+ || prot == 0
+ || (prot & 0777) != prot
+ || (cp = strtok(NULL, WSPACE)) == NULL) {
+ syslog(LOG_ERR, "%s: bad entry: %s", table, cp ? cp : "(null)");
+ continue;
+ }
+ if (strcmp(devname + 5, tty) == 0) {
+ for (cp = strtok(cp, ":"); cp; cp = strtok(NULL, ":")) {
+ login_protect(table, cp, prot, uid, gid);
+ }
+ }
+ }
+ fclose(fp);
+}
+
+/* login_protect - protect one device entry */
+
+static void
+login_protect(const char *table, char *pattern, int mask, uid_t uid, gid_t gid)
+{
+ glob_t gl;
+ char *path;
+ unsigned int i;
+
+ if (glob(pattern, GLOB_NOSORT, NULL, &gl) != 0)
+ return;
+ for (i = 0; i < gl.gl_pathc; i++) {
+ path = gl.gl_pathv[i];
+ /* clear flags of the device */
+ if (chflags(path, 0) && errno != ENOENT && errno != EOPNOTSUPP)
+ syslog(LOG_ERR, "%s: chflags(%s): %m", table, path);
+ if (chmod(path, mask) && errno != ENOENT)
+ syslog(LOG_ERR, "%s: chmod(%s): %m", table, path);
+ if (chown(path, uid, gid) && errno != ENOENT)
+ syslog(LOG_ERR, "%s: chown(%s): %m", table, path);
+ }
+ globfree(&gl);
+}
diff --git a/usr.bin/login/motd.template b/usr.bin/login/motd.template
new file mode 100644
index 000000000000..e743370ca0a2
--- /dev/null
+++ b/usr.bin/login/motd.template
@@ -0,0 +1,20 @@
+
+Welcome to FreeBSD!
+
+Release Notes, Errata: https://www.FreeBSD.org/releases/
+Security Advisories: https://www.FreeBSD.org/security/
+FreeBSD Handbook: https://www.FreeBSD.org/handbook/
+FreeBSD FAQ: https://www.FreeBSD.org/faq/
+Questions List: https://www.FreeBSD.org/lists/questions/
+FreeBSD Forums: https://forums.FreeBSD.org/
+
+Documents installed with the system are in the /usr/local/share/doc/freebsd/
+directory, or can be installed later with: pkg install en-freebsd-doc
+For other languages, replace "en" with a language code like de or fr.
+
+Show the version of FreeBSD installed: freebsd-version ; uname -a
+Please include that output and any error messages when posting questions.
+Introduction to manual pages: man man
+FreeBSD directory layout: man hier
+
+To change this login announcement, see motd(5).
diff --git a/usr.bin/login/pathnames.h b/usr.bin/login/pathnames.h
new file mode 100644
index 000000000000..25de2baa75ec
--- /dev/null
+++ b/usr.bin/login/pathnames.h
@@ -0,0 +1,37 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <paths.h>
+
+#define _PATH_HUSHLOGIN ".hushlogin"
+#define _PATH_MOTDFILE "/var/run/motd"
+#define _PATH_FBTAB "/etc/fbtab"
+#define _PATH_LOGINDEVPERM "/etc/logindevperm"