diff options
Diffstat (limited to 'usr.bin/login')
| -rw-r--r-- | usr.bin/login/Makefile | 34 | ||||
| -rw-r--r-- | usr.bin/login/Makefile.depend | 17 | ||||
| -rw-r--r-- | usr.bin/login/Makefile.depend.options | 5 | ||||
| -rw-r--r-- | usr.bin/login/README | 10 | ||||
| -rw-r--r-- | usr.bin/login/fbtab | 3 | ||||
| -rw-r--r-- | usr.bin/login/login.1 | 161 | ||||
| -rw-r--r-- | usr.bin/login/login.access | 45 | ||||
| -rw-r--r-- | usr.bin/login/login.c | 1034 | ||||
| -rw-r--r-- | usr.bin/login/login.conf | 326 | ||||
| -rw-r--r-- | usr.bin/login/login.h | 37 | ||||
| -rw-r--r-- | usr.bin/login/login_audit.c | 203 | ||||
| -rw-r--r-- | usr.bin/login/login_fbtab.c | 139 | ||||
| -rw-r--r-- | usr.bin/login/motd.template | 20 | ||||
| -rw-r--r-- | usr.bin/login/pathnames.h | 37 |
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" |
