2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char copyright
[] =
59 "@(#) Copyright (c) Apple Computer, Inc. 1997\n\n";
64 * login -h hostname (for telnetd, etc.)
65 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
68 #include <sys/param.h>
71 #include <sys/resource.h>
90 #include <sys/types.h>
91 #include <sys/socket.h>
92 #include <netinet/in.h>
93 #include <arpa/inet.h>
96 #include <bsm/libbsm.h>
97 #include <bsm/audit_uevents.h>
100 #include <pam/pam_appl.h>
101 #include <pam/pam_misc.h>
104 #include "pathnames.h"
106 void badlogin
__P((char *));
107 void checknologin
__P((void));
108 void dolastlog
__P((int));
109 void getloginname
__P((void));
110 void motd
__P((void));
111 int rootterm
__P((char *));
112 void sigint
__P((int));
113 void sleepexit
__P((int));
114 char *stypeof
__P((char *));
115 void timedout
__P((int));
117 int klogin
__P((struct passwd
*, char *, char *, char *));
120 void au_fail(char *, int);
123 extern void login
__P((struct utmp
*));
125 #define TTYGRPNAME "tty" /* name of group to own ttys */
128 * This bounds the time given to login. Not a define so it can
129 * be patched on machines where it's too small.
142 char term
[64], *hostname
, *username
= NULL
, *tty
;
144 #define NA_EVENT_STR_SIZE 25
152 extern char **environ
;
157 int ask
, ch
, cnt
, oflag
= 0, fflag
, hflag
, pflag
, quietlog
, rootlogin
= 0, rval
;
161 char *domain
, *p
, *salt
, *ttyn
;
162 char tbuf
[MAXPATHLEN
+ 2], tname
[sizeof(_PATH_TTY
) + 10];
163 char localhost
[MAXHOSTNAMELEN
];
165 pam_handle_t
*pamh
= NULL
;
166 struct pam_conv conv
= { misc_conv
, NULL
};
171 char auditsuccess
= 1;
173 (void)signal(SIGALRM
, timedout
);
174 (void)alarm(timeout
);
175 (void)signal(SIGQUIT
, SIG_IGN
);
176 (void)signal(SIGINT
, SIG_IGN
);
177 (void)setpriority(PRIO_PROCESS
, 0, 0);
179 openlog("login", LOG_ODELAY
, LOG_AUTH
);
183 * -p is used by getty to tell login not to destroy the environment
184 * -f is used to skip a second login authentication
185 * -h is used by other servers to pass the name of the remote
186 * host to login so that it may be placed in utmp and wtmp
189 if (gethostname(localhost
, sizeof(localhost
)) < 0)
190 syslog(LOG_ERR
, "couldn't get local hostname: %m");
192 domain
= strchr(localhost
, '.');
197 fflag
= hflag
= pflag
= 0;
199 while ((ch
= getopt(argc
, argv
, "1fh:p")) != EOF
)
209 errx(1, "-h option: %s", strerror(EPERM
));
211 if (domain
&& (p
= strchr(optarg
, '.')) &&
212 strcasecmp(p
, domain
) == 0)
222 syslog(LOG_ERR
, "invalid flag %c", ch
);
223 (void)fprintf(stderr
,
224 "usage: login [-fp] [-h hostname] [username]\n");
236 for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
239 ttyn
= ttyname(STDIN_FILENO
);
240 if (ttyn
== NULL
|| *ttyn
== '\0') {
241 (void)snprintf(tname
, sizeof(tname
), "%s??", _PATH_TTY
);
244 if (tty
= strrchr(ttyn
, '/'))
249 /* Set the terminal id */
250 audit_set_terminal_id(&tid
);
251 if (fstat(STDIN_FILENO
, &st
) < 0) {
252 fprintf(stderr
, "login: Unable to stat terminal\n");
253 au_fail("Unable to stat terminal", 1);
256 if (S_ISCHR(st
.st_mode
)) {
257 tid
.port
= st
.st_rdev
;
263 rval
= pam_start("login", username
, &conv
, &pamh
);
264 if( rval
!= PAM_SUCCESS
) {
265 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
266 au_fail("PAM Error", 1);
269 rval
= pam_set_item(pamh
, PAM_TTY
, tty
);
270 if( rval
!= PAM_SUCCESS
) {
271 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
272 au_fail("PAM Error", 1);
276 rval
= pam_set_item(pamh
, PAM_RHOST
, hostname
);
277 if( rval
!= PAM_SUCCESS
) {
278 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
279 au_fail("PAM Error", 1);
283 rval
= pam_set_item(pamh
, PAM_USER_PROMPT
, "login: ");
284 if( rval
!= PAM_SUCCESS
) {
285 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
286 au_fail("PAM Error", 1);
292 pam_set_item(pamh
, PAM_USER
, username
);
293 pwd
= getpwnam(username
);
294 if( (pwd
!= NULL
) && (pwd
->pw_uid
== 0) )
297 if( (pwd
!= NULL
) && fflag
&& ((uid
== 0) || (uid
== pwd
->pw_uid
)) ){
299 auditsuccess
= 0; /* we've simply opened a terminal window */
302 rval
= pam_authenticate(pamh
, 0);
303 while( (!oflag
) && (cnt
++ < 10) && ((rval
== PAM_AUTH_ERR
) ||
304 (rval
== PAM_USER_UNKNOWN
) ||
305 (rval
== PAM_CRED_INSUFFICIENT
) ||
306 (rval
== PAM_AUTHINFO_UNAVAIL
))) {
308 * we are not exiting here, but this corresponds to
309 * a failed login event, so set exitstatus to 1
311 au_fail("Login incorrect", 1);
313 printf("Login incorrect\n");
316 pwd
= getpwnam(username
);
317 if( (pwd
!= NULL
) && (pwd
->pw_uid
== 0) )
319 pam_set_item(pamh
, PAM_USER
, username
);
320 rval
= pam_authenticate(pamh
, 0);
323 if( rval
!= PAM_SUCCESS
) {
324 pam_get_item(pamh
, PAM_USER
, (void *)&username
);
326 printf("Login incorrect\n");
327 au_fail("Login incorrect", 1);
331 rval
= pam_acct_mgmt(pamh
, 0);
332 if( rval
== PAM_NEW_AUTHTOK_REQD
) {
333 rval
= pam_chauthtok(pamh
, PAM_CHANGE_EXPIRED_AUTHTOK
);
335 if( rval
!= PAM_SUCCESS
) {
336 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
337 au_fail("PAM error", 1);
343 rval
= pam_get_item(pamh
, PAM_USER
, (void *)&username
);
344 if( (rval
== PAM_SUCCESS
) && username
&& *username
)
345 pwd
= getpwnam(username
);
347 rval
= pam_open_session(pamh
, 0);
348 if( rval
!= PAM_SUCCESS
) {
349 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
350 au_fail("PAM error", 1);
354 rval
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
);
355 if( rval
!= PAM_SUCCESS
) {
356 fprintf(stderr
, "login: PAM Error: %s\n", pam_strerror(pamh
, rval
));
357 au_fail("PAM error", 1);
362 for (cnt
= 0;; ask
= 1) {
369 if ((instance
= strchr(username
, '.')) != NULL
) {
370 if (strncmp(instance
, ".root", 5) == 0)
376 if (strlen(username
) > UT_NAMESIZE
)
377 username
[UT_NAMESIZE
] = '\0';
380 * Note if trying multiple user names; log failures for
381 * previous user name, but don't bother logging one failure
382 * for nonexistent name (mistyped username).
384 if (failures
&& strcmp(tbuf
, username
)) {
385 if (failures
> (pwd
? 0 : 1)) {
390 (void)strcpy(tbuf
, username
);
392 if (pwd
= getpwnam(username
))
393 salt
= pwd
->pw_passwd
;
398 * if we have a valid account name, and it doesn't have a
399 * password, or the -f option was specified and the caller
400 * is root or the caller isn't changing their uid, don't
403 if (pwd
&& (*pwd
->pw_passwd
== '\0' ||
404 fflag
&& (uid
== 0 || uid
== pwd
->pw_uid
)))
407 if (pwd
&& pwd
->pw_uid
== 0)
410 (void)setpriority(PRIO_PROCESS
, 0, -4);
412 p
= getpass("Password:");
416 rval
= klogin(pwd
, instance
, localhost
, p
);
417 if (rval
!= 0 && rootlogin
&& pwd
->pw_uid
!= 0)
422 rval
= strcmp(crypt(p
, salt
), pwd
->pw_passwd
);
424 rval
= strcmp(crypt(p
, salt
), pwd
->pw_passwd
);
427 memset(p
, 0, strlen(p
));
429 (void)setpriority(PRIO_PROCESS
, 0, 0);
432 * If trying to log in as root without Kerberos,
433 * but with insecure terminal, refuse the login attempt.
438 if (pwd
&& rootlogin
&& !rootterm(tty
)) {
439 (void)fprintf(stderr
,
440 "%s login refused on this terminal.\n",
444 "LOGIN %s REFUSED FROM %s ON TTY %s",
445 pwd
->pw_name
, hostname
, tty
);
448 "LOGIN %s REFUSED ON TTY %s",
450 au_fail("Login refused on terminal", 0);
457 (void)printf("Login incorrect\n");
459 /* we allow 10 tries, but after 3 we start backing off */
463 au_fail("Login incorrect", 1);
466 au_fail("Login incorrect", 1);
467 sleep((u_int
)((cnt
- 3) * 5));
472 /* committed to login -- turn off timeout */
473 (void)alarm((u_int
)0);
477 /* if user not super-user, check for disabled logins */
481 /* Audit successful login */
485 setegid(pwd
->pw_gid
);
486 seteuid(rootlogin
? 0 : pwd
->pw_uid
);
488 /* First do a stat in case the homedir is automounted */
489 stat(pwd
->pw_dir
,&st
);
491 if (chdir(pwd
->pw_dir
) < 0) {
492 (void)printf("No home directory %s!\n", pwd
->pw_dir
);
497 (void)printf("Logging in with home = \"/\".\n");
503 quietlog
= access(_PATH_HUSHLOGIN
, F_OK
) == 0;
505 /* 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
));
517 (void)chown(ttyn
, pwd
->pw_uid
,
518 (gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
);
519 (void)chmod(ttyn
, 0620);
520 (void)setgid(pwd
->pw_gid
);
522 initgroups(username
, pwd
->pw_gid
);
524 if (*pwd
->pw_shell
== '\0')
525 pwd
->pw_shell
= _PATH_BSHELL
;
527 /* Destroy environment unless user has requested its preservation. */
529 environ
= malloc(sizeof(char *));
532 (void)setenv("HOME", pwd
->pw_dir
, 1);
533 (void)setenv("SHELL", pwd
->pw_shell
, 1);
535 (void)strncpy(term
, stypeof(tty
), sizeof(term
));
536 (void)setenv("TERM", term
, 0);
537 (void)setenv("LOGNAME", pwd
->pw_name
, 1);
538 (void)setenv("USER", pwd
->pw_name
, 1);
539 (void)setenv("PATH", _PATH_DEFPATH
, 0);
542 (void)setenv("KRBTKFILE", krbtkfile_env
, 1);
546 pmenv
= pam_getenvlist(pamh
);
547 for( cnt
= 0; pmenv
&& pmenv
[cnt
]; cnt
++ )
553 } else if( pid
!= 0 ) {
554 waitpid(pid
, NULL
, 0);
555 pam_setcred(pamh
, PAM_DELETE_CRED
);
556 rval
= pam_close_session(pamh
, 0);
563 if (tty
[sizeof("tty")-1] == 'd')
564 syslog(LOG_INFO
, "DIALUP %s, %s", tty
, pwd
->pw_name
);
566 /* If fflag is on, assume caller/authenticator has logged root login. */
567 if (rootlogin
&& fflag
== 0)
569 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s FROM %s",
570 username
, tty
, hostname
);
572 syslog(LOG_NOTICE
, "ROOT LOGIN (%s) ON %s", username
, tty
);
575 if (!quietlog
&& notickets
== 1)
576 (void)printf("Warning: no Kerberos tickets issued.\n");
582 sizeof(tbuf
), "%s/%s", _PATH_MAILDIR
, pwd
->pw_name
);
583 if (stat(tbuf
, &st
) == 0 && st
.st_size
!= 0)
584 (void)printf("You have %smail.\n",
585 (st
.st_mtime
> st
.st_atime
) ? "new " : "");
588 (void)signal(SIGALRM
, SIG_DFL
);
589 (void)signal(SIGQUIT
, SIG_DFL
);
590 (void)signal(SIGINT
, SIG_DFL
);
591 (void)signal(SIGTSTP
, SIG_IGN
);
594 (void)strcpy(tbuf
+ 1, (p
= strrchr(pwd
->pw_shell
, '/')) ?
595 p
+ 1 : pwd
->pw_shell
);
597 if (setlogin(pwd
->pw_name
) < 0)
598 syslog(LOG_ERR
, "setlogin() failure: %m");
600 /* Discard permissions last so can't get killed and drop core. */
604 (void) setuid(pwd
->pw_uid
);
607 execlp(pwd
->pw_shell
, tbuf
, 0);
608 err(1, "%s", pwd
->pw_shell
);
612 #define NBUFSIZ (MAXLOGNAME + 1 + 5) /* .root suffix */
614 #define NBUFSIZ (MAXLOGNAME + 1)
618 * The following tokens are included in the audit record for successful login attempts
629 uid_t uid
= pwd
->pw_uid
;
630 gid_t gid
= pwd
->pw_gid
;
631 pid_t pid
= getpid();
634 /* If we are not auditing, don't cut an audit record; just return */
635 if (auditon(A_GETCOND
, &au_cond
, sizeof(long)) < 0) {
636 fprintf(stderr
, "login: Could not determine audit condition\n");
639 if (au_cond
== AUC_NOAUDIT
)
642 /* Compute and Set the user's preselection mask */
643 if(au_user_mask(pwd
->pw_name
, &aumask
) == -1) {
644 fprintf(stderr
, "login: Could not set audit mask\n");
648 /* Set the audit info for the user */
649 auinfo
.ai_auid
= uid
;
650 auinfo
.ai_asid
= pid
;
651 bcopy(&tid
, &auinfo
.ai_termid
, sizeof(auinfo
.ai_termid
));
652 bcopy(&aumask
, &auinfo
.ai_mask
, sizeof(auinfo
.ai_mask
));
653 if(setaudit(&auinfo
) != 0) {
654 fprintf(stderr
, "login: setaudit failed: %s\n", strerror(errno
));
658 if((aufd
= au_open()) == -1) {
659 fprintf(stderr
, "login: Audit Error: au_open() failed\n");
663 /* The subject that is created (euid, egid of the current process) */
664 if((tok
= au_to_subject32(uid
, geteuid(), getegid(),
665 uid
, gid
, pid
, pid
, &tid
)) == NULL
) {
666 fprintf(stderr
, "login: Audit Error: au_to_subject32() failed\n");
671 if((tok
= au_to_return32(0, 0)) == NULL
) {
672 fprintf(stderr
, "login: Audit Error: au_to_return32() failed\n");
677 if(au_close(aufd
, 1, AUE_login
) == -1) {
678 fprintf(stderr
, "login: Audit Record was not committed.\n");
684 * The following tokens are included in the audit record for successful login attempts
690 void au_fail(char *errmsg
, int na
)
697 pid_t pid
= getpid();
699 /* If we are not auditing, don't cut an audit record; just return */
700 if (auditon(A_GETCOND
, &au_cond
, sizeof(long)) < 0) {
701 fprintf(stderr
, "login: Could not determine audit condition\n");
704 if (au_cond
== AUC_NOAUDIT
)
707 if((aufd
= au_open()) == -1) {
708 fprintf(stderr
, "login: Audit Error: au_open() failed\n");
713 /* Non attributable event */
714 /* Assuming that login is not called within a users' session => auid,asid == -1 */
715 if((tok
= au_to_subject32(-1, geteuid(), getegid(), -1, -1,
716 pid
, -1, &tid
)) == NULL
) {
718 fprintf(stderr
, "login: Audit Error: au_to_subject32() failed\n");
723 /* we know the subject -- so use its value instead */
726 if((tok
= au_to_subject32(uid
, geteuid(), getegid(),
727 uid
, gid
, pid
, pid
, &tid
)) == NULL
) {
728 fprintf(stderr
, "login: Audit Error: au_to_subject32() failed\n");
734 /* Include the error message */
735 if((tok
= au_to_text(errmsg
)) == NULL
) {
736 fprintf(stderr
, "login: Audit Error: au_to_text() failed\n");
741 if((tok
= au_to_return32(1, errno
)) == NULL
) {
742 fprintf(stderr
, "login: Audit Error: au_to_return32() failed\n");
747 if(au_close(aufd
, 1, AUE_login
) == -1) {
748 fprintf(stderr
, "login: Audit Error: au_close() was not committed\n");
758 static char nbuf
[NBUFSIZ
];
761 (void)printf("login: ");
762 for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
767 if (p
< nbuf
+ (NBUFSIZ
- 1))
772 (void)fprintf(stderr
,
773 "login names may not start with '-'.\n");
789 return ((t
= getttynam(ttyn
)) && t
->ty_status
& TTY_SECURE
);
792 jmp_buf motdinterrupt
;
801 if ((fd
= open(_PATH_MOTDFILE
, O_RDONLY
, 0)) < 0)
803 oldint
= signal(SIGINT
, sigint
);
804 if (setjmp(motdinterrupt
) == 0)
805 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
806 (void)write(fileno(stdout
), tbuf
, nchars
);
807 (void)signal(SIGINT
, oldint
);
817 longjmp(motdinterrupt
, 1);
826 (void)fprintf(stderr
, "Login timed out after %d seconds\n", timeout
);
836 if ((fd
= open(_PATH_NOLOGIN
, O_RDONLY
, 0)) >= 0) {
837 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
838 (void)write(fileno(stdout
), tbuf
, nchars
);
840 au_fail("No login", 0);
852 /* HACK HACK HACK: This is because HFS doesn't support sparse files
853 * and seeking into the file too far is too slow. The "solution"
854 * is to just bail if the seek time for a large uid would be too
857 if(pwd
->pw_uid
> 100000) {
858 syslog(LOG_NOTICE
, "User login %s (%d) not logged in lastlog. UID too large.", pwd
->pw_name
, pwd
->pw_uid
);
862 if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
863 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
865 if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
867 (void)printf("Last login: %.*s ",
868 24-5, (char *)ctime(&ll
.ll_time
));
869 if (*ll
.ll_host
!= '\0')
870 (void)printf("from %.*s\n",
871 (int)sizeof(ll
.ll_host
),
874 (void)printf("on %.*s\n",
875 (int)sizeof(ll
.ll_line
),
878 (void)lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), L_SET
);
880 memset((void *)&ll
, 0, sizeof(ll
));
881 (void)time(&ll
.ll_time
);
882 (void)strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
884 (void)strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
885 (void)write(fd
, (char *)&ll
, sizeof(ll
));
898 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s FROM %s",
899 failures
, failures
> 1 ? "S" : "", hostname
);
900 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
901 "%d LOGIN FAILURE%s FROM %s, %s",
902 failures
, failures
> 1 ? "S" : "", hostname
, name
);
904 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s ON %s",
905 failures
, failures
> 1 ? "S" : "", tty
);
906 syslog(LOG_AUTHPRIV
|LOG_NOTICE
,
907 "%d LOGIN FAILURE%s ON %s, %s",
908 failures
, failures
> 1 ? "S" : "", tty
, name
);
921 return (ttyid
&& (t
= getttynam(ttyid
)) ? t
->ty_type
: UNKNOWN
);