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.4 2003/11/03 19:31:30 eirikn 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_misc.h>
83 #include "pathnames.h"
85 /* wrapper for KAME-special getnameinfo() */
86 #ifndef NI_WITHSCOPEID
87 #define NI_WITHSCOPEID 0
90 void badlogin(char *);
91 void checknologin(void);
93 void getloginname(void);
98 void refused(char *,char *,int);
99 char *stypeof(char *);
101 int login_access(char *, char *);
102 void login_fbtab(char *, uid_t
, gid_t
);
105 static int auth_pam(void);
106 static int export_pam_environment(void);
107 static int ok_to_export(const char *);
109 static pam_handle_t
*pamh
= NULL
;
110 static char **environ_pam
;
113 if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) \
114 syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); \
115 if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) \
116 syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); \
117 if ((e = pam_end(pamh, e)) != PAM_SUCCESS) \
118 syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); \
121 static int auth_traditional(void);
122 extern void login(struct utmp
*);
123 static void usage(void);
125 #define TTYGRPNAME "tty" /* name of group to own ttys */
126 #define DEFAULT_BACKOFF 3
127 #define DEFAULT_RETRIES 10
128 #define DEFAULT_PROMPT "login: "
129 #define DEFAULT_PASSWD_PROMPT "Password:"
132 * This bounds the time given to login. Not a define so it can
133 * be patched on machines where it's too small.
137 /* Buffer for signal handling of timeout */
142 char *term
, *envinit
[1], *hostname
, *passwd_prompt
, *prompt
, *tty
, *username
;
143 char full_hostname
[MAXHOSTNAMELEN
];
146 main(int argc
, char **argv
)
148 extern char **environ
;
153 int rootok
, retries
, backoff
;
154 int ask
, ch
, cnt
, fflag
, hflag
, pflag
, quietlog
, rootlogin
, rval
;
160 char tbuf
[MAXPATHLEN
+ 2];
161 char tname
[sizeof(_PATH_TTY
) + 10];
163 login_cap_t
*lc
= NULL
;
169 (void)signal(SIGQUIT
, SIG_IGN
);
170 (void)signal(SIGINT
, SIG_IGN
);
171 (void)signal(SIGHUP
, SIG_IGN
);
172 if (setjmp(timeout_buf
)) {
175 (void)fprintf(stderr
, "Login timed out after %d seconds\n",
179 (void)signal(SIGALRM
, timedout
);
180 (void)alarm(timeout
);
181 (void)setpriority(PRIO_PROCESS
, 0, 0);
183 openlog("login", LOG_ODELAY
, LOG_AUTH
);
186 * -p is used by getty to tell login not to destroy the environment
187 * -f is used to skip a second login authentication
188 * -h is used by other servers to pass the name of the remote
189 * host to login so that it may be placed in utmp and wtmp
191 *full_hostname
= '\0';
194 fflag
= hflag
= pflag
= 0;
198 while ((ch
= getopt(argc
, argv
, "fh:p")) != -1)
205 errx(1, "-h option: %s", strerror(EPERM
));
207 if (strlcpy(full_hostname
, optarg
,
208 sizeof(full_hostname
)) >= sizeof(full_hostname
))
209 errx(1, "-h option: %s: exceeds maximum "
210 "hostname size", optarg
);
212 trimdomain(optarg
, UT_HOSTSIZE
);
214 if (strlen(optarg
) > UT_HOSTSIZE
) {
215 struct addrinfo hints
, *res
;
218 memset(&hints
, 0, sizeof(hints
));
219 hints
.ai_family
= AF_UNSPEC
;
220 ga_err
= getaddrinfo(optarg
, NULL
, &hints
,
223 char hostbuf
[MAXHOSTNAMELEN
];
225 getnameinfo(res
->ai_addr
,
228 sizeof(hostbuf
), NULL
, 0,
231 optarg
= strdup(hostbuf
);
232 if (optarg
== NULL
) {
238 optarg
= "invalid hostname";
250 syslog(LOG_ERR
, "invalid flag %c", ch
);
262 setproctitle("-%s", getprogname());
264 for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
267 ttyn
= ttyname(STDIN_FILENO
);
268 if (ttyn
== NULL
|| *ttyn
== '\0') {
269 (void)snprintf(tname
, sizeof(tname
), "%s??", _PATH_TTY
);
272 if ((tty
= strrchr(ttyn
, '/')) != NULL
)
278 * Get "login-retries" & "login-backoff" from default class
280 lc
= login_getclass(NULL
);
281 prompt
= login_getcapstr(lc
, "login_prompt",
282 DEFAULT_PROMPT
, DEFAULT_PROMPT
);
283 passwd_prompt
= login_getcapstr(lc
, "passwd_prompt",
284 DEFAULT_PASSWD_PROMPT
, DEFAULT_PASSWD_PROMPT
);
285 retries
= login_getcapnum(lc
, "login-retries", DEFAULT_RETRIES
,
287 backoff
= login_getcapnum(lc
, "login-backoff", DEFAULT_BACKOFF
,
292 for (cnt
= 0;; ask
= 1) {
298 rootok
= rootterm(tty
); /* Default (auth may change) */
300 if (strlen(username
) > UT_NAMESIZE
)
301 username
[UT_NAMESIZE
] = '\0';
304 * Note if trying multiple user names; log failures for
305 * previous user name, but don't bother logging one failure
306 * for nonexistent name (mistyped username).
308 if (failures
&& strcmp(tbuf
, username
)) {
309 if (failures
> (pwd
? 0 : 1))
312 (void)strlcpy(tbuf
, username
, sizeof(tbuf
));
314 pwd
= getpwnam(username
);
317 * if we have a valid account name, and it doesn't have a
318 * password, or the -f option was specified and the caller
319 * is root or the caller isn't changing their uid, don't
323 if (pwd
->pw_uid
== 0)
326 if (fflag
&& (uid
== (uid_t
)0 ||
327 uid
== (uid_t
)pwd
->pw_uid
)) {
328 /* already authenticated */
330 } else if (pwd
->pw_passwd
[0] == '\0') {
331 if (!rootlogin
|| rootok
) {
332 /* pretend password okay */
341 (void)setpriority(PRIO_PROCESS
, 0, -4);
345 * Try to authenticate using PAM. If a PAM system error
346 * occurs, perhaps because of a botched configuration,
347 * then fall back to using traditional Unix authentication.
349 if ((rval
= auth_pam()) == -1)
351 rval
= auth_traditional();
353 (void)setpriority(PRIO_PROCESS
, 0, 0);
357 * PAM authentication may have changed "pwd" to the
358 * entry for the template user. Check again to see if
359 * this is a root login after all.
361 if (pwd
!= NULL
&& pwd
->pw_uid
== 0)
367 * If trying to log in as root without Kerberos,
368 * but with insecure terminal, refuse the login attempt.
371 if (rootlogin
&& !rootok
)
372 refused(NULL
, "NOROOT", 0);
373 else /* valid password & authenticated */
377 (void)printf("Login incorrect\n");
381 * we allow up to 'retry' (10) tries,
382 * but after 'backoff' (3) we start backing off
384 if (++cnt
> backoff
) {
385 if (cnt
>= retries
) {
389 sleep((u_int
)((cnt
- backoff
) * 5));
393 /* committed to login -- turn off timeout */
394 (void)alarm((u_int
)0);
395 (void)signal(SIGHUP
, SIG_DFL
);
400 * Establish the login class.
402 lc
= login_getpwclass(pwd
);
404 /* if user not super-user, check for disabled logins */
406 auth_checknologin(lc
);
408 quietlog
= login_getcapbool(lc
, "hushlogin", 0);
409 /* Switching needed for NFS with root access disabled */
410 (void)setegid(pwd
->pw_gid
);
411 (void)seteuid(rootlogin
? 0 : pwd
->pw_uid
);
412 if (!*pwd
->pw_dir
|| chdir(pwd
->pw_dir
) < 0) {
413 if (login_getcapbool(lc
, "requirehome", 0))
414 refused("Home directory not available", "HOMEDIR", 1);
416 refused("Cannot find root directory", "ROOTDIR", 1);
417 if (!quietlog
|| *pwd
->pw_dir
)
418 printf("No home directory.\nLogging in with home = \"/\".\n");
424 quietlog
= access(_PATH_HUSHLOGIN
, F_OK
) == 0;
426 if (pwd
->pw_change
|| pwd
->pw_expire
)
427 (void)gettimeofday(&tp
, (struct timezone
*)NULL
);
429 #define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
431 warntime
= login_getcaptime(lc
, "warnexpire", DEFAULT_WARN
,
434 if (pwd
->pw_expire
) {
435 if (tp
.tv_sec
>= pwd
->pw_expire
) {
436 refused("Sorry -- your account has expired", "EXPIRED",
438 } else if (pwd
->pw_expire
- tp
.tv_sec
< warntime
&& !quietlog
)
439 (void)printf("Warning: your account expires on %s",
440 ctime(&pwd
->pw_expire
));
443 warntime
= login_getcaptime(lc
, "warnpassword", DEFAULT_WARN
,
447 if (pwd
->pw_change
) {
448 if (tp
.tv_sec
>= pwd
->pw_change
) {
449 (void)printf("Sorry -- your password has expired.\n");
451 syslog(LOG_INFO
, "%s Password expired - forcing change",
453 } else if (pwd
->pw_change
- tp
.tv_sec
< warntime
&& !quietlog
)
454 (void)printf("Warning: your password expires on %s",
455 ctime(&pwd
->pw_change
));
460 struct addrinfo hints
, *res
;
463 memset(&hints
, 0, sizeof(hints
));
464 hints
.ai_family
= AF_UNSPEC
;
465 ga_err
= getaddrinfo(full_hostname
, NULL
, &hints
,
468 char hostbuf
[MAXHOSTNAMELEN
];
470 getnameinfo(res
->ai_addr
, res
->ai_addrlen
,
471 hostbuf
, sizeof(hostbuf
), NULL
, 0,
472 NI_NUMERICHOST
|NI_WITHSCOPEID
);
473 if ((optarg
= strdup(hostbuf
)) == NULL
) {
474 syslog(LOG_NOTICE
, "strdup(): %m");
481 if (!auth_hostok(lc
, full_hostname
, optarg
))
482 refused("Permission denied", "HOST", 1);
485 if (!auth_ttyok(lc
, tty
))
486 refused("Permission denied", "TTY", 1);
488 if (!auth_timeok(lc
, time(NULL
)))
489 refused("Logins not available right now", "TIME", 1);
491 shell
= login_getcapstr(lc
, "shell", pwd
->pw_shell
, pwd
->pw_shell
);
492 if (*pwd
->pw_shell
== '\0')
493 pwd
->pw_shell
= _PATH_BSHELL
;
494 if (*shell
== '\0') /* Not overridden */
495 shell
= pwd
->pw_shell
;
496 if ((shell
= strdup(shell
)) == NULL
) {
497 syslog(LOG_NOTICE
, "strdup(): %m");
502 if (login_access(pwd
->pw_name
, hostname
? full_hostname
: tty
) == 0)
503 refused("Permission denied", "ACCESS", 1);
504 #endif /* LOGIN_ACCESS */
506 /* Nothing else left to fail -- really log in. */
507 memset((void *)&utmp
, 0, sizeof(utmp
));
508 (void)time(&utmp
.ut_time
);
509 (void)strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
511 (void)strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
512 (void)strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
518 * Set device protections, depending on what terminal the
519 * user is logged in. This feature is used on Suns to give
520 * console users better privacy.
522 login_fbtab(tty
, pwd
->pw_uid
, pwd
->pw_gid
);
525 * Clear flags of the tty. None should be set, and when the
526 * user sets them otherwise, this can cause the chown to fail.
527 * Since it isn't clear that flags are useful on character
528 * devices, we just clear them.
530 if (ttyn
!= tname
&& chflags(ttyn
, 0) && errno
!= EOPNOTSUPP
)
531 syslog(LOG_ERR
, "chflags(%s): %m", ttyn
);
532 if (ttyn
!= tname
&& chown(ttyn
, pwd
->pw_uid
,
533 (gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
))
534 syslog(LOG_ERR
, "chmod(%s): %m", ttyn
);
538 * Preserve TERM if it happens to be already set.
540 if ((term
= getenv("TERM")) != NULL
) {
541 if ((term
= strdup(term
)) == NULL
) {
549 * Exclude cons/vt/ptys only, assume dialup otherwise
550 * TODO: Make dialup tty determination a library call
551 * for consistency (finger etc.)
553 if (hostname
==NULL
&& isdialuptty(tty
))
554 syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
558 * Syslog each successful login, so we don't have to watch hundreds
559 * of wtmp or lastlogin files.
562 syslog(LOG_INFO
, "login from %s on %s as %s",
563 full_hostname
, tty
, pwd
->pw_name
);
565 syslog(LOG_INFO
, "login on %s as %s",
570 * If fflag is on, assume caller/authenticator has logged root login.
572 if (rootlogin
&& fflag
== 0)
575 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s FROM %s",
576 username
, tty
, full_hostname
);
578 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s",
583 * Destroy environment unless user has requested its preservation.
584 * We need to do this before setusercontext() because that may
585 * set or reset some environment variables.
591 * PAM modules might add supplementary groups during pam_setcred().
593 if (setusercontext(lc
, pwd
, pwd
->pw_uid
, LOGIN_SETGROUP
) != 0) {
594 syslog(LOG_ERR
, "setusercontext() failed - exiting");
600 if ((e
= pam_open_session(pamh
, 0)) != PAM_SUCCESS
) {
601 syslog(LOG_ERR
, "pam_open_session: %s",
602 pam_strerror(pamh
, e
));
603 } else if ((e
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
))
605 syslog(LOG_ERR
, "pam_setcred: %s",
606 pam_strerror(pamh
, e
));
610 * Add any environmental variables that the
611 * PAM modules may have set.
612 * Call *after* opening session!
615 environ_pam
= pam_getenvlist(pamh
);
617 export_pam_environment();
621 * We must fork() before setuid() because we need to call
622 * pam_close_session() as root.
630 /* parent - wait for child to finish, then cleanup
632 setproctitle("-%s [pam]", getprogname());
637 if ((e
= pam_end(pamh
, PAM_DATA_SILENT
)) != PAM_SUCCESS
)
638 syslog(LOG_ERR
, "pam_end: %s",
639 pam_strerror(pamh
, e
));
645 * We don't need to be root anymore, so
646 * set the user and session context
648 if (setlogin(username
) != 0) {
649 syslog(LOG_ERR
, "setlogin(%s): %m - exiting", username
);
652 if (setusercontext(lc
, pwd
, pwd
->pw_uid
,
653 LOGIN_SETALL
& ~(LOGIN_SETLOGIN
|LOGIN_SETGROUP
)) != 0) {
654 syslog(LOG_ERR
, "setusercontext() failed - exiting");
658 (void)setenv("SHELL", pwd
->pw_shell
, 1);
659 (void)setenv("HOME", pwd
->pw_dir
, 1);
660 if (term
!= NULL
&& *term
!= '\0')
661 (void)setenv("TERM", term
, 1); /* Preset overrides */
663 (void)setenv("TERM", stypeof(tty
), 0); /* Fallback doesn't */
665 (void)setenv("LOGNAME", username
, 1);
666 (void)setenv("USER", username
, 1);
667 (void)setenv("PATH", rootlogin
? _PATH_STDPATH
: _PATH_DEFPATH
, 0);
672 cw
= login_getcapstr(lc
, "copyright", NULL
, NULL
);
673 if (cw
!= NULL
&& access(cw
, F_OK
) == 0)
676 (void)printf("%s\n\t%s %s\n",
677 "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
678 "The Regents of the University of California. ",
679 "All rights reserved.");
683 cw
= login_getcapstr(lc
, "welcome", NULL
, NULL
);
684 if (cw
== NULL
|| access(cw
, F_OK
) != 0)
688 cw
= getenv("MAIL"); /* $MAIL may have been set by class */
690 strlcpy(tbuf
, cw
, sizeof(tbuf
));
692 snprintf(tbuf
, sizeof(tbuf
), "%s/%s", _PATH_MAILDIR
,
694 if (stat(tbuf
, &st
) == 0 && st
.st_size
!= 0)
695 (void)printf("You have %smail.\n",
696 (st
.st_mtime
> st
.st_atime
) ? "new " : "");
701 (void)signal(SIGALRM
, SIG_DFL
);
702 (void)signal(SIGQUIT
, SIG_DFL
);
703 (void)signal(SIGINT
, SIG_DFL
);
704 (void)signal(SIGTSTP
, SIG_IGN
);
707 if (system(_PATH_CHPASS
) != 0)
712 * Login shells have a leading '-' in front of argv[0]
714 if (snprintf(tbuf
, sizeof(tbuf
), "-%s",
715 (p
= strrchr(pwd
->pw_shell
, '/')) ? p
+ 1 : pwd
->pw_shell
) >=
717 syslog(LOG_ERR
, "user: %s: shell exceeds maximum pathname size",
719 errx(1, "shell exceeds maximum pathname size");
722 execlp(shell
, tbuf
, (char *)0);
727 auth_traditional(void)
735 salt
= pwd
!= NULL
? pwd
->pw_passwd
: "xx";
737 p
= getpass(passwd_prompt
);
741 if (!p
[0] && pwd
->pw_passwd
[0])
743 if (strcmp(ep
, pwd
->pw_passwd
) == 0)
747 /* clear entered password */
748 memset(p
, 0, strlen(p
));
754 * Attempt to authenticate the user using PAM. Returns 0 if the user is
755 * authenticated, or 1 if not authenticated. If some sort of PAM system
756 * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
757 * function returns -1. This can be used as an indication that we should
758 * fall back to a different authentication mechanism.
763 const char *tmpl_user
;
767 static struct pam_conv conv
= { misc_conv
, NULL
};
769 if ((e
= pam_start("login", username
, &conv
, &pamh
)) != PAM_SUCCESS
) {
770 syslog(LOG_ERR
, "pam_start: %s", pam_strerror(pamh
, e
));
773 if ((e
= pam_set_item(pamh
, PAM_TTY
, tty
)) != PAM_SUCCESS
) {
774 syslog(LOG_ERR
, "pam_set_item(PAM_TTY): %s",
775 pam_strerror(pamh
, e
));
778 if (hostname
!= NULL
&&
779 (e
= pam_set_item(pamh
, PAM_RHOST
, full_hostname
)) != PAM_SUCCESS
) {
780 syslog(LOG_ERR
, "pam_set_item(PAM_RHOST): %s",
781 pam_strerror(pamh
, e
));
784 e
= pam_authenticate(pamh
, 0);
789 * With PAM we support the concept of a "template"
790 * user. The user enters a login name which is
791 * authenticated by PAM, usually via a remote service
792 * such as RADIUS or TACACS+. If authentication
793 * succeeds, a different but related "template" name
794 * is used for setting the credentials, shell, and
795 * home directory. The name the user enters need only
796 * exist on the remote authentication server, but the
797 * template name must be present in the local password
800 * This is supported by two various mechanisms in the
801 * individual modules. However, from the application's
802 * point of view, the template user is always passed
803 * back as a changed value of the PAM_USER item.
805 if ((e
= pam_get_item(pamh
, PAM_USER
, &item
)) ==
807 tmpl_user
= (const char *) item
;
808 if (strcmp(username
, tmpl_user
) != 0)
809 pwd
= getpwnam(tmpl_user
);
811 syslog(LOG_ERR
, "Couldn't get PAM_USER: %s",
812 pam_strerror(pamh
, e
));
817 case PAM_USER_UNKNOWN
:
823 syslog(LOG_ERR
, "pam_authenticate: %s", pam_strerror(pamh
, e
));
829 e
= pam_acct_mgmt(pamh
, 0);
830 if (e
== PAM_NEW_AUTHTOK_REQD
) {
831 e
= pam_chauthtok(pamh
, PAM_CHANGE_EXPIRED_AUTHTOK
);
832 if (e
!= PAM_SUCCESS
) {
833 syslog(LOG_ERR
, "pam_chauthtok: %s",
834 pam_strerror(pamh
, e
));
837 } else if (e
!= PAM_SUCCESS
) {
843 if ((e
= pam_end(pamh
, e
)) != PAM_SUCCESS
) {
844 syslog(LOG_ERR
, "pam_end: %s", pam_strerror(pamh
, e
));
852 export_pam_environment(void)
856 for (pp
= environ_pam
; *pp
!= NULL
; pp
++) {
857 if (ok_to_export(*pp
))
865 * Sanity checks on PAM environmental variables:
866 * - Make sure there is an '=' in the string.
867 * - Make sure the string doesn't run on too long.
868 * - Do not export certain variables. This list was taken from the
869 * Solaris pam_putenv(3) man page.
872 ok_to_export(const char *s
)
874 static const char *noexport
[] = {
875 "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
881 if (strlen(s
) > 1024 || strchr(s
, '=') == NULL
)
883 if (strncmp(s
, "LD_", 3) == 0)
885 for (pp
= noexport
; *pp
!= NULL
; pp
++) {
887 if (s
[n
] == '=' && strncmp(s
, *pp
, n
) == 0)
898 (void)fprintf(stderr
, "usage: login [-fp] [-h hostname] [username]\n");
903 * Allow for authentication style and/or kerberos instance
906 #define NBUFSIZ UT_NAMESIZE + 64
913 static char nbuf
[NBUFSIZ
];
916 (void)printf("%s", prompt
);
917 for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
922 if (p
< nbuf
+ (NBUFSIZ
- 1))
927 (void)fprintf(stderr
,
928 "login names may not start with '-'.\n");
943 return ((t
= getttynam(ttyn
)) && t
->ty_status
& TTY_SECURE
);
946 volatile int motdinterrupt
;
949 sigint(int signo __unused
)
961 if ((fd
= open(motdfile
, O_RDONLY
, 0)) < 0)
964 oldint
= signal(SIGINT
, sigint
);
965 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0 && !motdinterrupt
)
966 (void)write(fileno(stdout
), tbuf
, nchars
);
967 (void)signal(SIGINT
, oldint
);
976 longjmp(timeout_buf
, signo
);
986 if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
987 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
989 if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
991 (void)printf("Last login: %.*s ",
992 24-5, (char *)ctime(&ll
.ll_time
));
993 if (*ll
.ll_host
!= '\0')
994 (void)printf("from %.*s\n",
995 (int)sizeof(ll
.ll_host
),
998 (void)printf("on %.*s\n",
999 (int)sizeof(ll
.ll_line
),
1002 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
1004 memset((void *)&ll
, 0, sizeof(ll
));
1005 (void)time(&ll
.ll_time
);
1006 (void)strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
1008 (void)strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
1009 (void)write(fd
, (char *)&ll
, sizeof(ll
));
1012 syslog(LOG_ERR
, "cannot open %s: %m", _PATH_LASTLOG
);
1017 badlogin(char *name
)
1023 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s FROM %s",
1024 failures
, failures
> 1 ? "S" : "", full_hostname
);
1025 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
1026 "%d LOGIN FAILURE%s FROM %s, %s",
1027 failures
, failures
> 1 ? "S" : "", full_hostname
, name
);
1029 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s ON %s",
1030 failures
, failures
> 1 ? "S" : "", tty
);
1031 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
1032 "%d LOGIN FAILURE%s ON %s, %s",
1033 failures
, failures
> 1 ? "S" : "", tty
, name
);
1039 #define UNKNOWN "su"
1042 stypeof(char *ttyid
)
1046 if (ttyid
!= NULL
&& *ttyid
!= '\0') {
1047 t
= getttynam(ttyid
);
1048 if (t
!= NULL
&& t
->ty_type
!= NULL
)
1049 return (t
->ty_type
);
1055 refused(char *msg
, char *rtype
, int lout
)
1059 printf("%s.\n", msg
);
1061 syslog(LOG_NOTICE
, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
1062 pwd
->pw_name
, rtype
, full_hostname
, tty
);
1064 syslog(LOG_NOTICE
, "LOGIN %s REFUSED (%s) ON TTY %s",
1065 pwd
->pw_name
, rtype
, tty
);