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/
57 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
58 * All rights reserved.
60 * Redistribution and use in source and binary forms are permitted
61 * provided that the above copyright notice and this paragraph are
62 * duplicated in all such forms and that any documentation,
63 * advertising materials, and other materials related to such
64 * distribution and use acknowledge that the software was developed
65 * by the University of California, Berkeley. The name of the
66 * University may not be used to endorse or promote products derived
67 * from this software without specific prior written permission.
68 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
69 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
70 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
75 * login -h hostname (for telnetd, etc.)
76 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
84 #include <sys/param.h>
95 #include <sys/resource.h>
100 #define rindex strrchr
101 #include <sys/ioctl.h>
102 #include <sys/wait.h>
111 #include <sys/syslog.h>
112 #include <sys/sysmacros.h>
114 #include "my_crypt.h"
117 # include <sys/sysmacros.h>
118 # include <linux/major.h>
132 # include <security/pam_appl.h>
133 # include <security/pam_misc.h>
134 # define PAM_MAX_LOGIN_TRIES 3
135 # define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
136 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
137 syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \
138 pam_end(pamh, retcode); exit(1); \
140 # define PAM_END { retcode = pam_close_session(pamh,0); \
141 pam_end(pamh,retcode); }
149 #define SLEEP_EXIT_TIMEOUT 5
152 #define DO_PS_FIDDLING
155 #ifdef DO_PS_FIDDLING
156 #include "setproctitle.h"
160 /* from before we had a lastlog.h file in linux */
168 #include "pathnames.h"
171 void opentty
P_((const char *tty
));
172 void getloginname
P_((void));
173 void timedout
P_((void));
174 int rootterm
P_((char *ttyn
));
175 void motd
P_((void));
176 void sigint
P_((void));
177 void checknologin
P_((void));
178 void dolastlog
P_((int quiet
));
179 void badlogin
P_((const char *name
));
180 char *stypeof
P_((char *ttyid
));
181 void checktty
P_((char *user
, char *tty
, struct passwd
*pwd
));
182 void sleepexit
P_((int eval
));
184 int cryptocard
P_((void));
189 #include <kerberos/krb.h>
190 #include <sys/termios.h>
191 char realm
[REALM_SZ
];
192 int kerror
= KSUCCESS
, notickets
= 1;
196 # define TTY_MODE 0620
198 # define TTY_MODE 0600
201 #define TTYGRPNAME "tty" /* name of group to own ttys */
202 /**# define TTYGRPNAME "other" **/
205 # define MAXPATHLEN 1024
209 * This bounds the time given to login. Not a define so it can
210 * be patched on machines where it's too small.
220 char term
[64], *hostname
, *username
, *tty
;
221 struct hostent hostaddress
;
225 struct sgttyb sgttyb
;
227 CINTR
, CQUIT
, CSTART
, CSTOP
, CEOT
, CBRK
229 struct ltchars ltc
= {
230 CSUSP
, CDSUSP
, CRPRNT
, CFLUSH
, CWERASE
, CLNEXT
234 const char *months
[] =
235 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
236 "Sep", "Oct", "Nov", "Dec" };
238 /* provided by Linus Torvalds 16-Feb-93 */
240 opentty(const char * tty
)
243 int fd
= open(tty
, O_RDWR
);
245 for (i
= 0 ; i
< fd
; i
++)
247 for (i
= 0 ; i
< 3 ; i
++)
253 /* true if the filedescriptor fd is a console tty, very Linux specific */
260 if ((fstat(fd
, &stb
) >= 0)
261 && (major(stb
.st_rdev
) == TTY_MAJOR
)
262 && (minor(stb
.st_rdev
) < 64)) {
271 main(int argc
, char **argv
)
273 extern int errno
, optind
;
274 extern char *optarg
, **environ
;
278 int ask
, fflag
, hflag
, pflag
, cnt
;
279 int quietlog
, passwd_req
;
281 char tbuf
[MAXPATHLEN
+ 2], tname
[sizeof(_PATH_TTY
) + 10];
282 char *ctime(), *ttyname(), *stypeof();
286 char vcsn
[20], vcsan
[20];
287 char * childArgv
[10];
292 pam_handle_t
*pamh
= NULL
;
293 struct pam_conv conv
= { misc_conv
, NULL
};
295 void (*oldSigHandler
) ();
303 signal(SIGALRM
, timedout
);
304 alarm((unsigned int)timeout
);
305 signal(SIGQUIT
, SIG_IGN
);
306 signal(SIGINT
, SIG_IGN
);
308 setpriority(PRIO_PROCESS
, 0, 0);
310 quota(Q_SETUID
, 0, 0, 0);
312 #ifdef DO_PS_FIDDLING
313 initproctitle(argc
, argv
);
317 * -p is used by getty to tell login not to destroy the environment
318 * -f is used to skip a second login authentication
319 * -h is used by other servers to pass the name of the remote
320 * host to login so that it may be placed in utmp and wtmp
322 gethostname(tbuf
, sizeof(tbuf
));
323 strncpy(thishost
, tbuf
, sizeof(thishost
)-1);
324 thishost
[sizeof(thishost
)-1] = 0;
325 domain
= index(tbuf
, '.');
327 username
= tty
= hostname
= NULL
;
328 fflag
= hflag
= pflag
= 0;
331 while ((ch
= getopt(argc
, argv
, "fh:p")) != EOF
)
340 "login: -h for super-user only.\n");
344 if (domain
&& (p
= index(optarg
, '.')) &&
345 strcasecmp(p
, domain
) == 0)
349 struct hostent
*he
= gethostbyname(hostname
);
351 memcpy(&hostaddress
, he
, sizeof(hostaddress
));
353 memset(&hostaddress
, 0, sizeof(hostaddress
));
365 "usage: login [-fp] [username]\n");
372 username
= strdup(p
);
374 /* wipe name - some people mistype their password here */
375 /* (of course we are too late, but perhaps this helps a little ..) */
383 ioctl(0, TIOCLSET
, &ioctlval
);
384 ioctl(0, TIOCNXCL
, 0);
385 fcntl(0, F_SETFL
, ioctlval
);
386 ioctl(0, TIOCGETP
, &sgttyb
);
387 sgttyb
.sg_erase
= CERASE
;
388 sgttyb
.sg_kill
= CKILL
;
389 ioctl(0, TIOCSLTC
, <c
);
390 ioctl(0, TIOCSETC
, &tc
);
391 ioctl(0, TIOCSETP
, &sgttyb
);
394 * Be sure that we're in
396 * This is really for HPUX
399 ioctl(0, FIOSNBIO
, &ioctlval
);
400 #endif /* ! __linux__ */
402 for (cnt
= getdtablesize(); cnt
> 2; cnt
--)
406 if (ttyn
== NULL
|| *ttyn
== '\0') {
407 /* no snprintf required - see definition of tname */
408 sprintf(tname
, "%s??", _PATH_TTY
);
412 /* find names of Virtual Console devices, for later mode change */
415 /* find number of tty */
416 while (*p
&& !isdigit(*p
)) p
++;
418 strcpy(vcsn
, "/dev/vcs"); strcat(vcsn
, p
);
419 strcpy(vcsan
, "/dev/vcsa"); strcat(vcsan
, p
);
425 struct termios tt
, ttt
;
429 ttt
.c_cflag
&= ~HUPCL
;
431 if((chown(ttyn
, 0, 0) == 0) && (chmod(ttyn
, 0622) == 0)) {
432 tcsetattr(0,TCSAFLUSH
,&ttt
);
433 signal(SIGHUP
, SIG_IGN
); /* so vhangup() wont kill us */
435 signal(SIGHUP
, SIG_DFL
);
440 /* re-open stdin,stdout,stderr after vhangup() closed them */
441 /* if it did, after 0.99.5 it doesn't! */
443 tcsetattr(0,TCSAFLUSH
,&tt
);
446 if ((tty
= rindex(ttyn
, '/')))
451 openlog("login", LOG_ODELAY
, LOG_AUTHPRIV
);
454 /* username is initialized to NULL
455 and if specified on the command line it is set.
456 Therefore, we are safe not setting it to anything
459 retcode
= pam_start("login",username
, &conv
, &pamh
);
460 if(retcode
!= PAM_SUCCESS
) {
461 fprintf(stderr
,"login: PAM Failure, aborting: %s\n",
462 pam_strerror(pamh
, retcode
));
463 syslog(LOG_ERR
,"Couldn't initialize PAM: %s", pam_strerror(pamh
, retcode
));
466 /* hostname & tty are either set to NULL or their correct values,
467 depending on how much we know */
468 retcode
= pam_set_item(pamh
, PAM_RHOST
, hostname
);
470 retcode
= pam_set_item(pamh
, PAM_TTY
, tty
);
472 /* if fflag == 1, then the user has already been authenticated */
473 if (fflag
&& (getuid() == 0))
478 if(passwd_req
== 1) {
481 /* there may be better ways to deal with some of these
482 conditions, but at least this way I don't think we'll
483 be giving away information... */
484 /* Perhaps someday we can trust that all PAM modules will
485 pay attention to failure count and get rid of MAX_LOGIN_TRIES? */
487 retcode
= pam_authenticate(pamh
, 0);
488 while((failcount
++ < PAM_MAX_LOGIN_TRIES
) &&
489 ((retcode
== PAM_AUTH_ERR
) ||
490 (retcode
== PAM_USER_UNKNOWN
) ||
491 (retcode
== PAM_CRED_INSUFFICIENT
) ||
492 (retcode
== PAM_AUTHINFO_UNAVAIL
))) {
493 pam_get_item(pamh
, PAM_USER
, (const void **) &username
);
494 syslog(LOG_NOTICE
,"FAILED LOGIN %d FROM %s FOR %s, %s",
495 failcount
, hostname
, username
, pam_strerror(pamh
, retcode
));
496 fprintf(stderr
,"Login incorrect\n\n");
497 pam_set_item(pamh
,PAM_USER
,NULL
);
498 retcode
= pam_authenticate(pamh
, 0);
501 if (retcode
!= PAM_SUCCESS
) {
502 pam_get_item(pamh
, PAM_USER
, (const void **) &username
);
504 if (retcode
== PAM_MAXTRIES
)
505 syslog(LOG_NOTICE
,"TOO MANY LOGIN TRIES (%d) FROM %s FOR "
506 "%s, %s", failcount
, hostname
, username
,
507 pam_strerror(pamh
, retcode
));
509 syslog(LOG_NOTICE
,"FAILED LOGIN SESSION FROM %s FOR %s, %s",
510 hostname
, username
, pam_strerror(pamh
, retcode
));
512 fprintf(stderr
,"\nLogin incorrect\n");
513 pam_end(pamh
, retcode
);
517 retcode
= pam_acct_mgmt(pamh
, 0);
519 if(retcode
== PAM_NEW_AUTHTOK_REQD
) {
520 retcode
= pam_chauthtok(pamh
, PAM_CHANGE_EXPIRED_AUTHTOK
);
526 /* Grab the user information out of the password file for future usage
527 First get the username that we are actually using, though.
529 retcode
= pam_get_item(pamh
, PAM_USER
, (const void **) &username
);
531 pwd
= getpwnam(username
);
532 if (pwd
) initgroups(username
, pwd
->pw_gid
);
534 retcode
= pam_setcred(pamh
, PAM_ESTABLISH_CRED
);
537 retcode
= pam_open_session(pamh
, 0);
540 #else /* ! USE_PAM */
542 for (cnt
= 0;; ask
= 1) {
545 ioctl(0, TIOCSETD
, &ioctlval
);
553 /* Dirty patch to fix a gigantic security hole when using
554 yellow pages. This problem should be solved by the
555 libraries, and not by programs, but this must be fixed
556 urgently! If the first char of the username is '+', we
558 Feb 95 <alvaro@etsit.upm.es> */
560 if (username
[0] == '+') {
561 puts("Illegal username");
566 /* (void)strcpy(tbuf, username); why was this here? */
567 if ((pwd
= getpwnam(username
))) {
571 if ((sp
= getspnam(username
)))
572 pwd
->pw_passwd
= sp
->sp_pwdp
;
574 salt
= pwd
->pw_passwd
;
579 initgroups(username
, pwd
->pw_gid
);
580 checktty(username
, tty
, pwd
); /* in checktty.c */
583 /* if user not super-user, check for disabled logins */
584 if (pwd
== NULL
|| pwd
->pw_uid
)
588 * Disallow automatic login to root; if not invoked by
589 * root, disallow if the uid's differ.
594 passwd_req
= pwd
->pw_uid
== 0 ||
595 (uid
&& uid
!= pwd
->pw_uid
);
599 * If trying to log in as root, but with insecure terminal,
600 * refuse the login attempt.
602 if (pwd
&& pwd
->pw_uid
== 0 && !rootterm(tty
)) {
604 "%s login refused on this terminal.\n",
609 "LOGIN %s REFUSED FROM %s ON TTY %s",
610 pwd
->pw_name
, hostname
, tty
);
613 "LOGIN %s REFUSED ON TTY %s",
619 * If no pre-authentication and a password exists
620 * for this user, prompt for one and verify it.
622 if (!passwd_req
|| (pwd
&& !*pwd
->pw_passwd
))
625 setpriority(PRIO_PROCESS
, 0, -4);
626 pp
= getpass("Password: ");
629 if (strncmp(pp
, "CRYPTO", 6) == 0) {
630 if (pwd
&& cryptocard()) break;
632 # endif /* CRYPTOCARD */
635 setpriority(PRIO_PROCESS
, 0, 0);
639 * If not present in pw file, act as we normally would.
640 * If we aren't Kerberos-authenticated, try the normal
641 * pw file for a password. If that's ok, log the user
642 * in without issueing any tickets.
645 if (pwd
&& !krb_get_lrealm(realm
,1)) {
647 * get TGT for local realm; be careful about uid's
648 * here for ticket file ownership
650 setreuid(geteuid(),pwd
->pw_uid
);
651 kerror
= krb_get_pw_in_tkt(pwd
->pw_name
, "", realm
,
652 "krbtgt", realm
, DEFAULT_TKT_LIFE
, pp
);
654 if (kerror
== INTK_OK
) {
655 memset(pp
, 0, strlen(pp
));
656 notickets
= 0; /* user got ticket */
660 # endif /* KERBEROS */
661 memset(pp
, 0, strlen(pp
));
662 if (pwd
&& !strcmp(p
, pwd
->pw_passwd
))
665 printf("Login incorrect\n");
666 badlogin(username
); /* log ALL bad logins */
669 /* we allow 10 tries, but after 3 we start backing off */
674 sleep((unsigned int)((cnt
- 3) * 5));
677 #endif /* !USE_PAM */
679 /* committed to login -- turn off timeout */
680 alarm((unsigned int)0);
683 if (quota(Q_SETUID
, pwd
->pw_uid
, 0, 0) < 0 && errno
!= EINVAL
) {
687 "Too many users logged on already.\nTry again later.\n");
691 "You have too many processes running.\n");
694 perror("quota (Q_SETUID)");
706 /* This requires some explanation: As root we may not be able to
707 read the directory of the user if it is on an NFS mounted
708 filesystem. We temporarily set our effective uid to the user-uid
709 making sure that we keep root privs. in the real uid.
711 A portable solution would require a fork(), but we rely on Linux
712 having the BSD setreuid() */
715 char tmpstr
[MAXPATHLEN
];
716 uid_t ruid
= getuid();
717 gid_t egid
= getegid();
719 /* avoid snprintf - old systems do not have it, or worse,
720 have a libc in which snprintf is the same as sprintf */
721 if (strlen(pwd
->pw_dir
) + sizeof(_PATH_HUSHLOGIN
) + 2 > MAXPATHLEN
)
724 sprintf(tmpstr
, "%s/%s", pwd
->pw_dir
, _PATH_HUSHLOGIN
);
725 setregid(-1, pwd
->pw_gid
);
726 setreuid(0, pwd
->pw_uid
);
727 quietlog
= (access(tmpstr
, R_OK
) == 0);
728 setuid(0); /* setreuid doesn't do it alone! */
736 if (notickets
&& !quietlog
)
737 printf("Warning: no Kerberos tickets issued\n");
740 # ifndef USE_PAM /* PAM does all of this for us */
741 # define TWOWEEKS (14*24*60*60)
742 if (pwd
->pw_change
|| pwd
->pw_expire
) {
745 gettimeofday(&tp
, (struct timezone
*)NULL
);
747 if (pwd
->pw_change
) {
748 if (tp
.tv_sec
>= pwd
->pw_change
) {
749 printf("Sorry -- your password has expired.\n");
752 else if (tp
.tv_sec
- pwd
->pw_change
< TWOWEEKS
&& !quietlog
) {
754 ttp
= localtime(&pwd
->pw_change
);
755 printf("Warning: your password expires on %s %d, %d\n",
756 months
[ttp
->tm_mon
], ttp
->tm_mday
,
757 TM_YEAR_BASE
+ ttp
->tm_year
);
761 if (pwd
->pw_expire
) {
762 if (tp
.tv_sec
>= pwd
->pw_expire
) {
763 printf("Sorry -- your account has expired.\n");
766 else if (tp
.tv_sec
- pwd
->pw_expire
< TWOWEEKS
&& !quietlog
) {
768 ttp
= localtime(&pwd
->pw_expire
);
769 printf("Warning: your account expires on %s %d, %d\n",
770 months
[ttp
->tm_mon
], ttp
->tm_mday
,
771 TM_YEAR_BASE
+ ttp
->tm_year
);
775 # endif /* !USE_PAM */
777 /* nothing else left to fail -- really log in */
781 memset((char *)&utmp
, 0, sizeof(utmp
));
783 strncpy(utmp
.ut_name
, username
, sizeof(utmp
.ut_name
));
784 /* ut_name may legally be non-null-terminated */
786 strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
787 utmp
.ut_host
[sizeof(utmp
.ut_host
)-1] = 0;
789 strncpy(utmp
.ut_line
, tty
, sizeof(utmp
.ut_line
));
790 utmp
.ut_line
[sizeof(utmp
.ut_line
)-1] = 0;
793 #else /* __linux__ defined */
794 /* for linux, write entries in utmp and wtmp */
800 pid_t mypid
= getpid();
802 utmpname(_PATH_UTMP
);
805 /* Find mypid in utmp.
806 login sometimes overwrites the runlevel entry in /var/run/utmp,
807 confusing sysvinit. I added a test for the entry type, and the problem
808 was gone. (In a runlevel entry, st_pid is not really a pid but some number
809 calculated from the previous and current runlevel).
810 Michael Riepe <michael@stud.uni-hannover.de>
812 while ((utp
= getutent()))
813 if (utp
->ut_pid
== mypid
814 && utp
->ut_type
>= INIT_PROCESS
815 && utp
->ut_type
<= DEAD_PROCESS
)
819 memcpy(&ut
, utp
, sizeof(ut
));
821 /* some gettys/telnetds don't initialize utmp... */
822 memset(&ut
, 0, sizeof(ut
));
824 /* endutent(); superfluous, error for glibc */
826 if (ut
.ut_id
[0] == 0)
827 strncpy(ut
.ut_id
, ttyn
+ 8, sizeof(ut
.ut_id
));
829 strncpy(ut
.ut_user
, username
, sizeof(ut
.ut_user
));
830 strncpy(ut
.ut_line
, ttyn
+ 5, sizeof(ut
.ut_line
));
831 ut
.ut_line
[sizeof(ut
.ut_line
)-1] = 0;
833 ut
.ut_time
= t
; /* ut_time is not always a time_t */
834 /* (we might test #ifdef _HAVE_UT_TV ) */
835 ut
.ut_type
= USER_PROCESS
;
838 strncpy(ut
.ut_host
, hostname
, sizeof(ut
.ut_host
));
839 ut
.ut_host
[sizeof(ut
.ut_host
)-1] = 0;
840 if (hostaddress
.h_addr_list
)
841 memcpy(&ut
.ut_addr
, hostaddress
.h_addr_list
[0],
848 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
849 updwtmp(_PATH_WTMP
, &ut
);
852 /* The O_APPEND open() flag should be enough to guarantee
853 atomic writes at end of file. */
854 if((wtmp
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
855 write(wtmp
, (char *)&ut
, sizeof(ut
));
859 /* Probably all this locking below is just nonsense,
860 and the short version is OK as well. */
863 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
|O_WRONLY
, 0660)) >= 0) {
865 if ((wtmp
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
866 write(wtmp
, (char *)&ut
, sizeof(ut
));
874 #endif /* __GLIBC__ */
876 #endif /* __linux__ */
881 if (!hflag
) { /* XXX */
882 static struct winsize win
= { 0, 0, 0, 0 };
884 ioctl(0, TIOCSWINSZ
, &win
);
887 chown(ttyn
, pwd
->pw_uid
,
888 (gr
= getgrnam(TTYGRPNAME
)) ? gr
->gr_gid
: pwd
->pw_gid
);
889 chmod(ttyn
, TTY_MODE
);
891 /* if tty is one of the VC's then change owner and mode of the
892 special /dev/vcs devices as well */
894 chown(vcsn
, pwd
->pw_uid
, (gr
? gr
->gr_gid
: pwd
->pw_gid
));
895 chown(vcsan
, pwd
->pw_uid
, (gr
? gr
->gr_gid
: pwd
->pw_gid
));
896 chmod(vcsn
, TTY_MODE
);
897 chmod(vcsan
, TTY_MODE
);
903 quota(Q_DOWARN
, pwd
->pw_uid
, (dev_t
)-1, 0);
906 if (*pwd
->pw_shell
== '\0')
907 pwd
->pw_shell
= _PATH_BSHELL
;
909 /* turn on new line discipline for the csh */
910 else if (!strcmp(pwd
->pw_shell
, _PATH_CSHELL
)) {
912 ioctl(0, TIOCSETD
, &ioctlval
);
916 /* preserve TERM even without -p flag */
920 if(!((ep
= getenv("TERM")) && (termenv
= strdup(ep
))))
924 /* destroy environment unless user has requested preservation */
927 environ
= (char**)malloc(sizeof(char*));
928 memset(environ
, 0, sizeof(char*));
932 setenv("HOME", pwd
->pw_dir
, 1);
933 setenv("SHELL", pwd
->pw_shell
, 1);
934 if (term
[0] == '\0') {
935 strncpy(term
, stypeof(tty
), sizeof(term
));
936 term
[sizeof(term
)-1] = 0;
938 setenv("TERM", term
, 0);
939 setenv("USER", pwd
->pw_name
, 1);
940 setenv("PATH", _PATH_DEFPATH
, 0);
942 setenv("HOME", pwd
->pw_dir
, 0); /* legal to override */
944 setenv("PATH", _PATH_DEFPATH
, 1);
946 setenv("PATH", _PATH_DEFPATH_ROOT
, 1);
948 setenv("SHELL", pwd
->pw_shell
, 1);
949 setenv("TERM", termenv
, 1);
951 /* mailx will give a funny error msg if you forget this one */
953 char tmp
[MAXPATHLEN
];
955 if (sizeof(_PATH_MAILDIR
) + strlen(pwd
->pw_name
) + 1 < MAXPATHLEN
) {
956 sprintf(tmp
, "%s/%s", _PATH_MAILDIR
, pwd
->pw_name
);
957 setenv("MAIL",tmp
,0);
961 /* LOGNAME is not documented in login(1) but
962 HP-UX 6.5 does it. We'll not allow modifying it.
964 setenv("LOGNAME", pwd
->pw_name
, 1);
970 const char * const * env
;
972 env
= (const char * const *)pam_getenvlist(pamh
);
975 for (i
=0; env
[i
++]; ) {
977 /* D(("env[%d] = %s", i-1,env[i-1])); */
983 #ifdef DO_PS_FIDDLING
984 setproctitle("login", username
);
987 if (tty
[sizeof("tty")-1] == 'S')
988 syslog(LOG_INFO
, "DIALUP AT %s BY %s", tty
, pwd
->pw_name
);
990 /* allow tracking of good logins.
991 -steve philp (sphilp@mail.alliance.net) */
993 if (pwd
->pw_uid
== 0) {
995 syslog(LOG_NOTICE
, "ROOT LOGIN ON %s FROM %s",
998 syslog(LOG_NOTICE
, "ROOT LOGIN ON %s", tty
);
1001 syslog(LOG_INFO
, "LOGIN ON %s BY %s FROM %s", tty
,
1002 pwd
->pw_name
, hostname
);
1004 syslog(LOG_INFO
, "LOGIN ON %s BY %s", tty
,
1013 mail
= getenv("MAIL");
1014 if (mail
&& stat(mail
, &st
) == 0 && st
.st_size
!= 0) {
1015 printf("You have %smail.\n",
1016 (st
.st_mtime
> st
.st_atime
) ? "new " : "");
1020 signal(SIGALRM
, SIG_DFL
);
1021 signal(SIGQUIT
, SIG_DFL
);
1022 signal(SIGTSTP
, SIG_IGN
);
1023 signal(SIGHUP
, SIG_DFL
);
1026 /* We must fork before setuid() because we need to call
1027 * pam_close_session() as root.
1029 signal(SIGINT
, SIG_IGN
);
1032 /* error in fork() */
1033 fprintf(stderr
,"login: failure forking: %s", strerror(errno
));
1036 } else if (childPid
) {
1037 /* parent - wait for child to finish, then cleanup session */
1044 signal(SIGINT
, SIG_DFL
);
1046 /* discard permissions last so can't get killed and drop core */
1047 if(setuid(pwd
->pw_uid
) < 0 && pwd
->pw_uid
) {
1048 syslog(LOG_ALERT
, "setuid() failed");
1052 /* wait until here to change directory! */
1053 if (chdir(pwd
->pw_dir
) < 0) {
1054 printf("No directory %s!\n", pwd
->pw_dir
);
1058 printf("Logging in with home = \"/\".\n");
1061 /* if the shell field has a space: treat it like a shell script */
1062 if (strchr(pwd
->pw_shell
, ' ')) {
1063 buff
= malloc(strlen(pwd
->pw_shell
) + 6);
1066 fprintf(stderr
, "login: no memory for shell script.\n");
1070 strcpy(buff
, "exec ");
1071 strcat(buff
, pwd
->pw_shell
);
1072 childArgv
[childArgc
++] = "/bin/sh";
1073 childArgv
[childArgc
++] = "-sh";
1074 childArgv
[childArgc
++] = "-c";
1075 childArgv
[childArgc
++] = buff
;
1078 strncpy(tbuf
+ 1, ((p
= rindex(pwd
->pw_shell
, '/')) ?
1079 p
+ 1 : pwd
->pw_shell
),
1081 tbuf
[sizeof(tbuf
)-1] = 0;
1083 childArgv
[childArgc
++] = pwd
->pw_shell
;
1084 childArgv
[childArgc
++] = tbuf
;
1087 childArgv
[childArgc
++] = NULL
;
1089 execvp(childArgv
[0], childArgv
+ 1);
1091 if (!strcmp(childArgv
[0], "/bin/sh"))
1092 fprintf(stderr
, "login: couldn't exec shell script: %s.\n",
1095 fprintf(stderr
, "login: no shell: %s.\n", strerror(errno
));
1105 static char nbuf
[UT_NAMESIZE
+ 1];
1111 printf("\n%s login: ", thishost
); fflush(stdout
);
1112 for (p
= nbuf
; (ch
= getchar()) != '\n'; ) {
1117 if (p
< nbuf
+ UT_NAMESIZE
)
1121 if (cnt
> UT_NAMESIZE
+ 20) {
1122 fprintf(stderr
, "login name much too long.\n");
1123 badlogin("NAME too long");
1130 "login names may not start with '-'.\n");
1140 fprintf(stderr
, "too many bare linefeeds.\n");
1141 badlogin("EXCESSIVE linefeeds");
1152 fprintf(stderr
, "Login timed out after %d seconds\n", timeout
);
1155 ioctl(0, TCGETA
, &ti
);
1157 ioctl(0, TCSETA
, &ti
);
1168 return((t
= getttynam(ttyn
)) && t
->ty_status
&TTY_SECURE
);
1176 fd
= open(SECURETTY
, O_RDONLY
);
1177 if(fd
< 0) return 1;
1179 /* read each line in /etc/securetty, if a line matches our ttyline
1180 then root is allowed to login on this tty, and we should return
1184 while(--cnt
>= 0 && (more
= read(fd
, p
, 1)) == 1 && *p
!= '\n') p
++;
1185 if(more
&& *p
== '\n') {
1187 if(!strcmp(buf
, ttyn
)) {
1200 jmp_buf motdinterrupt
;
1205 register int fd
, nchars
;
1206 void (*oldint
)(), sigint();
1209 if ((fd
= open(_PATH_MOTDFILE
, O_RDONLY
, 0)) < 0)
1211 oldint
= signal(SIGINT
, sigint
);
1212 if (setjmp(motdinterrupt
) == 0)
1213 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
1214 write(fileno(stdout
), tbuf
, nchars
);
1215 signal(SIGINT
, oldint
);
1222 longjmp(motdinterrupt
, 1);
1225 #ifndef USE_PAM /* PAM takes care of this */
1229 register int fd
, nchars
;
1232 if ((fd
= open(_PATH_NOLOGIN
, O_RDONLY
, 0)) >= 0) {
1233 while ((nchars
= read(fd
, tbuf
, sizeof(tbuf
))) > 0)
1234 write(fileno(stdout
), tbuf
, nchars
);
1247 if ((fd
= open(_PATH_LASTLOG
, O_RDWR
, 0)) >= 0) {
1248 lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), SEEK_SET
);
1250 if (read(fd
, (char *)&ll
, sizeof(ll
)) == sizeof(ll
) &&
1252 printf("Last login: %.*s ",
1253 24-5, (char *)ctime(&ll
.ll_time
));
1255 if (*ll
.ll_host
!= '\0')
1256 printf("from %.*s\n",
1257 (int)sizeof(ll
.ll_host
), ll
.ll_host
);
1260 (int)sizeof(ll
.ll_line
), ll
.ll_line
);
1262 lseek(fd
, (off_t
)pwd
->pw_uid
* sizeof(ll
), SEEK_SET
);
1264 memset((char *)&ll
, 0, sizeof(ll
));
1266 strncpy(ll
.ll_line
, tty
, sizeof(ll
.ll_line
));
1267 ll
.ll_line
[sizeof(ll
.ll_line
)-1] = 0;
1269 strncpy(ll
.ll_host
, hostname
, sizeof(ll
.ll_host
));
1270 ll
.ll_host
[sizeof(ll
.ll_host
)-1] = 0;
1272 write(fd
, (char *)&ll
, sizeof(ll
));
1278 badlogin(const char *name
)
1281 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s FROM %s, %s",
1282 failures
, failures
> 1 ? "S" : "", hostname
, name
);
1284 syslog(LOG_NOTICE
, "%d LOGIN FAILURE%s ON %s, %s",
1285 failures
, failures
> 1 ? "S" : "", tty
, name
);
1289 #define UNKNOWN "su"
1298 return(ttyid
&& (t
= getttynam(ttyid
)) ? t
->ty_type
: UNKNOWN
);
1302 /* should not be called from PAM code... Why? */
1307 sleep(SLEEP_EXIT_TIMEOUT
);