1 /* This program is derived from 4.3 BSD software and is
2 subject to the copyright notice below.
4 The port to HP-UX has been motivated by the incapability
5 of 'rlogin'/'rlogind' as per HP-UX 6.5 (and 7.0) to transfer window sizes.
9 - General HP-UX portation. Use of facilities not available
10 in HP-UX (e.g. setpriority) has been eliminated.
11 Utmp/wtmp handling has been ported.
13 - The program uses BSD command line options to be used
14 in connection with e.g. 'rlogind' i.e. 'new login'.
16 - HP features left out: logging of bad login attempts in /etc/btmp,
17 they are sent to syslog
21 '*' as login shell, add it if you need it
23 - BSD features left out: quota checks
25 analysis of terminal type (tset feature)
27 - BSD features thrown in: Security logging to syslogd.
28 This requires you to have a (ported) syslog
29 system -- 7.0 comes with syslog
33 - A lot of nitty gritty details has been adjusted in favour of
34 HP-UX, e.g. /etc/securetty, default paths and the environment
35 variables assigned by 'login'.
37 - We do *nothing* to setup/alter tty state, under HP-UX this is
38 to be done by getty/rlogind/telnetd/some one else.
40 Michael Glad (glad@daimi.dk)
41 Computer Science Department
47 1991-09-24 glad@daimi.aau.dk: HP-UX 8.0 port:
48 - now explictly sets non-blocking mode on descriptors
49 - strcasecmp is now part of HP-UX
51 1992-02-05 poe@daimi.aau.dk: Ported the stuff to Linux 0.12
52 From 1992 till now (1997) this code for Linux has been maintained at
53 ftp.daimi.aau.dk:/pub/linux/poe/
55 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
56 - added Native Language Support
57 Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
58 - fixed strerr(errno) in gettext calls
62 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
63 * All rights reserved.
65 * Redistribution and use in source and binary forms are permitted
66 * provided that the above copyright notice and this paragraph are
67 * duplicated in all such forms and that any documentation,
68 * advertising materials, and other materials related to such
69 * distribution and use acknowledge that the software was developed
70 * by the University of California, Berkeley. The name of the
71 * University may not be used to endorse or promote products derived
72 * from this software without specific prior written permission.
73 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
74 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
75 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
80 * login -h hostname (for telnetd, etc.)
81 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
89 #include <sys/param.h>
100 #include <sys/resource.h>
101 #include <sys/file.h>
105 #define rindex strrchr
106 #include <sys/ioctl.h>
107 #include <sys/wait.h>
116 #include <sys/syslog.h>
117 #include <sys/sysmacros.h>
119 #include "my_crypt.h"
123 # include <sys/sysmacros.h>
124 # include <linux/major.h>
138 # include <security/pam_appl.h>
139 # include <security/pam_misc.h>
140 # define PAM_MAX_LOGIN_TRIES 3
141 # define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
142 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
143 syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \
144 pam_end(pamh, retcode); exit(1); \
146 # define PAM_END { retcode = pam_close_session(pamh,0); \
147 pam_end(pamh,retcode); }
155 #define SLEEP_EXIT_TIMEOUT 5
158 #define DO_PS_FIDDLING
161 #ifdef DO_PS_FIDDLING
162 #include "setproctitle.h"
166 /* from before we had a lastlog.h file in linux */
174 #include "pathnames.h"
177 void opentty
P_((const char *tty
));
178 void getloginname
P_((void));
179 void timedout
P_((void));
180 int rootterm
P_((char *ttyn
));
181 void motd
P_((void));
182 void sigint
P_((void));
183 void checknologin
P_((void));
184 void dolastlog
P_((int quiet
));
185 void badlogin
P_((const char *name
));
186 char *stypeof
P_((char *ttyid
));
187 void checktty
P_((char *user
, char *tty
, struct passwd
*pwd
));
188 void sleepexit
P_((int eval
));
190 int cryptocard
P_((void));
195 #include <kerberos/krb.h>
196 #include <sys/termios.h>
197 char realm
[REALM_SZ
];
198 int kerror
= KSUCCESS
, notickets
= 1;
202 # define TTY_MODE 0620
204 # define TTY_MODE 0600
207 #define TTYGRPNAME "tty" /* name of group to own ttys */
208 /**# define TTYGRPNAME "other" **/
211 # define MAXPATHLEN 1024
215 * This bounds the time given to login. Not a define so it can
216 * be patched on machines where it's too small.
226 char term
[64], *hostname
, *username
, *tty
;
227 struct hostent hostaddress
;
231 struct sgttyb sgttyb
;
233 CINTR
, CQUIT
, CSTART
, CSTOP
, CEOT
, CBRK
235 struct ltchars ltc
= {
236 CSUSP
, CDSUSP
, CRPRNT
, CFLUSH
, CWERASE
, CLNEXT
240 const char *months
[] =
241 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
242 "Sep", "Oct", "Nov", "Dec" };
244 /* provided by Linus Torvalds 16-Feb-93 */
246 opentty(const char * tty
)
249 int fd
= open(tty
, O_RDWR
);
251 for (i
= 0 ; i
< fd
; i
++)
253 for (i
= 0 ; i
< 3 ; i
++)
259 /* true if the filedescriptor fd is a console tty, very Linux specific */
266 if ((fstat(fd
, &stb
) >= 0)
267 && (major(stb
.st_rdev
) == TTY_MAJOR
)
268 && (minor(stb
.st_rdev
) < 64)) {
277 main(int argc
, char **argv
)
279 extern int errno
, optind
;
280 extern char *optarg
, **environ
;
284 int ask
, fflag
, hflag
, pflag
, cnt
, errsv
;
285 int quietlog
, passwd_req
;
287 char tbuf
[MAXPATHLEN
+ 2], tname
[sizeof(_PATH_TTY
) + 10];
288 char *ctime(), *ttyname(), *stypeof();
292 char vcsn
[20], vcsan
[20];
293 char * childArgv
[10];
298 pam_handle_t
*pamh
= NULL
;
299 struct pam_conv conv
= { misc_conv
, NULL
};
308 signal(SIGALRM
, timedout
);
309 alarm((unsigned int)timeout
);
310 signal(SIGQUIT
, SIG_IGN
);
311 signal(SIGINT
, SIG_IGN
);
313 setlocale(LC_ALL
, "");
314 bindtextdomain(PACKAGE
, LOCALEDIR
);
317 setpriority(PRIO_PROCESS
, 0, 0);
319 quota(Q_SETUID
, 0, 0, 0);
321 #ifdef DO_PS_FIDDLING
322 initproctitle(argc
, argv
);
326 * -p is used by getty to tell login not to destroy the environment
327 * -f is used to skip a second login authentication
328 * -h is used by other servers to pass the name of the remote
329 * host to login so that it may be placed in utmp and wtmp
331 gethostname(tbuf
, sizeof(tbuf
));
332 strncpy(thishost
, tbuf
, sizeof(thishost
)-1);
333 thishost
[sizeof(thishost
)-1] = 0;
334 domain
= index(tbuf
, '.');
336 username
= tty
= hostname
= NULL
;
337 fflag
= hflag
= pflag
= 0;
340 while ((ch
= getopt(argc
, argv
, "fh:p")) != EOF
)
349 _("login: -h for super-user only.\n"));
353 if (domain
&& (p
= index(optarg
, '.')) &&
354 strcasecmp(p
, domain
) == 0)
356 hostname
= strdup(optarg
); /* strdup: Ambrose C. Li */
358 struct hostent
*he
= gethostbyname(hostname
);
360 memcpy(&hostaddress
, he
, sizeof(hostaddress
));
362 memset(&hostaddress
, 0, sizeof(hostaddress
));
374 _("usage: login [-fp] [username]\n"));
381 username
= strdup(p
);
383 /* wipe name - some people mistype their password here */
384 /* (of course we are too late, but perhaps this helps a little ..) */
392 ioctl(0, TIOCLSET
, &ioctlval
);
393 ioctl(0, TIOCNXCL
, 0);
394 fcntl(0, F_SETFL
, ioctlval
);
395 ioctl(0, TIOCGETP
, &sgttyb
);
396 sgttyb
.sg_erase
= CERASE
;
397 sgttyb
.sg_kill
= CKILL
;
398 ioctl(0, TIOCSLTC
, <c
);
399 ioctl(0, TIOCSETC
, &tc
);
400 ioctl(0, TIOCSETP
, &sgttyb
);
403 * Be sure that we're in
405 * This is really for HPUX
408 ioctl(0, FIOSNBIO
, &ioctlval
);
409 #endif /* ! __linux__ */
411 for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
415 if (ttyn
== NULL
|| *ttyn
== '\0') {
416 /* no snprintf required - see definition of tname */
417 sprintf(tname
, "%s??", _PATH_TTY
);
421 /* find names of Virtual Console devices, for later mode change */
424 /* find number of tty */
425 while (*p
&& !isdigit(*p
)) p
++;
427 strcpy(vcsn
, "/dev/vcs"); strcat(vcsn
, p
);
428 strcpy(vcsan
, "/dev/vcsa"); strcat(vcsan
, p
);
434 struct termios tt
, ttt
;
438 ttt
.c_cflag
&= ~HUPCL
;
440 if((chown(ttyn
, 0, 0) == 0) && (chmod(ttyn
, 0622) == 0)) {
441 tcsetattr(0,TCSAFLUSH
,&ttt
);
442 signal(SIGHUP
, SIG_IGN
); /* so vhangup() wont kill us */
444 signal(SIGHUP
, SIG_DFL
);
449 /* re-open stdin,stdout,stderr after vhangup() closed them */
450 /* if it did, after 0.99.5 it doesn't! */
452 tcsetattr(0,TCSAFLUSH
,&tt
);
455 if ((tty
= rindex(ttyn
, '/')))
460 openlog("login", LOG_ODELAY
, LOG_AUTHPRIV
);
463 /* other than iso-8859-1 */
465 fprintf(stderr
,"\033(K");
469 /* username is initialized to NULL
470 and if specified on the command line it is set.
471 Therefore, we are safe not setting it to anything
474 retcode
= pam_start("login",username
, &conv
, &pamh
);
475 if(retcode
!= PAM_SUCCESS
) {
476 fprintf(stderr
,_("login: PAM Failure, aborting: %s\n"),
477 pam_strerror(pamh
, retcode
));
478 syslog(LOG_ERR
,_("Couldn't initialize PAM: %s"), pam_strerror(pamh
, retcode
));
481 /* hostname & tty are either set to NULL or their correct values,
482 depending on how much we know */
483 retcode
= pam_set_item(pamh
, PAM_RHOST
, hostname
);
485 retcode
= pam_set_item(pamh
, PAM_TTY
, tty
);
489 /* other than iso-8859-1
490 * one more time due to reset tty by PAM
493 fprintf(stderr
,"\033(K");
496 /* if fflag == 1, then the user has already been authenticated */
497 if (fflag
&& (getuid() == 0))
502 if(passwd_req
== 1) {
505 /* there may be better ways to deal with some of these
506 conditions, but at least this way I don't think we'll
507 be giving away information... */
508 /* Perhaps someday we can trust that all PAM modules will
509 pay attention to failure count and get rid of MAX_LOGIN_TRIES? */
511 retcode
= pam_authenticate(pamh
, 0);
512 while((failcount
++ < PAM_MAX_LOGIN_TRIES
) &&
513 ((retcode
== PAM_AUTH_ERR
) ||
514 (retcode
== PAM_USER_UNKNOWN
) ||
515 (retcode
== PAM_CRED_INSUFFICIENT
) ||
516 (retcode
== PAM_AUTHINFO_UNAVAIL
))) {
517 pam_get_item(pamh
, PAM_USER
, (const void **) &username
);
518 syslog(LOG_NOTICE
,_("FAILED LOGIN %d FROM %s FOR %s, %s"),
519 failcount
, hostname
, username
, pam_strerror(pamh
, retcode
));
520 fprintf(stderr
,_("Login incorrect\n\n"));
521 pam_set_item(pamh
,PAM_USER
,NULL
);
522 retcode
= pam_authenticate(pamh
, 0);
525 if (retcode
!= PAM_SUCCESS
) {
526 pam_get_item(pamh
, PAM_USER
, (const void **) &username
);
528 if (retcode
== PAM_MAXTRIES
)
529 syslog(LOG_NOTICE
,_("TOO MANY LOGIN TRIES (%d) FROM %s FOR "
530 "%s, %s"), failcount
, hostname
, username
,
531 pam_strerror(pamh
, retcode
));
533 syslog(LOG_NOTICE
,_("FAILED LOGIN SESSION FROM %s FOR %s, %s"),
534 hostname
, username
, pam_strerror(pamh
, retcode
));
536 fprintf(stderr
,_("\nLogin incorrect\n"));
537 pam_end(pamh
, retcode
);
541 retcode
= pam_acct_mgmt(pamh
, 0);
543 if(retcode
== PAM_NEW_AUTHTOK_REQD
) {
544 retcode
= pam_chauthtok(pamh
, PAM_CHANGE_EXPIRED_AUTHTOK
);
550 /* Grab the user information out of the password file for future usage
551 First get the username that we are actually using, though.
553 retcode
= pam_get_item(pamh
, PAM_USER
, (const void **) &username
);
555 pwd
= getpwnam(username
);
556 if (pwd
) initgroups(username
, pwd
->pw_gid
);
558 retcode
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
);
561 retcode
= pam_open_session(pamh
, 0);
564 #else /* ! USE_PAM */
566 for (cnt
= 0;; ask
= 1) {
569 ioctl(0, TIOCSETD
, &ioctlval
);
577 /* Dirty patch to fix a gigantic security hole when using
578 yellow pages. This problem should be solved by the
579 libraries, and not by programs, but this must be fixed
580 urgently! If the first char of the username is '+', we
582 Feb 95 <alvaro@etsit.upm.es> */
584 if (username
[0] == '+') {
585 puts(_("Illegal username"));
590 /* (void)strcpy(tbuf, username); why was this here? */
591 if ((pwd
= getpwnam(username
))) {
595 if ((sp
= getspnam(username
)))
596 pwd
->pw_passwd
= sp
->sp_pwdp
;
598 salt
= pwd
->pw_passwd
;
603 initgroups(username
, pwd
->pw_gid
);
604 checktty(username
, tty
, pwd
); /* in checktty.c */
607 /* if user not super-user, check for disabled logins */
608 if (pwd
== NULL
|| pwd
->pw_uid
)
612 * Disallow automatic login to root; if not invoked by
613 * root, disallow if the uid's differ.
618 passwd_req
= pwd
->pw_uid
== 0 ||
619 (uid
&& uid
!= pwd
->pw_uid
);
623 * If trying to log in as root, but with insecure terminal,
624 * refuse the login attempt.
626 if (pwd
&& pwd
->pw_uid
== 0 && !rootterm(tty
)) {
628 _("%s login refused on this terminal.\n"),
633 _("LOGIN %s REFUSED FROM %s ON TTY %s"),
634 pwd
->pw_name
, hostname
, tty
);
637 _("LOGIN %s REFUSED ON TTY %s"),
643 * If no pre-authentication and a password exists
644 * for this user, prompt for one and verify it.
646 if (!passwd_req
|| (pwd
&& !*pwd
->pw_passwd
))
649 setpriority(PRIO_PROCESS
, 0, -4);
650 pp
= getpass(_("Password: "));
653 if (strncmp(pp
, "CRYPTO", 6) == 0) {
654 if (pwd
&& cryptocard()) break;
656 # endif /* CRYPTOCARD */
659 setpriority(PRIO_PROCESS
, 0, 0);
663 * If not present in pw file, act as we normally would.
664 * If we aren't Kerberos-authenticated, try the normal
665 * pw file for a password. If that's ok, log the user
666 * in without issueing any tickets.
669 if (pwd
&& !krb_get_lrealm(realm
,1)) {
671 * get TGT for local realm; be careful about uid's
672 * here for ticket file ownership
674 setreuid(geteuid(),pwd
->pw_uid
);
675 kerror
= krb_get_pw_in_tkt(pwd
->pw_name
, "", realm
,
676 "krbtgt", realm
, DEFAULT_TKT_LIFE
, pp
);
678 if (kerror
== INTK_OK
) {
679 memset(pp
, 0, strlen(pp
));
680 notickets
= 0; /* user got ticket */
684 # endif /* KERBEROS */
685 memset(pp
, 0, strlen(pp
));
686 if (pwd
&& !strcmp(p
, pwd
->pw_passwd
))
689 printf(_("Login incorrect\n"));
690 badlogin(username
); /* log ALL bad logins */
693 /* we allow 10 tries, but after 3 we start backing off */
698 sleep((unsigned int)((cnt
- 3) * 5));
701 #endif /* !USE_PAM */
703 /* committed to login -- turn off timeout */
704 alarm((unsigned int)0);
707 if (quota(Q_SETUID
, pwd
->pw_uid
, 0, 0) < 0 && errno
!= EINVAL
) {
711 _("Too many users logged on already.\nTry again later.\n"));
715 _("You have too many processes running.\n"));
718 perror("quota (Q_SETUID)");
730 /* This requires some explanation: As root we may not be able to
731 read the directory of the user if it is on an NFS mounted
732 filesystem. We temporarily set our effective uid to the user-uid
733 making sure that we keep root privs. in the real uid.
735 A portable solution would require a fork(), but we rely on Linux
736 having the BSD setreuid() */
739 char tmpstr
[MAXPATHLEN
];
740 uid_t ruid
= getuid();
741 gid_t egid
= getegid();
743 /* avoid snprintf - old systems do not have it, or worse,
744 have a libc in which snprintf is the same as sprintf */
745 if (strlen(pwd
->pw_dir
) + sizeof(_PATH_HUSHLOGIN
) + 2 > MAXPATHLEN
)
748 sprintf(tmpstr
, "%s/%s", pwd
->pw_dir
, _PATH_HUSHLOGIN
);
749 setregid(-1, pwd
->pw_gid
);
750 setreuid(0, pwd
->pw_uid
);
751 quietlog
= (access(tmpstr
, R_OK
) == 0);
752 setuid(0); /* setreuid doesn't do it alone! */
760 if (notickets
&& !quietlog
)
761 printf(_("Warning: no Kerberos tickets issued\n"));
764 # ifndef USE_PAM /* PAM does all of this for us */
765 # define TWOWEEKS (14*24*60*60)
766 if (pwd
->pw_change
|| pwd
->pw_expire
) {
769 gettimeofday(&tp
, (struct timezone
*)NULL
);
771 if (pwd
->pw_change
) {
772 if (tp
.tv_sec
>= pwd
->pw_change
) {
773 printf(_("Sorry -- your password has expired.\n"));
776 else if (tp
.tv_sec
- pwd
->pw_change
< TWOWEEKS
&& !quietlog
) {
778 ttp
= localtime(&pwd
->pw_change
);
779 printf(_("Warning: your password expires on %s %d, %d\n"),
780 months
[ttp
->tm_mon
], ttp
->tm_mday
,
781 TM_YEAR_BASE
+ ttp
->tm_year
);
785 if (pwd
->pw_expire
) {
786 if (tp
.tv_sec
>= pwd
->pw_expire
) {
787 printf(_("Sorry -- your account has expired.\n"));
790 else if (tp
.tv_sec
- pwd
->pw_expire
< TWOWEEKS
&& !quietlog
) {
792 ttp
= localtime(&pwd
->pw_expire
);
793 printf(_("Warning: your account expires on %s %d, %d\n"),
794 months
[ttp
->tm_mon
], ttp
->tm_mday
,
795 TM_YEAR_BASE
+ ttp
->tm_year
);
799 # endif /* !USE_PAM */
801 /* nothing else left to fail -- really log in */
805 memset((char *)&utmp
, 0, sizeof(utmp
));
807 strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
808 /* ut_name may legally be non-null-terminated */
810 strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
811 utmp
.ut_host
[sizeof(utmp
.ut_host
)-1] = 0;
813 strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
814 utmp
.ut_line
[sizeof(utmp
.ut_line
)-1] = 0;
817 #else /* __linux__ defined */
818 /* for linux, write entries in utmp and wtmp */
823 pid_t mypid
= getpid();
825 utmpname(_PATH_UTMP
);
828 /* Find mypid in utmp.
829 login sometimes overwrites the runlevel entry in /var/run/utmp,
830 confusing sysvinit. I added a test for the entry type, and the problem
831 was gone. (In a runlevel entry, st_pid is not really a pid but some number
832 calculated from the previous and current runlevel).
833 Michael Riepe <michael@stud.uni-hannover.de>
835 while ((utp
= getutent()))
836 if (utp
->ut_pid
== mypid
837 && utp
->ut_type
>= INIT_PROCESS
838 && utp
->ut_type
<= DEAD_PROCESS
)
841 /* If we can't find a pre-existing entry by pid, try by line.
842 BSD network daemons may rely on this. (anonymous) */
845 ut
.ut_type
= LOGIN_PROCESS
;
846 strncpy(ut
.ut_id
, ttyn
+ 8, sizeof(ut
.ut_id
));
847 strncpy(ut
.ut_line
, ttyn
+ 5, sizeof(ut
.ut_line
));
852 memcpy(&ut
, utp
, sizeof(ut
));
854 /* some gettys/telnetds don't initialize utmp... */
855 memset(&ut
, 0, sizeof(ut
));
858 if (ut
.ut_id
[0] == 0)
859 strncpy(ut
.ut_id
, ttyn
+ 8, sizeof(ut
.ut_id
));
861 strncpy(ut
.ut_user
, username
, sizeof(ut
.ut_user
));
862 strncpy(ut
.ut_line
, ttyn
+ 5, sizeof(ut
.ut_line
));
863 ut
.ut_line
[sizeof(ut
.ut_line
)-1] = 0;
864 #ifdef _HAVE_UT_TV /* in <utmpbits.h> included by <utmp.h> */
865 gettimeofday(&ut
.ut_tv
, NULL
);
870 ut
.ut_time
= t
; /* ut_time is not always a time_t */
871 /* glibc2 #defines it as ut_tv.tv_sec */
874 ut
.ut_type
= USER_PROCESS
;
877 strncpy(ut
.ut_host
, hostname
, sizeof(ut
.ut_host
));
878 ut
.ut_host
[sizeof(ut
.ut_host
)-1] = 0;
879 if (hostaddress
.h_addr_list
)
880 memcpy(&ut
.ut_addr
, hostaddress
.h_addr_list
[0],
887 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
888 updwtmp(_PATH_WTMP
, &ut
);
891 /* The O_APPEND open() flag should be enough to guarantee
892 atomic writes at end of file. */
893 if((wtmp
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
894 write(wtmp
, (char *)&ut
, sizeof(ut
));
898 /* Probably all this locking below is just nonsense,
899 and the short version is OK as well. */
902 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
|O_WRONLY
, 0660)) >= 0) {
904 if ((wtmp
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
905 write(wtmp
, (char *)&ut
, sizeof(ut
));
913 #endif /* __GLIBC__ */
915 #endif /* __linux__ */
920 if (!hflag
) { /* XXX */
921 static struct winsize win
= { 0, 0, 0, 0 };
923 ioctl(0, TIOCSWINSZ
, &win
);
926 chown(ttyn
, pwd
->pw_uid
,
927 (gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
);
928 chmod(ttyn
, TTY_MODE
);
930 /* if tty is one of the VC's then change owner and mode of the
931 special /dev/vcs devices as well */
933 chown(vcsn
, pwd
->pw_uid
, (gr
? gr
->gr_gid
: pwd
->pw_gid
));
934 chown(vcsan
, pwd
->pw_uid
, (gr
? gr
->gr_gid
: pwd
->pw_gid
));
935 chmod(vcsn
, TTY_MODE
);
936 chmod(vcsan
, TTY_MODE
);
942 quota(Q_DOWARN
, pwd
->pw_uid
, (dev_t
)-1, 0);
945 if (*pwd
->pw_shell
== '\0')
946 pwd
->pw_shell
= _PATH_BSHELL
;
948 /* turn on new line discipline for the csh */
949 else if (!strcmp(pwd
->pw_shell
, _PATH_CSHELL
)) {
951 ioctl(0, TIOCSETD
, &ioctlval
);
955 /* preserve TERM even without -p flag */
959 if(!((ep
= getenv("TERM")) && (termenv
= strdup(ep
))))
963 /* destroy environment unless user has requested preservation */
966 environ
= (char**)malloc(sizeof(char*));
967 memset(environ
, 0, sizeof(char*));
971 setenv("HOME", pwd
->pw_dir
, 1);
972 setenv("SHELL", pwd
->pw_shell
, 1);
973 if (term
[0] == '\0') {
974 strncpy(term
, stypeof(tty
), sizeof(term
));
975 term
[sizeof(term
)-1] = 0;
977 setenv("TERM", term
, 0);
978 setenv("USER", pwd
->pw_name
, 1);
979 setenv("PATH", _PATH_DEFPATH
, 0);
981 setenv("HOME", pwd
->pw_dir
, 0); /* legal to override */
983 setenv("PATH", _PATH_DEFPATH
, 1);
985 setenv("PATH", _PATH_DEFPATH_ROOT
, 1);
987 setenv("SHELL", pwd
->pw_shell
, 1);
988 setenv("TERM", termenv
, 1);
990 /* mailx will give a funny error msg if you forget this one */
992 char tmp
[MAXPATHLEN
];
994 if (sizeof(_PATH_MAILDIR
) + strlen(pwd
->pw_name
) + 1 < MAXPATHLEN
) {
995 sprintf(tmp
, "%s/%s", _PATH_MAILDIR
, pwd
->pw_name
);
996 setenv("MAIL",tmp
,0);
1000 /* LOGNAME is not documented in login(1) but
1001 HP-UX 6.5 does it. We'll not allow modifying it.
1003 setenv("LOGNAME", pwd
->pw_name
, 1);
1009 const char * const * env
;
1011 env
= (const char * const *)pam_getenvlist(pamh
);
1014 for (i
=0; env
[i
++]; ) {
1016 /* D(("env[%d] = %s", i-1,env[i-1])); */
1022 #ifdef DO_PS_FIDDLING
1023 setproctitle("login", username
);
1026 if (tty
[sizeof("tty")-1] == 'S')
1027 syslog(LOG_INFO
, _("DIALUP AT %s BY %s"), tty
, pwd
->pw_name
);
1029 /* allow tracking of good logins.
1030 -steve philp (sphilp@mail.alliance.net) */
1032 if (pwd
->pw_uid
== 0) {
1034 syslog(LOG_NOTICE
, _("ROOT LOGIN ON %s FROM %s"),
1037 syslog(LOG_NOTICE
, _("ROOT LOGIN ON %s"), tty
);
1040 syslog(LOG_INFO
, _("LOGIN ON %s BY %s FROM %s"), tty
,
1041 pwd
->pw_name
, hostname
);
1043 syslog(LOG_INFO
, _("LOGIN ON %s BY %s"), tty
,
1052 mail
= getenv("MAIL");
1053 if (mail
&& stat(mail
, &st
) == 0 && st
.st_size
!= 0) {
1054 printf(_("You have %smail.\n"),
1055 (st
.st_mtime
> st
.st_atime
) ? _("new ") : "");
1059 signal(SIGALRM
, SIG_DFL
);
1060 signal(SIGQUIT
, SIG_DFL
);
1061 signal(SIGTSTP
, SIG_IGN
);
1062 signal(SIGHUP
, SIG_DFL
);
1065 /* We must fork before setuid() because we need to call
1066 * pam_close_session() as root.
1068 signal(SIGINT
, SIG_IGN
);
1072 /* error in fork() */
1073 fprintf(stderr
,_("login: failure forking: %s"), strerror(errsv
));
1076 } else if (childPid
) {
1077 /* parent - wait for child to finish, then cleanup session */
1084 signal(SIGINT
, SIG_DFL
);
1086 /* discard permissions last so can't get killed and drop core */
1087 if(setuid(pwd
->pw_uid
) < 0 && pwd
->pw_uid
) {
1088 syslog(LOG_ALERT
, _("setuid() failed"));
1092 /* wait until here to change directory! */
1093 if (chdir(pwd
->pw_dir
) < 0) {
1094 printf(_("No directory %s!\n"), pwd
->pw_dir
);
1098 printf(_("Logging in with home = \"/\".\n"));
1101 /* if the shell field has a space: treat it like a shell script */
1102 if (strchr(pwd
->pw_shell
, ' ')) {
1103 buff
= malloc(strlen(pwd
->pw_shell
) + 6);
1106 fprintf(stderr
, _("login: no memory for shell script.\n"));
1110 strcpy(buff
, "exec ");
1111 strcat(buff
, pwd
->pw_shell
);
1112 childArgv
[childArgc
++] = "/bin/sh";
1113 childArgv
[childArgc
++] = "-sh";
1114 childArgv
[childArgc
++] = "-c";
1115 childArgv
[childArgc
++] = buff
;
1118 strncpy(tbuf
+ 1, ((p
= rindex(pwd
->pw_shell
, '/')) ?
1119 p
+ 1 : pwd
->pw_shell
),
1121 tbuf
[sizeof(tbuf
)-1] = 0;
1123 childArgv
[childArgc
++] = pwd
->pw_shell
;
1124 childArgv
[childArgc
++] = tbuf
;
1127 childArgv
[childArgc
++] = NULL
;
1129 execvp(childArgv
[0], childArgv
+ 1);
1133 if (!strcmp(childArgv
[0], "/bin/sh"))
1134 fprintf(stderr
, _("login: couldn't exec shell script: %s.\n"),
1137 fprintf(stderr
, _("login: no shell: %s.\n"), strerror(errsv
));
1147 static char nbuf
[UT_NAMESIZE
+ 1];
1153 printf(_("\n%s login: "), thishost
); fflush(stdout
);
1154 for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
1159 if (p
< nbuf
+ UT_NAMESIZE
)
1163 if (cnt
> UT_NAMESIZE
+ 20) {
1164 fprintf(stderr
, _("login name much too long.\n"));
1165 badlogin(_("NAME too long"));
1172 _("login names may not start with '-'.\n"));
1182 fprintf(stderr
, _("too many bare linefeeds.\n"));
1183 badlogin(_("EXCESSIVE linefeeds"));
1194 fprintf(stderr
, _("Login timed out after %d seconds\n"), timeout
);
1197 ioctl(0, TCGETA
, &ti
);
1199 ioctl(0, TCSETA
, &ti
);
1210 return((t
= getttynam(ttyn
)) && t
->ty_status
&TTY_SECURE
);
1218 fd
= open(SECURETTY
, O_RDONLY
);
1219 if(fd
< 0) return 1;
1221 /* read each line in /etc/securetty, if a line matches our ttyline
1222 then root is allowed to login on this tty, and we should return
1226 while(--cnt
>= 0 && (more
= read(fd
, p
, 1)) == 1 && *p
!= '\n') p
++;
1227 if(more
&& *p
== '\n') {
1229 if(!strcmp(buf
, ttyn
)) {
1242 jmp_buf motdinterrupt
;
1247 register int fd
, nchars
;
1248 void (*oldint
)(), sigint();
1251 if ((fd
= open(_PATH_MOTDFILE
, O_RDONLY
, 0)) < 0)
1253 oldint
= signal(SIGINT
, sigint
);
1254 if (setjmp(motdinterrupt
) == 0)
1255 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
1256 write(fileno(stdout
), tbuf
, nchars
);
1257 signal(SIGINT
, oldint
);
1264 longjmp(motdinterrupt
, 1);
1267 #ifndef USE_PAM /* PAM takes care of this */
1271 register int fd
, nchars
;
1274 if ((fd
= open(_PATH_NOLOGIN
, O_RDONLY
, 0)) >= 0) {
1275 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
1276 write(fileno(stdout
), tbuf
, nchars
);
1289 if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
1290 lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), SEEK_SET
);
1292 if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
1294 printf(_("Last login: %.*s "),
1295 24-5, (char *)ctime(&ll
.ll_time
));
1297 if (*ll
.ll_host
!= '\0')
1298 printf(_("from %.*s\n"),
1299 (int)sizeof(ll
.ll_host
), ll
.ll_host
);
1301 printf(_("on %.*s\n"),
1302 (int)sizeof(ll
.ll_line
), ll
.ll_line
);
1304 lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), SEEK_SET
);
1306 memset((char *)&ll
, 0, sizeof(ll
));
1308 strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
1309 ll
.ll_line
[sizeof(ll
.ll_line
)-1] = 0;
1311 strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
1312 ll
.ll_host
[sizeof(ll
.ll_host
)-1] = 0;
1314 write(fd
, (char *)&ll
, sizeof(ll
));
1320 badlogin(const char *name
)
1322 if (failures
== 1) {
1324 syslog(LOG_NOTICE
, _("LOGIN FAILURE FROM %s, %s"),
1327 syslog(LOG_NOTICE
, _("LOGIN FAILURE ON %s, %s"),
1331 syslog(LOG_NOTICE
, _("%d LOGIN FAILURES FROM %s, %s"),
1332 failures
, hostname
, name
);
1334 syslog(LOG_NOTICE
, _("%d LOGIN FAILURES ON %s, %s"),
1335 failures
, tty
, name
);
1340 #define UNKNOWN "su"
1349 return(ttyid
&& (t
= getttynam(ttyid
)) ? t
->ty_type
: UNKNOWN
);
1353 /* should not be called from PAM code... Why? */
1358 sleep(SLEEP_EXIT_TIMEOUT
);