2 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)login.c 8.4 (Berkeley) 4/2/94
34 * $FreeBSD: src/usr.bin/login/login.c,v 1.51.2.15 2003/04/29 14:10:41 des Exp $
35 * $DragonFly: src/usr.bin/login/login.c,v 1.6 2006/01/12 13:43:11 corecode Exp $
39 static char copyright
[] =
40 "@(#) Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994\n\
41 The Regents of the University of California. All rights reserved.\n";
46 * login -h hostname (for telnetd, etc.)
47 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
50 #include <sys/copyright.h>
51 #include <sys/param.h>
53 #include <sys/socket.h>
55 #include <sys/resource.h>
57 #include <netinet/in.h>
58 #include <arpa/inet.h>
64 #include <login_cap.h>
78 #include <security/pam_appl.h>
79 #include <security/pam_types.h>
80 #include <security/openpam.h>
84 #include "pathnames.h"
86 /* wrapper for KAME-special getnameinfo() */
87 #ifndef NI_WITHSCOPEID
88 #define NI_WITHSCOPEID 0
91 void badlogin(char *);
92 void checknologin(void);
94 void getloginname(void);
99 void refused(char *,char *,int);
100 char *stypeof(char *);
102 int login_access(char *, char *);
103 void login_fbtab(char *, uid_t
, gid_t
);
106 static int auth_pam(void);
107 static int export_pam_environment(void);
108 static int ok_to_export(const char *);
110 static pam_handle_t
*pamh
= NULL
;
111 static char **environ_pam
;
114 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
115 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \
116 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \
117 syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \
118 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \
119 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \
122 static int auth_traditional(void);
123 extern void login(struct utmp
*);
124 static void usage(void);
126 #define TTYGRPNAME "tty" /* name of group to own ttys */
127 #define DEFAULT_BACKOFF 3
128 #define DEFAULT_RETRIES 10
129 #define DEFAULT_PROMPT "login: "
130 #define DEFAULT_PASSWD_PROMPT "Password:"
133 * This bounds the time given to login. Not a define so it can
134 * be patched on machines where it's too small.
138 /* Buffer for signal handling of timeout */
143 char *term
, *envinit
[1], *hostname
, *passwd_prompt
, *prompt
, *tty
, *username
;
144 char full_hostname
[MAXHOSTNAMELEN
];
147 main(int argc
, char **argv
)
149 extern char **environ
;
154 int rootok
, retries
, backoff
;
155 int ask
, ch
, cnt
, fflag
, hflag
, pflag
, quietlog
, rootlogin
, rval
;
161 char tbuf
[MAXPATHLEN
+ 2];
162 char tname
[sizeof(_PATH_TTY
) + 10];
164 login_cap_t
*lc
= NULL
;
170 (void)signal(SIGQUIT
, SIG_IGN
);
171 (void)signal(SIGINT
, SIG_IGN
);
172 (void)signal(SIGHUP
, SIG_IGN
);
173 if (setjmp(timeout_buf
)) {
176 (void)fprintf(stderr
, "Login timed out after %d seconds\n",
180 (void)signal(SIGALRM
, timedout
);
181 (void)alarm(timeout
);
182 (void)setpriority(PRIO_PROCESS
, 0, 0);
184 openlog("login", LOG_ODELAY
, LOG_AUTH
);
187 * -p is used by getty to tell login not to destroy the environment
188 * -f is used to skip a second login authentication
189 * -h is used by other servers to pass the name of the remote
190 * host to login so that it may be placed in utmp and wtmp
192 *full_hostname
= '\0';
195 fflag
= hflag
= pflag
= 0;
199 while ((ch
= getopt(argc
, argv
, "fh:p")) != -1)
206 errx(1, "-h option: %s", strerror(EPERM
));
208 if (strlcpy(full_hostname
, optarg
,
209 sizeof(full_hostname
)) >= sizeof(full_hostname
))
210 errx(1, "-h option: %s: exceeds maximum "
211 "hostname size", optarg
);
213 trimdomain(optarg
, UT_HOSTSIZE
);
215 if (strlen(optarg
) > UT_HOSTSIZE
) {
216 struct addrinfo hints
, *res
;
219 memset(&hints
, 0, sizeof(hints
));
220 hints
.ai_family
= AF_UNSPEC
;
221 ga_err
= getaddrinfo(optarg
, NULL
, &hints
,
224 char hostbuf
[MAXHOSTNAMELEN
];
226 getnameinfo(res
->ai_addr
,
229 sizeof(hostbuf
), NULL
, 0,
232 optarg
= strdup(hostbuf
);
233 if (optarg
== NULL
) {
239 optarg
= "invalid hostname";
251 syslog(LOG_ERR
, "invalid flag %c", ch
);
263 setproctitle("-%s", getprogname());
265 for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
268 ttyn
= ttyname(STDIN_FILENO
);
269 if (ttyn
== NULL
|| *ttyn
== '\0') {
270 (void)snprintf(tname
, sizeof(tname
), "%s??", _PATH_TTY
);
273 if ((tty
= strrchr(ttyn
, '/')) != NULL
)
279 * Get "login-retries" & "login-backoff" from default class
281 lc
= login_getclass(NULL
);
282 prompt
= login_getcapstr(lc
, "login_prompt",
283 DEFAULT_PROMPT
, DEFAULT_PROMPT
);
284 passwd_prompt
= login_getcapstr(lc
, "passwd_prompt",
285 DEFAULT_PASSWD_PROMPT
, DEFAULT_PASSWD_PROMPT
);
286 retries
= login_getcapnum(lc
, "login-retries", DEFAULT_RETRIES
,
288 backoff
= login_getcapnum(lc
, "login-backoff", DEFAULT_BACKOFF
,
293 for (cnt
= 0;; ask
= 1) {
299 rootok
= rootterm(tty
); /* Default (auth may change) */
301 if (strlen(username
) > UT_NAMESIZE
)
302 username
[UT_NAMESIZE
] = '\0';
305 * Note if trying multiple user names; log failures for
306 * previous user name, but don't bother logging one failure
307 * for nonexistent name (mistyped username).
309 if (failures
&& strcmp(tbuf
, username
)) {
310 if (failures
> (pwd
? 0 : 1))
313 (void)strlcpy(tbuf
, username
, sizeof(tbuf
));
315 pwd
= getpwnam(username
);
318 * if we have a valid account name, and it doesn't have a
319 * password, or the -f option was specified and the caller
320 * is root or the caller isn't changing their uid, don't
324 if (pwd
->pw_uid
== 0)
327 if (fflag
&& (uid
== (uid_t
)0 ||
328 uid
== (uid_t
)pwd
->pw_uid
)) {
329 /* already authenticated */
331 } else if (pwd
->pw_passwd
[0] == '\0') {
332 if (!rootlogin
|| rootok
) {
333 /* pretend password okay */
342 (void)setpriority(PRIO_PROCESS
, 0, -4);
346 * Try to authenticate using PAM. If a PAM system error
347 * occurs, perhaps because of a botched configuration,
348 * then fall back to using traditional Unix authentication.
350 if ((rval
= auth_pam()) == -1)
352 rval
= auth_traditional();
354 (void)setpriority(PRIO_PROCESS
, 0, 0);
358 * PAM authentication may have changed "pwd" to the
359 * entry for the template user. Check again to see if
360 * this is a root login after all.
362 if (pwd
!= NULL
&& pwd
->pw_uid
== 0)
368 * If trying to log in as root without Kerberos,
369 * but with insecure terminal, refuse the login attempt.
372 if (rootlogin
&& !rootok
)
373 refused(NULL
, "NOROOT", 0);
374 else /* valid password & authenticated */
378 (void)printf("Login incorrect\n");
382 * we allow up to 'retry' (10) tries,
383 * but after 'backoff' (3) we start backing off
385 if (++cnt
> backoff
) {
386 if (cnt
>= retries
) {
390 sleep((u_int
)((cnt
- backoff
) * 5));
394 /* committed to login -- turn off timeout */
395 (void)alarm((u_int
)0);
396 (void)signal(SIGHUP
, SIG_DFL
);
401 * Establish the login class.
403 lc
= login_getpwclass(pwd
);
405 /* if user not super-user, check for disabled logins */
407 auth_checknologin(lc
);
409 quietlog
= login_getcapbool(lc
, "hushlogin", 0);
410 /* Switching needed for NFS with root access disabled */
411 (void)setegid(pwd
->pw_gid
);
412 (void)seteuid(rootlogin
? 0 : pwd
->pw_uid
);
413 if (!*pwd
->pw_dir
|| chdir(pwd
->pw_dir
) < 0) {
414 if (login_getcapbool(lc
, "requirehome", 0))
415 refused("Home directory not available", "HOMEDIR", 1);
417 refused("Cannot find root directory", "ROOTDIR", 1);
418 if (!quietlog
|| *pwd
->pw_dir
)
419 printf("No home directory.\nLogging in with home = \"/\".\n");
425 quietlog
= access(_PATH_HUSHLOGIN
, F_OK
) == 0;
427 if (pwd
->pw_change
|| pwd
->pw_expire
)
428 (void)gettimeofday(&tp
, (struct timezone
*)NULL
);
430 #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
432 warntime
= login_getcaptime(lc
, "warnexpire", DEFAULT_WARN
,
435 if (pwd
->pw_expire
) {
436 if (tp
.tv_sec
>= pwd
->pw_expire
) {
437 refused("Sorry -- your account has expired", "EXPIRED",
439 } else if (pwd
->pw_expire
- tp
.tv_sec
< warntime
&& !quietlog
)
440 (void)printf("Warning: your account expires on %s",
441 ctime(&pwd
->pw_expire
));
444 warntime
= login_getcaptime(lc
, "warnpassword", DEFAULT_WARN
,
448 if (pwd
->pw_change
) {
449 if (tp
.tv_sec
>= pwd
->pw_change
) {
450 (void)printf("Sorry -- your password has expired.\n");
452 syslog(LOG_INFO
, "%s Password expired - forcing change",
454 } else if (pwd
->pw_change
- tp
.tv_sec
< warntime
&& !quietlog
)
455 (void)printf("Warning: your password expires on %s",
456 ctime(&pwd
->pw_change
));
461 struct addrinfo hints
, *res
;
464 memset(&hints
, 0, sizeof(hints
));
465 hints
.ai_family
= AF_UNSPEC
;
466 ga_err
= getaddrinfo(full_hostname
, NULL
, &hints
,
469 char hostbuf
[MAXHOSTNAMELEN
];
471 getnameinfo(res
->ai_addr
, res
->ai_addrlen
,
472 hostbuf
, sizeof(hostbuf
), NULL
, 0,
473 NI_NUMERICHOST
|NI_WITHSCOPEID
);
474 if ((optarg
= strdup(hostbuf
)) == NULL
) {
475 syslog(LOG_NOTICE
, "strdup(): %m");
482 if (!auth_hostok(lc
, full_hostname
, optarg
))
483 refused("Permission denied", "HOST", 1);
486 if (!auth_ttyok(lc
, tty
))
487 refused("Permission denied", "TTY", 1);
489 if (!auth_timeok(lc
, time(NULL
)))
490 refused("Logins not available right now", "TIME", 1);
492 shell
= login_getcapstr(lc
, "shell", pwd
->pw_shell
, pwd
->pw_shell
);
493 if (*pwd
->pw_shell
== '\0')
494 pwd
->pw_shell
= _PATH_BSHELL
;
495 if (*shell
== '\0') /* Not overridden */
496 shell
= pwd
->pw_shell
;
497 if ((shell
= strdup(shell
)) == NULL
) {
498 syslog(LOG_NOTICE
, "strdup(): %m");
503 if (login_access(pwd
->pw_name
, hostname
? full_hostname
: tty
) == 0)
504 refused("Permission denied", "ACCESS", 1);
505 #endif /* LOGIN_ACCESS */
507 /* Nothing else left to fail -- really log in. */
508 memset((void *)&utmp
, 0, sizeof(utmp
));
509 (void)time(&utmp
.ut_time
);
510 (void)strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
512 (void)strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
513 (void)strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
519 * Set device protections, depending on what terminal the
520 * user is logged in. This feature is used on Suns to give
521 * console users better privacy.
523 login_fbtab(tty
, pwd
->pw_uid
, pwd
->pw_gid
);
526 * Clear flags of the tty. None should be set, and when the
527 * user sets them otherwise, this can cause the chown to fail.
528 * Since it isn't clear that flags are useful on character
529 * devices, we just clear them.
531 if (ttyn
!= tname
&& chflags(ttyn
, 0) && errno
!= EOPNOTSUPP
)
532 syslog(LOG_ERR
, "chflags(%s): %m", ttyn
);
533 if (ttyn
!= tname
&& chown(ttyn
, pwd
->pw_uid
,
534 (gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
))
535 syslog(LOG_ERR
, "chmod(%s): %m", ttyn
);
539 * Preserve TERM if it happens to be already set.
541 if ((term
= getenv("TERM")) != NULL
) {
542 if ((term
= strdup(term
)) == NULL
) {
550 * Exclude cons/vt/ptys only, assume dialup otherwise
551 * TODO: Make dialup tty determination a library call
552 * for consistency (finger etc.)
554 if (hostname
==NULL
&& isdialuptty(tty
))
555 syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
559 * Syslog each successful login, so we don't have to watch hundreds
560 * of wtmp or lastlogin files.
563 syslog(LOG_INFO
, "login from %s on %s as %s",
564 full_hostname
, tty
, pwd
->pw_name
);
566 syslog(LOG_INFO
, "login on %s as %s",
571 * If fflag is on, assume caller/authenticator has logged root login.
573 if (rootlogin
&& fflag
== 0)
576 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s FROM %s",
577 username
, tty
, full_hostname
);
579 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s",
584 * Destroy environment unless user has requested its preservation.
585 * We need to do this before setusercontext() because that may
586 * set or reset some environment variables.
592 * PAM modules might add supplementary groups during pam_setcred().
594 if (setusercontext(lc
, pwd
, pwd
->pw_uid
, LOGIN_SETGROUP
) != 0) {
595 syslog(LOG_ERR
, "setusercontext() failed - exiting");
601 if ((e
= pam_open_session(pamh
, 0)) != PAM_SUCCESS
) {
602 syslog(LOG_ERR
, "pam_open_session: %s",
603 pam_strerror(pamh
, e
));
604 } else if ((e
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
))
606 syslog(LOG_ERR
, "pam_setcred: %s",
607 pam_strerror(pamh
, e
));
611 * Add any environmental variables that the
612 * PAM modules may have set.
613 * Call *after* opening session!
616 environ_pam
= pam_getenvlist(pamh
);
618 export_pam_environment();
622 * We must fork() before setuid() because we need to call
623 * pam_close_session() as root.
631 /* parent - wait for child to finish, then cleanup
633 setproctitle("-%s [pam]", getprogname());
638 if ((e
= pam_end(pamh
, PAM_SILENT
)) != PAM_SUCCESS
)
639 syslog(LOG_ERR
, "pam_end: %s",
640 pam_strerror(pamh
, e
));
646 * We don't need to be root anymore, so
647 * set the user and session context
649 if (setlogin(username
) != 0) {
650 syslog(LOG_ERR
, "setlogin(%s): %m - exiting", username
);
653 if (setusercontext(lc
, pwd
, pwd
->pw_uid
,
654 LOGIN_SETALL
& ~(LOGIN_SETLOGIN
|LOGIN_SETGROUP
)) != 0) {
655 syslog(LOG_ERR
, "setusercontext() failed - exiting");
659 if (setenv("SHELL", pwd
->pw_shell
, 1) == -1)
660 err(1, "setenv: cannot set SHELL=%s", pwd
->pw_shell
);
661 if (setenv("HOME", pwd
->pw_dir
, 1) == -1)
662 err(1, "setenv: cannot set HOME=%s", pwd
->pw_dir
);
663 if (term
!= NULL
&& *term
!= '\0') {
664 if (setenv("TERM", term
, 1) == -1) /* Preset overrides */
665 err(1, "setenv: cannot set TERM=%s", term
);
668 if (setenv("TERM", stypeof(tty
), 0) == -1) /* Fallback doesn't */
669 err(1, "setenv: cannot set TERM=%s", stypeof(tty
));
671 if (setenv("LOGNAME", username
, 1) == -1)
672 err(1, "setenv: cannot set LOGNAME=%s", username
);
673 if (setenv("USER", username
, 1) == -1)
674 err(1, "setenv: cannot set USER=%s", username
);
675 if (setenv("PATH", rootlogin
? _PATH_STDPATH
: _PATH_DEFPATH
, 0) == -1)
676 err(1, "setenv: cannot set PATH=%s", rootlogin
? _PATH_STDPATH
: _PATH_DEFPATH
);
681 cw
= login_getcapstr(lc
, "copyright", NULL
, NULL
);
682 if (cw
!= NULL
&& access(cw
, F_OK
) == 0)
685 (void)printf("%s\n\t%s %s\n",
686 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
687 "The Regents of the University of California. ",
688 "All rights reserved.");
692 cw
= login_getcapstr(lc
, "welcome", NULL
, NULL
);
693 if (cw
== NULL
|| access(cw
, F_OK
) != 0)
697 cw
= getenv("MAIL"); /* $MAIL may have been set by class */
699 strlcpy(tbuf
, cw
, sizeof(tbuf
));
701 snprintf(tbuf
, sizeof(tbuf
), "%s/%s", _PATH_MAILDIR
,
703 if (stat(tbuf
, &st
) == 0 && st
.st_size
!= 0)
704 (void)printf("You have %smail.\n",
705 (st
.st_mtime
> st
.st_atime
) ? "new " : "");
710 (void)signal(SIGALRM
, SIG_DFL
);
711 (void)signal(SIGQUIT
, SIG_DFL
);
712 (void)signal(SIGINT
, SIG_DFL
);
713 (void)signal(SIGTSTP
, SIG_IGN
);
716 if (system(_PATH_CHPASS
) != 0)
721 * Login shells have a leading '-' in front of argv[0]
723 if (snprintf(tbuf
, sizeof(tbuf
), "-%s",
724 (p
= strrchr(pwd
->pw_shell
, '/')) ? p
+ 1 : pwd
->pw_shell
) >=
726 syslog(LOG_ERR
, "user: %s: shell exceeds maximum pathname size",
728 errx(1, "shell exceeds maximum pathname size");
731 execlp(shell
, tbuf
, (char *)0);
736 auth_traditional(void)
744 salt
= pwd
!= NULL
? pwd
->pw_passwd
: "xx";
746 p
= getpass(passwd_prompt
);
750 if (!p
[0] && pwd
->pw_passwd
[0])
752 if (strcmp(ep
, pwd
->pw_passwd
) == 0)
756 /* clear entered password */
757 memset(p
, 0, strlen(p
));
763 * Attempt to authenticate the user using PAM. Returns 0 if the user is
764 * authenticated, or 1 if not authenticated. If some sort of PAM system
765 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
766 * function returns -1. This can be used as an indication that we should
767 * fall back to a different authentication mechanism.
772 const char *tmpl_user
;
776 static struct pam_conv conv
;
778 conv
.conv
= &openpam_ttyconv
;
780 if ((e
= pam_start("login", username
, &conv
, &pamh
)) != PAM_SUCCESS
) {
781 syslog(LOG_ERR
, "pam_start: %s", pam_strerror(pamh
, e
));
784 if ((e
= pam_set_item(pamh
, PAM_TTY
, tty
)) != PAM_SUCCESS
) {
785 syslog(LOG_ERR
, "pam_set_item(PAM_TTY): %s",
786 pam_strerror(pamh
, e
));
789 if (hostname
!= NULL
&&
790 (e
= pam_set_item(pamh
, PAM_RHOST
, full_hostname
)) != PAM_SUCCESS
) {
791 syslog(LOG_ERR
, "pam_set_item(PAM_RHOST): %s",
792 pam_strerror(pamh
, e
));
795 e
= pam_authenticate(pamh
, 0);
800 * With PAM we support the concept of a "template"
801 * user. The user enters a login name which is
802 * authenticated by PAM, usually via a remote service
803 * such as RADIUS or TACACS+. If authentication
804 * succeeds, a different but related "template" name
805 * is used for setting the credentials, shell, and
806 * home directory. The name the user enters need only
807 * exist on the remote authentication server, but the
808 * template name must be present in the local password
811 * This is supported by two various mechanisms in the
812 * individual modules. However, from the application's
813 * point of view, the template user is always passed
814 * back as a changed value of the PAM_USER item.
816 if ((e
= pam_get_item(pamh
, PAM_USER
, &item
)) ==
818 tmpl_user
= (const char *) item
;
819 if (strcmp(username
, tmpl_user
) != 0)
820 pwd
= getpwnam(tmpl_user
);
822 syslog(LOG_ERR
, "Couldn't get PAM_USER: %s",
823 pam_strerror(pamh
, e
));
828 case PAM_USER_UNKNOWN
:
834 syslog(LOG_ERR
, "pam_authenticate: %s", pam_strerror(pamh
, e
));
840 e
= pam_acct_mgmt(pamh
, 0);
841 if (e
== PAM_NEW_AUTHTOK_REQD
) {
842 e
= pam_chauthtok(pamh
, PAM_CHANGE_EXPIRED_AUTHTOK
);
843 if (e
!= PAM_SUCCESS
) {
844 syslog(LOG_ERR
, "pam_chauthtok: %s",
845 pam_strerror(pamh
, e
));
848 } else if (e
!= PAM_SUCCESS
) {
854 if ((e
= pam_end(pamh
, e
)) != PAM_SUCCESS
) {
855 syslog(LOG_ERR
, "pam_end: %s", pam_strerror(pamh
, e
));
863 export_pam_environment(void)
867 for (pp
= environ_pam
; *pp
!= NULL
; pp
++) {
868 if (ok_to_export(*pp
)) {
869 if (putenv(*pp
) == -1)
870 err(1, "putenv: cannot set %s", *pp
);
878 * Sanity checks on PAM environmental variables:
879 * - Make sure there is an '=' in the string.
880 * - Make sure the string doesn't run on too long.
881 * - Do not export certain variables. This list was taken from the
882 * Solaris pam_putenv(3) man page.
885 ok_to_export(const char *s
)
887 static const char *noexport
[] = {
888 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
894 if (strlen(s
) > 1024 || strchr(s
, '=') == NULL
)
896 if (strncmp(s
, "LD_", 3) == 0)
898 for (pp
= noexport
; *pp
!= NULL
; pp
++) {
900 if (s
[n
] == '=' && strncmp(s
, *pp
, n
) == 0)
911 (void)fprintf(stderr
, "usage: login [-fp] [-h hostname] [username]\n");
916 * Allow for authentication style and/or kerberos instance
919 #define NBUFSIZ UT_NAMESIZE + 64
926 static char nbuf
[NBUFSIZ
];
929 (void)printf("%s", prompt
);
930 for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
935 if (p
< nbuf
+ (NBUFSIZ
- 1))
940 (void)fprintf(stderr
,
941 "login names may not start with '-'.\n");
956 return ((t
= getttynam(ttyn
)) && t
->ty_status
& TTY_SECURE
);
959 volatile int motdinterrupt
;
962 sigint(int signo __unused
)
974 if ((fd
= open(motdfile
, O_RDONLY
, 0)) < 0)
977 oldint
= signal(SIGINT
, sigint
);
978 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0 && !motdinterrupt
)
979 (void)write(fileno(stdout
), tbuf
, nchars
);
980 (void)signal(SIGINT
, oldint
);
989 longjmp(timeout_buf
, signo
);
999 if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
1000 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
1002 if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
1004 (void)printf("Last login: %.*s ",
1005 24-5, (char *)ctime(&ll
.ll_time
));
1006 if (*ll
.ll_host
!= '\0')
1007 (void)printf("from %.*s\n",
1008 (int)sizeof(ll
.ll_host
),
1011 (void)printf("on %.*s\n",
1012 (int)sizeof(ll
.ll_line
),
1015 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
1017 memset((void *)&ll
, 0, sizeof(ll
));
1018 (void)time(&ll
.ll_time
);
1019 (void)strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
1021 (void)strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
1022 (void)write(fd
, (char *)&ll
, sizeof(ll
));
1025 syslog(LOG_ERR
, "cannot open %s: %m", _PATH_LASTLOG
);
1030 badlogin(char *name
)
1036 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s FROM %s",
1037 failures
, failures
> 1 ? "S" : "", full_hostname
);
1038 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
1039 "%d LOGIN FAILURE%s FROM %s, %s",
1040 failures
, failures
> 1 ? "S" : "", full_hostname
, name
);
1042 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s ON %s",
1043 failures
, failures
> 1 ? "S" : "", tty
);
1044 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
1045 "%d LOGIN FAILURE%s ON %s, %s",
1046 failures
, failures
> 1 ? "S" : "", tty
, name
);
1052 #define UNKNOWN "su"
1055 stypeof(char *ttyid
)
1059 if (ttyid
!= NULL
&& *ttyid
!= '\0') {
1060 t
= getttynam(ttyid
);
1061 if (t
!= NULL
&& t
->ty_type
!= NULL
)
1062 return (t
->ty_type
);
1068 refused(char *msg
, char *rtype
, int lout
)
1072 printf("%s.\n", msg
);
1074 syslog(LOG_NOTICE
, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1075 pwd
->pw_name
, rtype
, full_hostname
, tty
);
1077 syslog(LOG_NOTICE
, "LOGIN %s REFUSED (%s) ON TTY %s",
1078 pwd
->pw_name
, rtype
, tty
);