/* * login [ -f name ] [ -p passwdline ] [ command ] * -f: if su, log in with no password * -p: if su, use entire password line. * command: if given, just execute command */ #include <sys/param.h> #include <sys/ttyio.h> #include <utmp.h> #include <signal.h> #include <setjmp.h> #include <pwd.h> #include <grp.h> #include <stdio.h> #include <sys/stat.h> #include <sys/lnode.h> #include <sys/share.h> #include <shares.h> #include <errno.h> #define DEFSHARES 1 /* Default number of shares for a group 0 user */ #define SYSERROR (-1) #define MINUSAGE 1e6 #ifndef ETOOMANYU #define ETOOMANYU ENOSPC /* Must go in errno.h or lnode.h */ #endif #define SCPYN(a, b) strncpy(a, b, sizeof(a)) #define ISIZE 32 #define POSTMKSIZ sizeof "From Sun Jan 00 00:00:00 1979" char maildir[30] = "/usr/spool/mail/"; struct passwd nouser = {"", "nope"}; struct utmp utmp; char minusnam[16] = "-"; char homedir[64] = "HOME="; char path[] = "PATH=:/bin:/usr/bin"; char **env; int nenv = 0; char nolog[] = "/etc/nologin"; struct passwd *pwd; struct passwd *pwdecode(); char *cmd; struct passwd *getpwnam(); char *strcat(); int setpwent(); char *ttyname(); char *crypt(); char *getpass(); char *strrchr(), *strchr(); extern char **environ; main(argc, argv) char **argv; { register char *namep; char input[ISIZE]; char pwline[128]; int t, f, c; char *ttyn; int neednopass = 0; int hangitup = 0; int ntries = 0; FILE *nlfd; int i; struct ttydevb tb; alarm(60); signal(SIGQUIT, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGHUP, SIG_IGN); nice(-100); nice(20); nice(0); #define ONOFILE 20 for (t=NSYSFILE; t<ONOFILE; t++) close(t); ttyn = ttyname(0); if (ttyn==0) ttyn = "/dev/tty??"; SCPYN(input, ""); switch(argc) { case 0: case 1: break; case 2: SCPYN(input, argv[1]); break; default: if (strcmp(argv[1], "-f")==0 || strcmp(argv[1], "-p")==0) { if (getuid()!=0) { printf("login: not super-user\n"); exit(1); } neednopass++; if (strcmp(argv[1], "-f")==0) SCPYN(input, argv[2]); else { SCPYN(pwline, argv[2]); pwd = pwdecode(pwline); SCPYN(input, pwd->pw_name); } if (argc>3) cmd = argv[3]; } else exit(1); } loop: if (ntries) { if (ntries > 5 || hangitup) { ioctl(0, TIOCGDEV, &tb); tb.ispeed = tb.ospeed = 0; ioctl(0, TIOCSDEV, &tb); sleep(5); exit(1); } neednopass = 0; pwd = NULL; SCPYN(input, ""); } ntries++; while (input[0] == '\0') { namep = input; printf("login: "); while ((c = getchar()) != '\n') { if(c == ' ') c = '_'; if (c == EOF) exit(0); if (namep < input + ISIZE - 1) *namep++ = c; } *namep = NULL; } SCPYN(utmp.ut_name, input); utmp.ut_time = 0; if (pwd == NULL) { setpwent(); if ((pwd = getpwnam(input)) == NULL) pwd = &nouser; endpwent(); } if (namep = strchr(utmp.ut_name, '\001')) if (namep[1]=='L' && namep[2]=='\002') /* loopback? */ hangitup++; time(&utmp.ut_time); SCPYN(utmp.ut_line, strchr(ttyn+1, '/')+1); if (*pwd->pw_passwd != '\0' && !neednopass) { namep = crypt(getpass("Password:"), pwd->pw_passwd); if (strcmp(namep, pwd->pw_passwd)) { /* magic string detects loopbacks */ printf("\001L\002ogin incorrect\n"); f = open("/usr/adm/xtmp", 1); if (f > 0) { lseek(f, 0L, 2); write(f, (char *)&utmp, sizeof(utmp)); close(f); } goto loop; } } if(pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) != NULL){ while((c = getc(nlfd)) != EOF) putchar(c); exit(0); } if(setuplimits(pwd) < 0) goto loop; (void)setupgroups(pwd); if(chdir(pwd->pw_dir) < 0) { printf("No directory\n"); if(pwd->pw_uid != 0 || (access(nolog, 0) < 0)) goto loop; } setlogname(utmp.ut_name); if (cmd) { /* remote exec */ t = strlen(utmp.ut_name); if (t < sizeof(utmp.ut_name)) utmp.ut_name[t] = '*'; } t = ttyslot(); if (t>0 && (f = open("/etc/utmp", 1)) >= 0) { lseek(f, (long)(t*sizeof(utmp)), 0); write(f, (char *)&utmp, sizeof(utmp)); close(f); } if (t>0 && (f = open("/usr/adm/wtmp", 1)) >= 0) { lseek(f, 0L, 2); write(f, (char *)&utmp, sizeof(utmp)); close(f); } chown(ttyn, pwd->pw_uid, pwd->pw_gid); chmod(ttyn, 0622); setgid(pwd->pw_gid); setuid(pwd->pw_uid); if (*pwd->pw_shell == '\0') pwd->pw_shell = "/bin/sh"; strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); nenv = 0; for(i = 0; environ[i]; i++) ; env = (char **) malloc(sizeof(char *) * (i + 10)); if (env == NULL) { printf("No memory for environment.\n"); exit(1); } for (i = 0; environ[i]; i++) { if (strncmp(environ[i], "HOME=", 5) == 0) continue; if (strncmp(environ[i], "PATH=", 5) == 0) continue; env[nenv++] = environ[i]; } if(homedir[0]) env[nenv++] = homedir; if(path[0]) env[nenv++] = path; env[nenv] = NULL; if ((namep = strrchr(pwd->pw_shell, '/')) == NULL) namep = pwd->pw_shell; else namep++; strcat(minusnam, namep); alarm(0); umask(02); if (cmd==NULL) { showmotd(); strcat(maildir, pwd->pw_name); if(access(maildir,4)==0) { struct stat statb; stat(maildir, &statb); if (statb.st_size > POSTMKSIZ) printf("You have mail.\n"); } } signal(SIGQUIT, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGHUP, SIG_DFL); environ = env; if (cmd==NULL) execlp(pwd->pw_shell, minusnam, 0); else { env[nenv++] = "REXEC=1"; ioctl(0, TIOCEXCL, (void *)NULL); env[nenv] = 0; execlp(pwd->pw_shell, minusnam, "-c", cmd, (char *)0); } printf("No shell\n"); exit(0); } int stopmotd; catch() { signal(SIGINT, SIG_IGN); stopmotd++; } showmotd() { FILE *mf; register c; signal(SIGINT, catch); if((mf = fopen("/etc/motd","r")) != NULL) { while((c = getc(mf)) != EOF && stopmotd == 0) putchar(c); fclose(mf); } signal(SIGINT, SIG_IGN); } /* ** Set up parameters for share scheduler */ int catchsys(); jmp_buf Sigsysbuf; int setuplimits(pwd) register struct passwd *pwd; { register int (*oldsig)(); register unsigned long extime; struct sh_consts shconsts; struct lnode share; if ( pwd->pw_uid == 0 ) return 0; /* root needs no set-up */ oldsig = signal(SIGSYS, catchsys); if ( setjmp(Sigsysbuf) || limits((struct lnode *)&shconsts, L_GETCOSTS) == SYSERROR || (Shareflags & NOSHARE) ) { (void)signal(SIGSYS, oldsig); return 0; /* Share not installed/active */ } (void)signal(SIGSYS, oldsig); if ( (extime = getshares(&share, pwd->pw_uid, 0)) == 0 ) { share.l_shares = DEFSHARES; share.l_usage = MINUSAGE; } else if ( limits(&share, L_OTHLIM) == SYSERROR ) { /* ** Decay usage by time since last access. */ if ( (extime = (utmp.ut_time - extime) / Delta) > 0 ) { extern double pow(); share.l_usage *= pow(DecayUsage, (float)extime); if ( share.l_usage < MINUSAGE ) share.l_usage = MINUSAGE; } } if ( setlimits(&share) == SYSERROR ) { if ( errno == ETOOMANYU ) { char * cp = "other"; share.l_uid = OTHERUID; if ( limits(&share, L_OTHLIM) != SYSERROR ) (void)setlimits(&share); else cp = "root"; printf("Warning: system out of share structures, using \"%s\".\n", cp); } else perror("setlimits"); } closeshares(); return 0; } int catchsys(sig) { longjmp(Sigsysbuf, 1); perror("longjmp"); abort(); } /* ** Set up access groups. */ int setupgroups(pwd) register struct passwd *pwd; { register char ** cpp; register short * gp; register struct group * grp; register int n; short groups[NGROUPS]; if ( getgroups(NGROUPS, groups) == SYSERROR ) return; /* Not installed */ (void)setgrent(); gp = groups; while ( gp < &groups[NGROUPS] && (grp = getgrent()) != (struct group *)0 ) for ( cpp = grp->gr_mem ; *cpp != (char *)0 ; cpp++ ) if ( strcmp(*cpp, pwd->pw_name) == 0 && grp->gr_gid != pwd->pw_gid ) { *gp++ = grp->gr_gid; break; } (void)endgrent(); if ( (n = gp-groups) == 0 ) return; if ( setgroups(n, groups) == SYSERROR ) perror("setgroups"); }