1/* 2 * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18#ifndef lint 19char copyright[] = 20"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22#endif /* not lint */ 23 24#ifndef lint 25static char sccsid[] = "@(#)login.c.1 5.28 (Berkeley) 01/15/89"; 26#endif /* not lint */ 27 28/* 29 * login [ name ] 30 * login -h hostname (for telnetd, etc.) 31 * login -f name (for pre-authenticated login: datakit, xterm, etc.) 32 */ 33 34#include <sys/param.h> 35#include <sys/quota.h> 36#include <sys/stat.h> 37#include <sys/time.h> 38#include <sys/resource.h> 39#include <sys/file.h> 40#include <sys/ioctl.h> 41 42#include <utmp.h> 43#include <signal.h> 44#include <lastlog.h> 45#include <errno.h> 46#include <ttyent.h> 47#include <syslog.h> 48#include <grp.h> 49#include <pwd.h> 50#include <setjmp.h> 51#include <stdio.h> 52#include <strings.h> 53 54#define TTYGRPNAME "tty" /* name of group to own ttys */ 55 56#define MOTDFILE "/etc/motd" 57#define MAILDIR "/usr/spool/mail" 58#define NOLOGIN "/etc/nologin" 59#define HUSHLOGIN ".hushlogin" 60#define LASTLOG "/usr/adm/lastlog" 61#define BSHELL "/bin/sh" 62 63/* 64 * This bounds the time given to login. Not a define so it can 65 * be patched on machines where it's too small. 66 */ 67int timeout = 300; 68 69struct passwd *pwd; 70int repeatcnt; 71char term[64], *hostname, *username, *tty; 72 73struct sgttyb sgttyb; 74struct tchars tc = { 75 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 76}; 77struct ltchars ltc = { 78 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 79}; 80 81main(argc, argv) 82 int argc; 83 char **argv; 84{ 85 extern int errno, optind; 86 extern char *optarg, **environ; 87 struct group *gr; 88 register int ch; 89 register char *p; 90 int ask, fflag, hflag, pflag, cnt; 91 int quietlog, passwd_req, ioctlval, timedout(); 92 char *domain, *salt, *envinit[1], *ttyn; 93 char tbuf[MAXPATHLEN + 2]; 94 char *ttyname(), *stypeof(), *crypt(), *getpass(); 95 time_t time(); 96 off_t lseek(); 97 98 (void)signal(SIGALRM, timedout); 99 (void)alarm((u_int)timeout); 100 (void)signal(SIGQUIT, SIG_IGN); 101 (void)signal(SIGINT, SIG_IGN); 102 (void)setpriority(PRIO_PROCESS, 0, 0); 103 (void)quota(Q_SETUID, 0, 0, 0); 104 105 /* 106 * -p is used by getty to tell login not to destroy the environment 107 * -f is used to skip a second login authentication 108 * -h is used by other servers to pass the name of the remote 109 * host to login so that it may be placed in utmp and wtmp 110 */ 111 (void)gethostname(tbuf, sizeof(tbuf)); 112 domain = index(tbuf, '.'); 113 114 fflag = hflag = pflag = 0; 115 passwd_req = 1; 116 while ((ch = getopt(argc, argv, "fh:p")) != EOF) 117 switch (ch) { 118 case 'f': 119 fflag = 1; 120 break; 121 case 'h': 122 if (getuid()) { 123 fprintf(stderr, 124 "login: -h for super-user only.\n"); 125 exit(1); 126 } 127 hflag = 1; 128 if (domain && (p = index(optarg, '.')) && 129 strcasecmp(p, domain) == 0) 130 *p = 0; 131 hostname = optarg; 132 break; 133 case 'p': 134 pflag = 1; 135 break; 136 case '?': 137 default: 138 fprintf(stderr, "usage: login [-fp] [username]\n"); 139 exit(1); 140 } 141 argc -= optind; 142 argv += optind; 143 if (*argv) { 144 ask = 0; 145 username = *argv; 146 } 147 else 148 ask = 1; 149 150 ioctlval = 0; 151 (void)ioctl(0, TIOCLSET, &ioctlval); 152 (void)ioctl(0, TIOCNXCL, 0); 153 (void)fcntl(0, F_SETFL, ioctlval); 154 (void)ioctl(0, TIOCGETP, &sgttyb); 155 sgttyb.sg_erase = CERASE; 156 sgttyb.sg_kill = CKILL; 157 (void)ioctl(0, TIOCSLTC, <c); 158 (void)ioctl(0, TIOCSETC, &tc); 159 (void)ioctl(0, TIOCSETP, &sgttyb); 160 161 for (cnt = getdtablesize(); cnt > 2; cnt--) 162 close(cnt); 163 164 ttyn = ttyname(0); 165 if (ttyn == NULL || *ttyn == '\0') 166 ttyn = "/dev/tty??"; 167 if (tty = rindex(ttyn, '/')) 168 ++tty; 169 else 170 tty = ttyn; 171 172 openlog("login", LOG_ODELAY, LOG_AUTH); 173 174 for (cnt = 0;; ask = 1) { 175 ioctlval = 0; 176 (void)ioctl(0, TIOCSETD, &ioctlval); 177 178 if (ask) { 179 fflag = 0; 180 getloginname(); 181 } 182 /* note if trying multiple login's */ 183 if (repeatcnt) { 184 if (strcmp(tbuf, username)) { 185 badlogin(tbuf); 186 repeatcnt = 1; 187 (void)strcpy(tbuf, username); 188 } 189 else 190 ++repeatcnt; 191 } 192 else { 193 repeatcnt = 1; 194 (void)strcpy(tbuf, username); 195 } 196 if (pwd = getpwnam(username)) 197 salt = pwd->pw_passwd; 198 else 199 salt = "xx"; 200 201 /* if user not super-user, check for disabled logins */ 202 if (pwd == NULL || pwd->pw_uid) 203 checknologin(); 204 205 /* 206 * Disallow automatic login to root; if not invoked by 207 * root, disallow if the uid's differ. 208 */ 209 if (fflag && pwd) { 210 int uid = getuid(); 211 212 passwd_req = pwd->pw_uid == 0 || 213 (uid && uid != pwd->pw_uid); 214 } 215 216 /* 217 * If no pre-authentication and a password exists 218 * for this user, prompt for one and verify it. 219 */ 220 if (!passwd_req || pwd && !*pwd->pw_passwd) 221 break; 222 223 setpriority(PRIO_PROCESS, 0, -4); 224 p = crypt(getpass("Password:"), salt); 225 setpriority(PRIO_PROCESS, 0, 0); 226 if (pwd && !strcmp(p, pwd->pw_passwd)) 227 break; 228 229 printf("Login incorrect\n"); 230 /* we allow 10 tries, but after 3 we start backing off */ 231 if (++cnt > 3) { 232 if (cnt >= 10) { 233 badlogin(username); 234 (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 235 sleepexit(1); 236 } 237 sleep((u_int)((cnt - 3) * 5)); 238 } 239 } 240 241 /* committed to login -- turn off timeout */ 242 (void)alarm((u_int)0); 243 244 /* log any mistakes -- don't count last one */ 245 --repeatcnt; 246 badlogin(username); 247 248 /* 249 * If valid so far and root is logging in, see if root logins on 250 * this terminal are permitted. 251 */ 252 if (pwd->pw_uid == 0 && !rootterm()) { 253 if (hostname) 254 syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %s", 255 tty, hostname); 256 else 257 syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty); 258 printf("Login incorrect\n"); 259 sleepexit(1); 260 } 261 262 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 263 switch(errno) { 264 case EUSERS: 265 fprintf(stderr, 266 "Too many users logged on already.\nTry again later.\n"); 267 break; 268 case EPROCLIM: 269 fprintf(stderr, 270 "You have too many processes running.\n"); 271 break; 272 default: 273 perror("quota (Q_SETUID)"); 274 } 275 sleepexit(0); 276 } 277 278 if (chdir(pwd->pw_dir) < 0) { 279 printf("No directory %s!\n", pwd->pw_dir); 280 if (chdir("/")) 281 exit(0); 282 pwd->pw_dir = "/"; 283 printf("Logging in with home = \"/\".\n"); 284 } 285 286 /* nothing else left to fail -- really log in */ 287 { 288 struct utmp utmp; 289 290 (void)time(&utmp.ut_time); 291 strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 292 strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 293 strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 294 login(&utmp); 295 } 296 297 quietlog = access(HUSHLOGIN, F_OK) == 0; 298 dolastlog(quietlog); 299 300 if (!hflag) { /* XXX */ 301 static struct winsize win = { 0, 0, 0, 0 }; 302 303 (void)ioctl(0, TIOCSWINSZ, &win); 304 } 305 306 (void)chown(ttyn, pwd->pw_uid, 307 (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 308 (void)chmod(ttyn, 0620); 309 (void)setgid(pwd->pw_gid); 310 311 initgroups(username, pwd->pw_gid); 312 313 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 314 (void)setuid(pwd->pw_uid); 315 316 if (*pwd->pw_shell == '\0') 317 pwd->pw_shell = BSHELL; 318 /* turn on new line discipline for the csh */ 319 else if (!strcmp(pwd->pw_shell, "/bin/csh")) { 320 ioctlval = NTTYDISC; 321 (void)ioctl(0, TIOCSETD, &ioctlval); 322 } 323 324 /* destroy environment unless user has requested preservation */ 325 if (!pflag) 326 environ = envinit; 327 (void)setenv("HOME", pwd->pw_dir, 1); 328 (void)setenv("SHELL", pwd->pw_shell, 1); 329 if (term[0] == '\0') 330 strncpy(term, stypeof(), sizeof(term)); 331 (void)setenv("TERM", term, 0); 332 (void)setenv("USER", pwd->pw_name, 1); 333 (void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0); 334 335 if (tty[sizeof("tty")-1] == 'd') 336 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 337 if (pwd->pw_uid == 0) 338 if (hostname) 339 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %s", 340 tty, hostname); 341 else 342 syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); 343 344 if (!quietlog) { 345 struct stat st; 346 347 motd(); 348 (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name); 349 if (stat(tbuf, &st) == 0 && st.st_size != 0) 350 printf("You have %smail.\n", 351 (st.st_mtime > st.st_atime) ? "new " : ""); 352 } 353 354 (void)signal(SIGALRM, SIG_DFL); 355 (void)signal(SIGQUIT, SIG_DFL); 356 (void)signal(SIGINT, SIG_DFL); 357 (void)signal(SIGTSTP, SIG_IGN); 358 359 tbuf[0] = '-'; 360 strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 361 p + 1 : pwd->pw_shell); 362 execlp(pwd->pw_shell, tbuf, 0); 363 fprintf(stderr, "login: no shell: "); 364 perror(pwd->pw_shell); 365 exit(0); 366} 367 368getloginname() 369{ 370 register int ch; 371 register char *p; 372 static char nbuf[UT_NAMESIZE + 1]; 373 374 for (;;) { 375 printf("login: "); 376 for (p = nbuf; (ch = getchar()) != '\n'; ) { 377 if (ch == EOF) { 378 badlogin(username); 379 exit(0); 380 } 381 if (p < nbuf + UT_NAMESIZE) 382 *p++ = ch; 383 } 384 if (p > nbuf) 385 if (nbuf[0] == '-') 386 fprintf(stderr, 387 "login names may not start with '-'.\n"); 388 else { 389 *p = '\0'; 390 username = nbuf; 391 break; 392 } 393 } 394} 395 396timedout() 397{ 398 fprintf(stderr, "Login timed out after %d seconds\n", timeout); 399 exit(0); 400} 401 402rootterm() 403{ 404 struct ttyent *t; 405 406 return((t = getttynam(tty)) && t->ty_status&TTY_SECURE); 407} 408 409jmp_buf motdinterrupt; 410 411motd() 412{ 413 register int fd, nchars; 414 int (*oldint)(), sigint(); 415 char tbuf[8192]; 416 417 if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0) 418 return; 419 oldint = signal(SIGINT, sigint); 420 if (setjmp(motdinterrupt) == 0) 421 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 422 (void)write(fileno(stdout), tbuf, nchars); 423 (void)signal(SIGINT, oldint); 424 (void)close(fd); 425} 426 427sigint() 428{ 429 longjmp(motdinterrupt, 1); 430} 431 432checknologin() 433{ 434 register int fd, nchars; 435 char tbuf[8192]; 436 437 if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) { 438 while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 439 (void)write(fileno(stdout), tbuf, nchars); 440 sleepexit(0); 441 } 442} 443 444dolastlog(quiet) 445 int quiet; 446{ 447 struct lastlog ll; 448 int fd; 449 450 if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) { 451 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 452 if (!quiet) { 453 if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 454 ll.ll_time != 0) { 455 printf("Last login: %.*s ", 456 24-5, (char *)ctime(&ll.ll_time)); 457 if (*ll.ll_host != '\0') 458 printf("from %.*s\n", 459 sizeof(ll.ll_host), ll.ll_host); 460 else 461 printf("on %.*s\n", 462 sizeof(ll.ll_line), ll.ll_line); 463 } 464 (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 465 } 466 (void)time(&ll.ll_time); 467 strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 468 strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 469 (void)write(fd, (char *)&ll, sizeof(ll)); 470 (void)close(fd); 471 } 472} 473 474badlogin(name) 475 char *name; 476{ 477 if (!repeatcnt) 478 return; 479 if (hostname) 480 syslog(LOG_ERR, "%d LOGIN FAILURE%s ON %s FROM %s, %s", 481 repeatcnt, repeatcnt > 1 ? "S" : "", tty, hostname, name); 482 else 483 syslog(LOG_ERR, "%d LOGIN FAILURE%s ON %s, %s", 484 repeatcnt, repeatcnt > 1 ? "S" : "", tty, name); 485} 486 487#undef UNKNOWN 488#define UNKNOWN "su" 489 490char * 491stypeof() 492{ 493 struct ttyent *t; 494 495 return(tty && (t = getttynam(tty)) ? t->ty_type : UNKNOWN); 496} 497 498getstr(buf, cnt, err) 499 char *buf, *err; 500 int cnt; 501{ 502 char ch; 503 504 do { 505 if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 506 exit(1); 507 if (--cnt < 0) { 508 fprintf(stderr, "%s too long\r\n", err); 509 sleepexit(1); 510 } 511 *buf++ = ch; 512 } while (ch); 513} 514 515sleepexit(eval) 516 int eval; 517{ 518 sleep((u_int)5); 519 exit(eval); 520} 521