]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/login.c
Imported from util-linux-2.11o tarball.
[thirdparty/util-linux.git] / login-utils / login.c
1 /* This program is derived from 4.3 BSD software and is
2 subject to the copyright notice below.
3
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.
6
7 Changes:
8
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.
12
13 - The program uses BSD command line options to be used
14 in connection with e.g. 'rlogind' i.e. 'new login'.
15
16 - HP features left out: password expiry
17 '*' as login shell, add it if you need it
18
19 - BSD features left out: quota checks
20 password expiry
21 analysis of terminal type (tset feature)
22
23 - BSD features thrown in: Security logging to syslogd.
24 This requires you to have a (ported) syslog
25 system -- 7.0 comes with syslog
26
27 'Lastlog' feature.
28
29 - A lot of nitty gritty details have been adjusted in favour of
30 HP-UX, e.g. /etc/securetty, default paths and the environment
31 variables assigned by 'login'.
32
33 - We do *nothing* to setup/alter tty state, under HP-UX this is
34 to be done by getty/rlogind/telnetd/some one else.
35
36 Michael Glad (glad@daimi.dk)
37 Computer Science Department
38 Aarhus University
39 Denmark
40
41 1990-07-04
42
43 1991-09-24 glad@daimi.aau.dk: HP-UX 8.0 port:
44 - now explictly sets non-blocking mode on descriptors
45 - strcasecmp is now part of HP-UX
46
47 1992-02-05 poe@daimi.aau.dk: Ported the stuff to Linux 0.12
48 From 1992 till now (1997) this code for Linux has been maintained at
49 ftp.daimi.aau.dk:/pub/linux/poe/
50
51 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
52 - added Native Language Support
53 Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
54 - fixed strerr(errno) in gettext calls
55 */
56
57 /*
58 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
59 * All rights reserved.
60 *
61 * Redistribution and use in source and binary forms are permitted
62 * provided that the above copyright notice and this paragraph are
63 * duplicated in all such forms and that any documentation,
64 * advertising materials, and other materials related to such
65 * distribution and use acknowledge that the software was developed
66 * by the University of California, Berkeley. The name of the
67 * University may not be used to endorse or promote products derived
68 * from this software without specific prior written permission.
69 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
70 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
71 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
72 */
73
74 /*
75 * login [ name ]
76 * login -h hostname (for telnetd, etc.)
77 * login -f name (for pre-authenticated login: datakit, xterm, etc.)
78 */
79
80 /* #define TESTING */
81
82 #ifdef TESTING
83 #include "param.h"
84 #else
85 #include <sys/param.h>
86 #endif
87
88 #include <stdio.h>
89 #include <ctype.h>
90 #include <unistd.h>
91 #include <getopt.h>
92 #include <memory.h>
93 #include <time.h>
94 #include <sys/stat.h>
95 #include <sys/time.h>
96 #include <sys/resource.h>
97 #include <sys/file.h>
98 #include <termios.h>
99 #include <string.h>
100 #define index strchr
101 #define rindex strrchr
102 #include <sys/ioctl.h>
103 #include <sys/wait.h>
104 #include <signal.h>
105 #include <errno.h>
106 #include <grp.h>
107 #include <pwd.h>
108 #include <utmp.h>
109 #include <setjmp.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <sys/syslog.h>
113 #include <sys/sysmacros.h>
114 #include <netdb.h>
115 #include "pathnames.h"
116 #include "my_crypt.h"
117 #include "login.h"
118 #include "xstrncpy.h"
119 #include "nls.h"
120
121 #ifdef __linux__
122 # include <sys/sysmacros.h>
123 # include <linux/major.h>
124 #endif
125
126 #ifdef TESTING
127 # include "utmp.h"
128 #else
129 # include <utmp.h>
130 #endif
131
132 #ifdef SHADOW_PWD
133 # include <shadow.h>
134 #endif
135
136 #ifdef USE_PAM
137 # include <security/pam_appl.h>
138 # include <security/pam_misc.h>
139 # define PAM_MAX_LOGIN_TRIES 3
140 # define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
141 fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
142 syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \
143 pam_end(pamh, retcode); exit(1); \
144 }
145 # define PAM_END { \
146 pam_setcred(pamh, PAM_DELETE_CRED); \
147 retcode = pam_close_session(pamh,0); \
148 pam_end(pamh,retcode); \
149 }
150 #endif
151
152 #ifndef __linux__
153 # include <tzfile.h>
154 #endif
155 #include <lastlog.h>
156
157 #define SLEEP_EXIT_TIMEOUT 5
158
159 #ifdef __linux__
160 #define DO_PS_FIDDLING
161 #endif
162
163 #ifdef DO_PS_FIDDLING
164 #include "setproctitle.h"
165 #endif
166
167 #if 0
168 /* from before we had a lastlog.h file in linux */
169 struct lastlog
170 { long ll_time;
171 char ll_line[12];
172 char ll_host[16];
173 };
174 #endif
175
176 #ifndef USE_PAM
177 static void getloginname (void);
178 static void checknologin (void);
179 static int rootterm (char *ttyn);
180 #endif
181 static void timedout (int);
182 static void sigint (int);
183 static void motd (void);
184 static void dolastlog (int quiet);
185
186 #ifndef __linux__
187 static char *stypeof (char *ttyid);
188 #endif
189
190 #ifdef CRYPTOCARD
191 #include "cryptocard.h"
192 #endif
193
194 #ifdef KERBEROS
195 #include <kerberos/krb.h>
196 #include <sys/termios.h>
197 char realm[REALM_SZ];
198 int kerror = KSUCCESS, notickets = 1;
199 #endif
200
201 #ifdef USE_TTY_GROUP
202 # define TTY_MODE 0620
203 #else
204 # define TTY_MODE 0600
205 #endif
206
207 #define TTYGRPNAME "tty" /* name of group to own ttys */
208 /**# define TTYGRPNAME "other" **/
209
210 #ifndef MAXPATHLEN
211 # define MAXPATHLEN 1024
212 #endif
213
214 /*
215 * This bounds the time given to login. Not a define so it can
216 * be patched on machines where it's too small.
217 */
218 #ifndef __linux__
219 int timeout = 300;
220 #else
221 int timeout = 60; /* used in cryptocard.c */
222 #endif
223
224 struct passwd *pwd; /* used in cryptocard.c */
225 #if USE_PAM
226 static struct passwd pwdcopy;
227 #endif
228 char hostaddress[4]; /* used in checktty.c */
229 char *hostname; /* idem */
230 static char *username, *tty_name, *tty_number;
231 static char thishost[100];
232 static int failures = 1;
233
234 #ifndef __linux__
235 struct sgttyb sgttyb;
236 struct tchars tc = {
237 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
238 };
239 struct ltchars ltc = {
240 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
241 };
242 #endif
243
244 const char *months[] = {
245 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
246 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
247 };
248
249 /* Nice and simple code provided by Linus Torvalds 16-Feb-93 */
250 /* Nonblocking stuff by Maciej W. Rozycki, macro@ds2.pg.gda.pl, 1999.
251 He writes: "Login performs open() on a tty in a blocking mode.
252 In some cases it may make login wait in open() for carrier infinitely,
253 for example if the line is a simplistic case of a three-wire serial
254 connection. I believe login should open the line in the non-blocking mode
255 leaving the decision to make a connection to getty (where it actually
256 belongs). */
257 static void
258 opentty(const char * tty) {
259 int i;
260 int fd = open(tty, O_RDWR | O_NONBLOCK);
261 int flags = fcntl(fd, F_GETFL);
262
263 flags &= ~O_NONBLOCK;
264 fcntl(fd, F_SETFL, flags);
265
266 for (i = 0 ; i < fd ; i++)
267 close(i);
268 for (i = 0 ; i < 3 ; i++)
269 dup2(fd, i);
270 if (fd >= 3)
271 close(fd);
272 }
273
274 /* true if the filedescriptor fd is a console tty, very Linux specific */
275 static int
276 consoletty(int fd) {
277 #ifdef __linux__
278 struct stat stb;
279
280 if ((fstat(fd, &stb) >= 0)
281 && (major(stb.st_rdev) == TTY_MAJOR)
282 && (minor(stb.st_rdev) < 64)) {
283 return 1;
284 }
285 #endif
286 return 0;
287 }
288
289 #if USE_PAM
290 /*
291 * Log failed login attempts in _PATH_BTMP if that exists.
292 * Must be called only with username the name of an actual user.
293 * The most common login failure is to give password instead of username.
294 */
295 #define _PATH_BTMP "/var/log/btmp"
296 static void
297 logbtmp(const char *line, const char *username, const char *hostname) {
298 struct utmp ut;
299
300 memset(&ut, 0, sizeof(ut));
301
302 strncpy(ut.ut_user, username ? username : "(unknown)",
303 sizeof(ut.ut_user));
304
305 strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
306 xstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
307
308 #if defined(_HAVE_UT_TV) /* in <utmpbits.h> included by <utmp.h> */
309 gettimeofday(&ut.ut_tv, NULL);
310 #else
311 {
312 time_t t;
313 time(&t);
314 ut.ut_time = t; /* ut_time is not always a time_t */
315 }
316 #endif
317
318 ut.ut_type = LOGIN_PROCESS; /* XXX doesn't matter */
319 ut.ut_pid = getpid();
320 if (hostname) {
321 xstrncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
322 if (hostaddress[0])
323 memcpy(&ut.ut_addr, hostaddress, sizeof(ut.ut_addr));
324 }
325 #ifdef HAVE_updwtmp /* bad luck for ancient systems */
326 updwtmp(_PATH_BTMP, &ut);
327 #endif
328 }
329 #endif /* USE_PAM */
330
331 int
332 main(int argc, char **argv)
333 {
334 extern int optind;
335 extern char *optarg, **environ;
336 struct group *gr;
337 register int ch;
338 register char *p;
339 int ask, fflag, hflag, pflag, cnt, errsv;
340 int quietlog, passwd_req;
341 char *domain, *ttyn;
342 char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
343 char *termenv;
344 char * childArgv[10];
345 char * buff;
346 int childArgc = 0;
347 #ifdef USE_PAM
348 int retcode;
349 pam_handle_t *pamh = NULL;
350 struct pam_conv conv = { misc_conv, NULL };
351 pid_t childPid;
352 #else
353 char *salt, *pp;
354 #endif
355 #ifdef CHOWNVCS
356 char vcsn[20], vcsan[20];
357 #endif
358 #ifndef __linux__
359 int ioctlval;
360 #endif
361
362 signal(SIGALRM, timedout);
363 alarm((unsigned int)timeout);
364 signal(SIGQUIT, SIG_IGN);
365 signal(SIGINT, SIG_IGN);
366
367 setlocale(LC_ALL, "");
368 bindtextdomain(PACKAGE, LOCALEDIR);
369 textdomain(PACKAGE);
370
371 setpriority(PRIO_PROCESS, 0, 0);
372 #ifdef HAVE_QUOTA
373 quota(Q_SETUID, 0, 0, 0);
374 #endif
375 #ifdef DO_PS_FIDDLING
376 initproctitle(argc, argv);
377 #endif
378
379 /*
380 * -p is used by getty to tell login not to destroy the environment
381 * -f is used to skip a second login authentication
382 * -h is used by other servers to pass the name of the remote
383 * host to login so that it may be placed in utmp and wtmp
384 */
385 gethostname(tbuf, sizeof(tbuf));
386 xstrncpy(thishost, tbuf, sizeof(thishost));
387 domain = index(tbuf, '.');
388
389 username = tty_name = hostname = NULL;
390 fflag = hflag = pflag = 0;
391 passwd_req = 1;
392
393 while ((ch = getopt(argc, argv, "fh:p")) != -1)
394 switch (ch) {
395 case 'f':
396 fflag = 1;
397 break;
398
399 case 'h':
400 if (getuid()) {
401 fprintf(stderr,
402 _("login: -h for super-user only.\n"));
403 exit(1);
404 }
405 hflag = 1;
406 if (domain && (p = index(optarg, '.')) &&
407 strcasecmp(p, domain) == 0)
408 *p = 0;
409
410 hostname = strdup(optarg); /* strdup: Ambrose C. Li */
411 {
412 struct hostent *he = gethostbyname(hostname);
413
414 /* he points to static storage; copy the part we use */
415 hostaddress[0] = 0;
416 if (he && he->h_addr_list && he->h_addr_list[0])
417 memcpy(hostaddress, he->h_addr_list[0],
418 sizeof(hostaddress));
419 }
420 break;
421
422 case 'p':
423 pflag = 1;
424 break;
425
426 case '?':
427 default:
428 fprintf(stderr,
429 _("usage: login [-fp] [username]\n"));
430 exit(1);
431 }
432 argc -= optind;
433 argv += optind;
434 if (*argv) {
435 char *p = *argv;
436 username = strdup(p);
437 ask = 0;
438 /* wipe name - some people mistype their password here */
439 /* (of course we are too late, but perhaps this helps a little ..) */
440 while(*p)
441 *p++ = ' ';
442 } else
443 ask = 1;
444
445 #ifndef __linux__
446 ioctlval = 0;
447 ioctl(0, TIOCLSET, &ioctlval);
448 ioctl(0, TIOCNXCL, 0);
449 fcntl(0, F_SETFL, ioctlval);
450 ioctl(0, TIOCGETP, &sgttyb);
451 sgttyb.sg_erase = CERASE;
452 sgttyb.sg_kill = CKILL;
453 ioctl(0, TIOCSLTC, &ltc);
454 ioctl(0, TIOCSETC, &tc);
455 ioctl(0, TIOCSETP, &sgttyb);
456
457 /*
458 * Be sure that we're in blocking mode!!!
459 * This is really for HPUX
460 */
461 ioctlval = 0;
462 ioctl(0, FIOSNBIO, &ioctlval);
463 #endif /* ! __linux__ */
464
465 for (cnt = getdtablesize(); cnt > 2; cnt--)
466 close(cnt);
467
468 ttyn = ttyname(0);
469 if (ttyn == NULL || *ttyn == '\0') {
470 /* no snprintf required - see definition of tname */
471 sprintf(tname, "%s??", _PATH_TTY);
472 ttyn = tname;
473 }
474
475 if (strncmp(ttyn, "/dev/", 5) == 0)
476 tty_name = ttyn+5;
477 else
478 tty_name = ttyn;
479
480 if (strncmp(ttyn, "/dev/tty", 8) == 0)
481 tty_number = ttyn+8;
482 else {
483 char *p = ttyn;
484 while (*p && !isdigit(*p)) p++;
485 tty_number = p;
486 }
487
488 #ifdef CHOWNVCS
489 /* find names of Virtual Console devices, for later mode change */
490 snprintf(vcsn, sizeof(vcsn), "/dev/vcs%s", tty_number);
491 snprintf(vcsan, sizeof(vcsan), "/dev/vcsa%s", tty_number);
492 #endif
493
494 setpgrp();
495
496 {
497 struct termios tt, ttt;
498
499 tcgetattr(0, &tt);
500 ttt = tt;
501 ttt.c_cflag &= ~HUPCL;
502
503 /* These can fail, e.g. with ttyn on a read-only filesystem */
504 chown(ttyn, 0, 0);
505 chmod(ttyn, TTY_MODE);
506
507 /* Kill processes left on this tty */
508 tcsetattr(0,TCSAFLUSH,&ttt);
509 signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */
510 vhangup();
511 signal(SIGHUP, SIG_DFL);
512
513 setsid();
514
515 /* re-open stdin,stdout,stderr after vhangup() closed them */
516 /* if it did, after 0.99.5 it doesn't! */
517 opentty(ttyn);
518 tcsetattr(0,TCSAFLUSH,&tt);
519 }
520
521 openlog("login", LOG_ODELAY, LOG_AUTHPRIV);
522
523 #if 0
524 /* other than iso-8859-1 */
525 printf("\033(K");
526 fprintf(stderr,"\033(K");
527 #endif
528
529 #ifdef USE_PAM
530 /*
531 * username is initialized to NULL
532 * and if specified on the command line it is set.
533 * Therefore, we are safe not setting it to anything
534 */
535
536 retcode = pam_start("login",username, &conv, &pamh);
537 if(retcode != PAM_SUCCESS) {
538 fprintf(stderr, _("login: PAM Failure, aborting: %s\n"),
539 pam_strerror(pamh, retcode));
540 syslog(LOG_ERR, _("Couldn't initialize PAM: %s"),
541 pam_strerror(pamh, retcode));
542 exit(99);
543 }
544 /* hostname & tty are either set to NULL or their correct values,
545 depending on how much we know */
546 retcode = pam_set_item(pamh, PAM_RHOST, hostname);
547 PAM_FAIL_CHECK;
548 retcode = pam_set_item(pamh, PAM_TTY, tty_name);
549 PAM_FAIL_CHECK;
550
551 /*
552 * Andrew.Taylor@cal.montage.ca: Provide a user prompt to PAM
553 * so that the "login: " prompt gets localized. Unfortunately,
554 * PAM doesn't have an interface to specify the "Password: " string
555 * (yet).
556 */
557 retcode = pam_set_item(pamh, PAM_USER_PROMPT, _("login: "));
558 PAM_FAIL_CHECK;
559
560 #if 0
561 /*
562 * other than iso-8859-1
563 * one more time due to reset tty by PAM
564 */
565 printf("\033(K");
566 fprintf(stderr,"\033(K");
567 #endif
568
569 /* if fflag == 1, then the user has already been authenticated */
570 if (fflag && (getuid() == 0))
571 passwd_req = 0;
572 else
573 passwd_req = 1;
574
575 if(passwd_req == 1) {
576 int failcount=0;
577
578 /* if we didn't get a user on the command line, set it to NULL */
579 pam_get_item(pamh, PAM_USER, (const void **) &username);
580 if (!username)
581 pam_set_item(pamh, PAM_USER, NULL);
582
583 /* there may be better ways to deal with some of these
584 conditions, but at least this way I don't think we'll
585 be giving away information... */
586 /* Perhaps someday we can trust that all PAM modules will
587 pay attention to failure count and get rid of MAX_LOGIN_TRIES? */
588
589 retcode = pam_authenticate(pamh, 0);
590 while((failcount++ < PAM_MAX_LOGIN_TRIES) &&
591 ((retcode == PAM_AUTH_ERR) ||
592 (retcode == PAM_USER_UNKNOWN) ||
593 (retcode == PAM_CRED_INSUFFICIENT) ||
594 (retcode == PAM_AUTHINFO_UNAVAIL))) {
595 pam_get_item(pamh, PAM_USER, (const void **) &username);
596
597 syslog(LOG_NOTICE,_("FAILED LOGIN %d FROM %s FOR %s, %s"),
598 failcount, hostname, username, pam_strerror(pamh, retcode));
599 logbtmp(tty_name, username, hostname);
600
601 fprintf(stderr,_("Login incorrect\n\n"));
602 pam_set_item(pamh,PAM_USER,NULL);
603 retcode = pam_authenticate(pamh, 0);
604 }
605
606 if (retcode != PAM_SUCCESS) {
607 pam_get_item(pamh, PAM_USER, (const void **) &username);
608
609 if (retcode == PAM_MAXTRIES)
610 syslog(LOG_NOTICE,_("TOO MANY LOGIN TRIES (%d) FROM %s FOR "
611 "%s, %s"), failcount, hostname, username,
612 pam_strerror(pamh, retcode));
613 else
614 syslog(LOG_NOTICE,_("FAILED LOGIN SESSION FROM %s FOR %s, %s"),
615 hostname, username, pam_strerror(pamh, retcode));
616 logbtmp(tty_name, username, hostname);
617
618 fprintf(stderr,_("\nLogin incorrect\n"));
619 pam_end(pamh, retcode);
620 exit(0);
621 }
622
623 retcode = pam_acct_mgmt(pamh, 0);
624
625 if(retcode == PAM_NEW_AUTHTOK_REQD) {
626 retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
627 }
628
629 PAM_FAIL_CHECK;
630 }
631
632 /* Grab the user information out of the password file for future usage
633 First get the username that we are actually using, though.
634 */
635 retcode = pam_get_item(pamh, PAM_USER, (const void **) &username);
636 PAM_FAIL_CHECK;
637
638 if (!username || !*username) {
639 fprintf(stderr, _("\nSession setup problem, abort.\n"));
640 syslog(LOG_ERR, _("NULL user name in %s:%d. Abort."),
641 __FUNCTION__, __LINE__);
642 pam_end(pamh, PAM_SYSTEM_ERR);
643 exit(1);
644 }
645 if (!(pwd = getpwnam(username))) {
646 fprintf(stderr, _("\nSession setup problem, abort.\n"));
647 syslog(LOG_ERR, _("Invalid user name \"%s\" in %s:%d. Abort."),
648 username, __FUNCTION__, __LINE__);
649 pam_end(pamh, PAM_SYSTEM_ERR);
650 exit(1);
651 }
652
653 /* Create a copy of the pwd struct - otherwise it may get
654 * clobbered by PAM */
655 memcpy(&pwdcopy, pwd, sizeof(*pwd));
656 pwd = &pwdcopy;
657 pwd->pw_name = strdup(pwd->pw_name);
658 pwd->pw_passwd = strdup(pwd->pw_passwd);
659 pwd->pw_gecos = strdup(pwd->pw_gecos);
660 pwd->pw_dir = strdup(pwd->pw_dir);
661 pwd->pw_shell = strdup(pwd->pw_shell);
662 if (!pwd->pw_name || !pwd->pw_passwd || !pwd->pw_gecos ||
663 !pwd->pw_dir || !pwd->pw_shell) {
664 fprintf(stderr, _("login: Out of memory\n"));
665 syslog(LOG_ERR, "Out of memory");
666 pam_end(pamh, PAM_SYSTEM_ERR);
667 exit(1);
668 }
669 username = pwd->pw_name;
670
671 /*
672 * Initialize the supplementary group list.
673 * This should be done before pam_setcred because
674 * the PAM modules might add groups during pam_setcred.
675 */
676 if (initgroups(username, pwd->pw_gid) < 0) {
677 syslog(LOG_ERR, "initgroups: %m");
678 fprintf(stderr, _("\nSession setup problem, abort.\n"));
679 pam_end(pamh, PAM_SYSTEM_ERR);
680 exit(1);
681 }
682
683 retcode = pam_open_session(pamh, 0);
684 PAM_FAIL_CHECK;
685
686 retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
687 PAM_FAIL_CHECK;
688
689 #else /* ! USE_PAM */
690
691 for (cnt = 0;; ask = 1) {
692 # ifndef __linux__
693 ioctlval = 0;
694 ioctl(0, TIOCSETD, &ioctlval);
695 # endif
696
697 if (ask) {
698 fflag = 0;
699 getloginname();
700 }
701
702 /* Dirty patch to fix a gigantic security hole when using
703 yellow pages. This problem should be solved by the
704 libraries, and not by programs, but this must be fixed
705 urgently! If the first char of the username is '+', we
706 avoid login success.
707 Feb 95 <alvaro@etsit.upm.es> */
708
709 if (username[0] == '+') {
710 puts(_("Illegal username"));
711 badlogin(username);
712 sleepexit(1);
713 }
714
715 /* (void)strcpy(tbuf, username); why was this here? */
716 if ((pwd = getpwnam(username))) {
717 # ifdef SHADOW_PWD
718 struct spwd *sp;
719
720 if ((sp = getspnam(username)))
721 pwd->pw_passwd = sp->sp_pwdp;
722 # endif
723 salt = pwd->pw_passwd;
724 } else
725 salt = "xx";
726
727 if (pwd) {
728 initgroups(username, pwd->pw_gid);
729 checktty(username, tty_name, pwd); /* in checktty.c */
730 }
731
732 /* if user not super-user, check for disabled logins */
733 if (pwd == NULL || pwd->pw_uid)
734 checknologin();
735
736 /*
737 * Disallow automatic login to root; if not invoked by
738 * root, disallow if the uid's differ.
739 */
740 if (fflag && pwd) {
741 int uid = getuid();
742
743 passwd_req = pwd->pw_uid == 0 ||
744 (uid && uid != pwd->pw_uid);
745 }
746
747 /*
748 * If trying to log in as root, but with insecure terminal,
749 * refuse the login attempt.
750 */
751 if (pwd && pwd->pw_uid == 0 && !rootterm(tty_name)) {
752 fprintf(stderr,
753 _("%s login refused on this terminal.\n"),
754 pwd->pw_name);
755
756 if (hostname)
757 syslog(LOG_NOTICE,
758 _("LOGIN %s REFUSED FROM %s ON TTY %s"),
759 pwd->pw_name, hostname, tty_name);
760 else
761 syslog(LOG_NOTICE,
762 _("LOGIN %s REFUSED ON TTY %s"),
763 pwd->pw_name, tty_name);
764 continue;
765 }
766
767 /*
768 * If no pre-authentication and a password exists
769 * for this user, prompt for one and verify it.
770 */
771 if (!passwd_req || (pwd && !*pwd->pw_passwd))
772 break;
773
774 setpriority(PRIO_PROCESS, 0, -4);
775 pp = getpass(_("Password: "));
776
777 # ifdef CRYPTOCARD
778 if (strncmp(pp, "CRYPTO", 6) == 0) {
779 if (pwd && cryptocard()) break;
780 }
781 # endif /* CRYPTOCARD */
782
783 p = crypt(pp, salt);
784 setpriority(PRIO_PROCESS, 0, 0);
785
786 # ifdef KERBEROS
787 /*
788 * If not present in pw file, act as we normally would.
789 * If we aren't Kerberos-authenticated, try the normal
790 * pw file for a password. If that's ok, log the user
791 * in without issueing any tickets.
792 */
793
794 if (pwd && !krb_get_lrealm(realm,1)) {
795 /*
796 * get TGT for local realm; be careful about uid's
797 * here for ticket file ownership
798 */
799 setreuid(geteuid(),pwd->pw_uid);
800 kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm,
801 "krbtgt", realm, DEFAULT_TKT_LIFE, pp);
802 setuid(0);
803 if (kerror == INTK_OK) {
804 memset(pp, 0, strlen(pp));
805 notickets = 0; /* user got ticket */
806 break;
807 }
808 }
809 # endif /* KERBEROS */
810 memset(pp, 0, strlen(pp));
811
812 if (pwd && !strcmp(p, pwd->pw_passwd))
813 break;
814
815 printf(_("Login incorrect\n"));
816 badlogin(username); /* log ALL bad logins */
817 failures++;
818
819 /* we allow 10 tries, but after 3 we start backing off */
820 if (++cnt > 3) {
821 if (cnt >= 10) {
822 sleepexit(1);
823 }
824 sleep((unsigned int)((cnt - 3) * 5));
825 }
826 }
827 #endif /* !USE_PAM */
828
829 /* committed to login -- turn off timeout */
830 alarm((unsigned int)0);
831
832 #ifdef HAVE_QUOTA
833 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
834 switch(errno) {
835 case EUSERS:
836 fprintf(stderr,
837 _("Too many users logged on already.\nTry again later.\n"));
838 break;
839 case EPROCLIM:
840 fprintf(stderr,
841 _("You have too many processes running.\n"));
842 break;
843 default:
844 perror("quota (Q_SETUID)");
845 }
846 sleepexit(0); /* %% */
847 }
848 #endif
849
850 /* paranoia... */
851 #ifdef SHADOW_PWD
852 endspent();
853 #endif
854 endpwent();
855
856 /* This requires some explanation: As root we may not be able to
857 read the directory of the user if it is on an NFS mounted
858 filesystem. We temporarily set our effective uid to the user-uid
859 making sure that we keep root privs. in the real uid.
860
861 A portable solution would require a fork(), but we rely on Linux
862 having the BSD setreuid() */
863
864 {
865 char tmpstr[MAXPATHLEN];
866 uid_t ruid = getuid();
867 gid_t egid = getegid();
868
869 /* avoid snprintf - old systems do not have it, or worse,
870 have a libc in which snprintf is the same as sprintf */
871 if (strlen(pwd->pw_dir) + sizeof(_PATH_HUSHLOGIN) + 2 > MAXPATHLEN)
872 quietlog = 0;
873 else {
874 sprintf(tmpstr, "%s/%s", pwd->pw_dir, _PATH_HUSHLOGIN);
875 setregid(-1, pwd->pw_gid);
876 setreuid(0, pwd->pw_uid);
877 quietlog = (access(tmpstr, R_OK) == 0);
878 setuid(0); /* setreuid doesn't do it alone! */
879 setreuid(ruid, 0);
880 setregid(-1, egid);
881 }
882 }
883
884 /* for linux, write entries in utmp and wtmp */
885 {
886 struct utmp ut;
887 struct utmp *utp;
888 pid_t mypid = getpid();
889
890 utmpname(_PATH_UTMP);
891 setutent();
892
893 /* Find mypid in utmp.
894 login sometimes overwrites the runlevel entry in /var/run/utmp,
895 confusing sysvinit. I added a test for the entry type, and the problem
896 was gone. (In a runlevel entry, st_pid is not really a pid but some number
897 calculated from the previous and current runlevel).
898 Michael Riepe <michael@stud.uni-hannover.de>
899 */
900 while ((utp = getutent()))
901 if (utp->ut_pid == mypid
902 && utp->ut_type >= INIT_PROCESS
903 && utp->ut_type <= DEAD_PROCESS)
904 break;
905
906 /* If we can't find a pre-existing entry by pid, try by line.
907 BSD network daemons may rely on this. (anonymous) */
908 if (utp == NULL) {
909 setutent();
910 ut.ut_type = LOGIN_PROCESS;
911 strncpy(ut.ut_id, tty_number, sizeof(ut.ut_id));
912 strncpy(ut.ut_line, tty_name, sizeof(ut.ut_line));
913 utp = getutid(&ut);
914 }
915
916 if (utp) {
917 memcpy(&ut, utp, sizeof(ut));
918 } else {
919 /* some gettys/telnetds don't initialize utmp... */
920 memset(&ut, 0, sizeof(ut));
921 }
922
923 if (ut.ut_id[0] == 0)
924 strncpy(ut.ut_id, tty_number, sizeof(ut.ut_id));
925
926 strncpy(ut.ut_user, username, sizeof(ut.ut_user));
927 xstrncpy(ut.ut_line, tty_name, sizeof(ut.ut_line));
928 #ifdef _HAVE_UT_TV /* in <utmpbits.h> included by <utmp.h> */
929 gettimeofday(&ut.ut_tv, NULL);
930 #else
931 {
932 time_t t;
933 time(&t);
934 ut.ut_time = t; /* ut_time is not always a time_t */
935 /* glibc2 #defines it as ut_tv.tv_sec */
936 }
937 #endif
938 ut.ut_type = USER_PROCESS;
939 ut.ut_pid = mypid;
940 if (hostname) {
941 xstrncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
942 if (hostaddress[0])
943 memcpy(&ut.ut_addr, hostaddress, sizeof(ut.ut_addr));
944 }
945
946 pututline(&ut);
947 endutent();
948
949 #ifdef HAVE_updwtmp
950 updwtmp(_PATH_WTMP, &ut);
951 #else
952 #if 0
953 /* The O_APPEND open() flag should be enough to guarantee
954 atomic writes at end of file. */
955 {
956 int wtmp;
957
958 if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
959 write(wtmp, (char *)&ut, sizeof(ut));
960 close(wtmp);
961 }
962 }
963 #else
964 /* Probably all this locking below is just nonsense,
965 and the short version is OK as well. */
966 {
967 int lf, wtmp;
968 if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
969 flock(lf, LOCK_EX);
970 if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
971 write(wtmp, (char *)&ut, sizeof(ut));
972 close(wtmp);
973 }
974 flock(lf, LOCK_UN);
975 close(lf);
976 }
977 }
978 #endif
979 #endif
980 }
981
982 dolastlog(quietlog);
983
984 chown(ttyn, pwd->pw_uid,
985 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
986 chmod(ttyn, TTY_MODE);
987
988 #ifdef CHOWNVCS
989 /* if tty is one of the VC's then change owner and mode of the
990 special /dev/vcs devices as well */
991 if (consoletty(0)) {
992 chown(vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
993 chown(vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
994 chmod(vcsn, TTY_MODE);
995 chmod(vcsan, TTY_MODE);
996 }
997 #endif
998
999 setgid(pwd->pw_gid);
1000
1001 #ifdef HAVE_QUOTA
1002 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
1003 #endif
1004
1005 if (*pwd->pw_shell == '\0')
1006 pwd->pw_shell = _PATH_BSHELL;
1007 #ifndef __linux__
1008 /* turn on new line discipline for the csh */
1009 else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) {
1010 ioctlval = NTTYDISC;
1011 ioctl(0, TIOCSETD, &ioctlval);
1012 }
1013 #endif
1014
1015 /* preserve TERM even without -p flag */
1016 {
1017 char *ep;
1018
1019 if(!((ep = getenv("TERM")) && (termenv = strdup(ep))))
1020 termenv = "dumb";
1021 }
1022
1023 /* destroy environment unless user has requested preservation */
1024 if (!pflag)
1025 {
1026 environ = (char**)malloc(sizeof(char*));
1027 memset(environ, 0, sizeof(char*));
1028 }
1029
1030 setenv("HOME", pwd->pw_dir, 0); /* legal to override */
1031 if(pwd->pw_uid)
1032 setenv("PATH", _PATH_DEFPATH, 1);
1033 else
1034 setenv("PATH", _PATH_DEFPATH_ROOT, 1);
1035
1036 setenv("SHELL", pwd->pw_shell, 1);
1037 setenv("TERM", termenv, 1);
1038
1039 /* mailx will give a funny error msg if you forget this one */
1040 {
1041 char tmp[MAXPATHLEN];
1042 /* avoid snprintf */
1043 if (sizeof(_PATH_MAILDIR) + strlen(pwd->pw_name) + 1 < MAXPATHLEN) {
1044 sprintf(tmp, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
1045 setenv("MAIL",tmp,0);
1046 }
1047 }
1048
1049 /* LOGNAME is not documented in login(1) but
1050 HP-UX 6.5 does it. We'll not allow modifying it.
1051 */
1052 setenv("LOGNAME", pwd->pw_name, 1);
1053
1054 #ifdef USE_PAM
1055 {
1056 int i;
1057 char ** env = pam_getenvlist(pamh);
1058
1059 if (env != NULL) {
1060 for (i=0; env[i]; i++) {
1061 putenv(env[i]);
1062 /* D(("env[%d] = %s", i,env[i])); */
1063 }
1064 }
1065 }
1066 #endif
1067
1068 #ifdef DO_PS_FIDDLING
1069 setproctitle("login", username);
1070 #endif
1071
1072 if (!strncmp(tty_name, "ttyS", 4))
1073 syslog(LOG_INFO, _("DIALUP AT %s BY %s"), tty_name, pwd->pw_name);
1074
1075 /* allow tracking of good logins.
1076 -steve philp (sphilp@mail.alliance.net) */
1077
1078 if (pwd->pw_uid == 0) {
1079 if (hostname)
1080 syslog(LOG_NOTICE, _("ROOT LOGIN ON %s FROM %s"),
1081 tty_name, hostname);
1082 else
1083 syslog(LOG_NOTICE, _("ROOT LOGIN ON %s"), tty_name);
1084 } else {
1085 if (hostname)
1086 syslog(LOG_INFO, _("LOGIN ON %s BY %s FROM %s"), tty_name,
1087 pwd->pw_name, hostname);
1088 else
1089 syslog(LOG_INFO, _("LOGIN ON %s BY %s"), tty_name,
1090 pwd->pw_name);
1091 }
1092
1093 if (!quietlog) {
1094 struct stat st;
1095 char *mail;
1096
1097 motd();
1098 mail = getenv("MAIL");
1099 if (mail && stat(mail, &st) == 0 && st.st_size != 0) {
1100 if (st.st_mtime > st.st_atime)
1101 printf(_("You have new mail.\n"));
1102 else
1103 printf(_("You have mail.\n"));
1104 }
1105 }
1106
1107 signal(SIGALRM, SIG_DFL);
1108 signal(SIGQUIT, SIG_DFL);
1109 signal(SIGTSTP, SIG_IGN);
1110
1111 #ifdef USE_PAM
1112 /*
1113 * We must fork before setuid() because we need to call
1114 * pam_close_session() as root.
1115 */
1116 /*
1117 * Problem: if the user's shell is a shell like ash that doesnt do
1118 * setsid() or setpgrp(), then a ctrl-\, sending SIGQUIT to every
1119 * process in the pgrp, will kill us.
1120 * Solution: use TIOCNOTTY and setsid().
1121 */
1122 signal(SIGINT, SIG_IGN);
1123 signal(SIGHUP, SIG_IGN); /* ignore signal from TIOCNOTTY below */
1124
1125 childPid = fork();
1126 if (childPid < 0) {
1127 int errsv = errno;
1128 /* error in fork() */
1129 fprintf(stderr,_("login: failure forking: %s"), strerror(errsv));
1130 PAM_END;
1131 exit(0);
1132 } else if (childPid) {
1133 /* parent - wait for child to finish, then cleanup session */
1134 ioctl(0, TIOCNOTTY, NULL);
1135 signal(SIGHUP, SIG_DFL);
1136
1137 wait(NULL);
1138 PAM_END;
1139 exit(0);
1140 }
1141 /* child */
1142 setsid();
1143 /* reopen, as we need controlling tty in the child */
1144 opentty(ttyn);
1145 #endif
1146 signal(SIGHUP, SIG_DFL);
1147 signal(SIGINT, SIG_DFL);
1148
1149 /* discard permissions last so can't get killed and drop core */
1150 if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) {
1151 syslog(LOG_ALERT, _("setuid() failed"));
1152 exit(1);
1153 }
1154
1155 /* wait until here to change directory! */
1156 if (chdir(pwd->pw_dir) < 0) {
1157 printf(_("No directory %s!\n"), pwd->pw_dir);
1158 if (chdir("/"))
1159 exit(0);
1160 pwd->pw_dir = "/";
1161 printf(_("Logging in with home = \"/\".\n"));
1162 }
1163
1164 /* if the shell field has a space: treat it like a shell script */
1165 if (strchr(pwd->pw_shell, ' ')) {
1166 buff = malloc(strlen(pwd->pw_shell) + 6);
1167
1168 if (!buff) {
1169 fprintf(stderr, _("login: no memory for shell script.\n"));
1170 exit(0);
1171 }
1172
1173 strcpy(buff, "exec ");
1174 strcat(buff, pwd->pw_shell);
1175 childArgv[childArgc++] = "/bin/sh";
1176 childArgv[childArgc++] = "-sh";
1177 childArgv[childArgc++] = "-c";
1178 childArgv[childArgc++] = buff;
1179 } else {
1180 tbuf[0] = '-';
1181 xstrncpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ?
1182 p + 1 : pwd->pw_shell),
1183 sizeof(tbuf)-1);
1184
1185 childArgv[childArgc++] = pwd->pw_shell;
1186 childArgv[childArgc++] = tbuf;
1187 }
1188
1189 childArgv[childArgc++] = NULL;
1190
1191 execvp(childArgv[0], childArgv + 1);
1192
1193 errsv = errno;
1194
1195 if (!strcmp(childArgv[0], "/bin/sh"))
1196 fprintf(stderr, _("login: couldn't exec shell script: %s.\n"),
1197 strerror(errsv));
1198 else
1199 fprintf(stderr, _("login: no shell: %s.\n"), strerror(errsv));
1200
1201 exit(0);
1202 }
1203
1204 #ifndef USE_PAM
1205 static void
1206 getloginname(void) {
1207 int ch, cnt, cnt2;
1208 char *p;
1209 static char nbuf[UT_NAMESIZE + 1];
1210
1211 cnt2 = 0;
1212 for (;;) {
1213 cnt = 0;
1214 printf(_("\n%s login: "), thishost); fflush(stdout);
1215 for (p = nbuf; (ch = getchar()) != '\n'; ) {
1216 if (ch == EOF) {
1217 badlogin("EOF");
1218 exit(0);
1219 }
1220 if (p < nbuf + UT_NAMESIZE)
1221 *p++ = ch;
1222
1223 cnt++;
1224 if (cnt > UT_NAMESIZE + 20) {
1225 fprintf(stderr, _("login name much too long.\n"));
1226 badlogin(_("NAME too long"));
1227 exit(0);
1228 }
1229 }
1230 if (p > nbuf) {
1231 if (nbuf[0] == '-')
1232 fprintf(stderr,
1233 _("login names may not start with '-'.\n"));
1234 else {
1235 *p = '\0';
1236 username = nbuf;
1237 break;
1238 }
1239 }
1240
1241 cnt2++;
1242 if (cnt2 > 50) {
1243 fprintf(stderr, _("too many bare linefeeds.\n"));
1244 badlogin(_("EXCESSIVE linefeeds"));
1245 exit(0);
1246 }
1247 }
1248 }
1249 #endif
1250
1251 void
1252 timedout(int sig) {
1253 struct termio ti;
1254
1255 fprintf(stderr, _("Login timed out after %d seconds\n"), timeout);
1256
1257 /* reset echo */
1258 ioctl(0, TCGETA, &ti);
1259 ti.c_lflag |= ECHO;
1260 ioctl(0, TCSETA, &ti);
1261 exit(0); /* %% */
1262 }
1263
1264 #ifndef USE_PAM
1265 int
1266 rootterm(char * ttyn)
1267 #ifndef __linux__
1268 {
1269 struct ttyent *t;
1270
1271 return((t = getttynam(ttyn)) && (t->ty_status&TTY_SECURE));
1272 }
1273 #else
1274 {
1275 int fd;
1276 char buf[100],*p;
1277 int cnt, more = 0;
1278
1279 fd = open(SECURETTY, O_RDONLY);
1280 if(fd < 0) return 1;
1281
1282 /* read each line in /etc/securetty, if a line matches our ttyline
1283 then root is allowed to login on this tty, and we should return
1284 true. */
1285 for(;;) {
1286 p = buf; cnt = 100;
1287 while(--cnt >= 0 && (more = read(fd, p, 1)) == 1 && *p != '\n') p++;
1288 if(more && *p == '\n') {
1289 *p = '\0';
1290 if(!strcmp(buf, ttyn)) {
1291 close(fd);
1292 return 1;
1293 } else
1294 continue;
1295 } else {
1296 close(fd);
1297 return 0;
1298 }
1299 }
1300 }
1301 #endif /* !__linux__ */
1302 #endif /* !USE_PAM */
1303
1304 jmp_buf motdinterrupt;
1305
1306 void
1307 motd(void) {
1308 int fd, nchars;
1309 void (*oldint)(int);
1310 char tbuf[8192];
1311
1312 if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
1313 return;
1314 oldint = signal(SIGINT, sigint);
1315 if (setjmp(motdinterrupt) == 0)
1316 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
1317 write(fileno(stdout), tbuf, nchars);
1318 signal(SIGINT, oldint);
1319 close(fd);
1320 }
1321
1322 void
1323 sigint(int sig) {
1324 longjmp(motdinterrupt, 1);
1325 }
1326
1327 #ifndef USE_PAM /* PAM takes care of this */
1328 void
1329 checknologin(void) {
1330 int fd, nchars;
1331 char tbuf[8192];
1332
1333 if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
1334 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
1335 write(fileno(stdout), tbuf, nchars);
1336 close(fd);
1337 sleepexit(0);
1338 }
1339 }
1340 #endif
1341
1342 void
1343 dolastlog(int quiet) {
1344 struct lastlog ll;
1345 int fd;
1346
1347 if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
1348 lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
1349 if (!quiet) {
1350 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
1351 ll.ll_time != 0) {
1352 printf(_("Last login: %.*s "),
1353 24-5, (char *)ctime(&ll.ll_time));
1354
1355 if (*ll.ll_host != '\0')
1356 printf(_("from %.*s\n"),
1357 (int)sizeof(ll.ll_host), ll.ll_host);
1358 else
1359 printf(_("on %.*s\n"),
1360 (int)sizeof(ll.ll_line), ll.ll_line);
1361 }
1362 lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET);
1363 }
1364 memset((char *)&ll, 0, sizeof(ll));
1365 time(&ll.ll_time);
1366 xstrncpy(ll.ll_line, tty_name, sizeof(ll.ll_line));
1367 if (hostname)
1368 xstrncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
1369
1370 write(fd, (char *)&ll, sizeof(ll));
1371 close(fd);
1372 }
1373 }
1374
1375 void
1376 badlogin(const char *name) {
1377 if (failures == 1) {
1378 if (hostname)
1379 syslog(LOG_NOTICE, _("LOGIN FAILURE FROM %s, %s"),
1380 hostname, name);
1381 else
1382 syslog(LOG_NOTICE, _("LOGIN FAILURE ON %s, %s"),
1383 tty_name, name);
1384 } else {
1385 if (hostname)
1386 syslog(LOG_NOTICE, _("%d LOGIN FAILURES FROM %s, %s"),
1387 failures, hostname, name);
1388 else
1389 syslog(LOG_NOTICE, _("%d LOGIN FAILURES ON %s, %s"),
1390 failures, tty_name, name);
1391 }
1392 }
1393
1394 #undef UNKNOWN
1395 #define UNKNOWN "su"
1396
1397 #ifndef __linux__
1398 char *
1399 stypeof(char *ttyid) {
1400 struct ttyent *t;
1401
1402 return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
1403 }
1404 #endif
1405
1406 /* Should not be called from PAM code... */
1407 void
1408 sleepexit(int eval) {
1409 sleep(SLEEP_EXIT_TIMEOUT);
1410 exit(eval);
1411 }