📄 login.c
字号:
int wtmp; if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { write(wtmp, (char *)&ut, sizeof(ut)); close(wtmp); } }#else /* Probably all this locking below is just nonsense, and the short version is OK as well. */ { int lf, wtmp; if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { flock(lf, LOCK_EX); if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { write(wtmp, (char *)&ut, sizeof(ut)); close(wtmp); } flock(lf, LOCK_UN); close(lf); } }#endif#endif } dolastlog(quietlog); chown(ttyn, pwd->pw_uid, (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); chmod(ttyn, TTY_MODE);#ifdef CHOWNVCS /* if tty is one of the VC's then change owner and mode of the special /dev/vcs devices as well */ if (consoletty(0)) { chown(vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid)); chown(vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid)); chmod(vcsn, TTY_MODE); chmod(vcsan, TTY_MODE); }#endif setgid(pwd->pw_gid); #ifdef HAVE_QUOTA quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);#endif if (*pwd->pw_shell == '\0') pwd->pw_shell = _PATH_BSHELL; /* preserve TERM even without -p flag */ { char *ep; if(!((ep = getenv("TERM")) && (termenv = strdup(ep)))) termenv = "dumb"; } /* destroy environment unless user has requested preservation */ if (!pflag) { environ = (char**)malloc(sizeof(char*)); memset(environ, 0, sizeof(char*)); } setenv("HOME", pwd->pw_dir, 0); /* legal to override */ if(pwd->pw_uid) setenv("PATH", _PATH_DEFPATH, 1); else setenv("PATH", _PATH_DEFPATH_ROOT, 1); setenv("SHELL", pwd->pw_shell, 1); setenv("TERM", termenv, 1); /* mailx will give a funny error msg if you forget this one */ { char tmp[MAXPATHLEN]; /* avoid snprintf */ if (sizeof(_PATH_MAILDIR) + strlen(pwd->pw_name) + 1 < MAXPATHLEN) { sprintf(tmp, "%s/%s", _PATH_MAILDIR, pwd->pw_name); setenv("MAIL",tmp,0); } } /* LOGNAME is not documented in login(1) but HP-UX 6.5 does it. We'll not allow modifying it. */ setenv("LOGNAME", pwd->pw_name, 1);#ifdef USE_PAM { int i; char ** env = pam_getenvlist(pamh); if (env != NULL) { for (i=0; env[i]; i++) { putenv(env[i]); /* D(("env[%d] = %s", i,env[i])); */ } } }#endif#ifdef DO_PS_FIDDLING setproctitle("login", username);#endif if (!strncmp(tty_name, "ttyS", 4)) syslog(LOG_INFO, _("DIALUP AT %s BY %s"), tty_name, pwd->pw_name); /* allow tracking of good logins. -steve philp (sphilp@mail.alliance.net) */ if (pwd->pw_uid == 0) { if (hostname) syslog(LOG_NOTICE, _("ROOT LOGIN ON %s FROM %s"), tty_name, hostname); else syslog(LOG_NOTICE, _("ROOT LOGIN ON %s"), tty_name); } else { if (hostname) syslog(LOG_INFO, _("LOGIN ON %s BY %s FROM %s"), tty_name, pwd->pw_name, hostname); else syslog(LOG_INFO, _("LOGIN ON %s BY %s"), tty_name, pwd->pw_name); } if (!quietlog) { motd();#ifdef DO_STAT_MAIL /* * This turns out to be a bad idea: when the mail spool * is NFS mounted, and the NFS connection hangs, the * login hangs, even root cannot login. * Checking for mail should be done from the shell. */ { struct stat st; char *mail; mail = getenv("MAIL"); if (mail && stat(mail, &st) == 0 && st.st_size != 0) { if (st.st_mtime > st.st_atime) printf(_("You have new mail.\n")); else printf(_("You have mail.\n")); } }#endif } signal(SIGALRM, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTSTP, SIG_IGN);#ifdef USE_PAM /* * We must fork before setuid() because we need to call * pam_close_session() as root. */ childPid = fork(); if (childPid < 0) { int errsv = errno; /* error in fork() */ fprintf(stderr, _("login: failure forking: %s"), strerror(errsv)); PAM_END; exit(0); } if (childPid) { /* parent - wait for child to finish, then cleanup session */ signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); wait(NULL); PAM_END; exit(0); } /* child */ /* * Problem: if the user's shell is a shell like ash that doesnt do * setsid() or setpgrp(), then a ctrl-\, sending SIGQUIT to every * process in the pgrp, will kill us. */ /* start new session */ setsid(); /* make sure we have a controlling tty */ opentty(ttyn); openlog("login", LOG_ODELAY, LOG_AUTHPRIV); /* reopen */ /* * TIOCSCTTY: steal tty from other process group. */ if (ioctl(0, TIOCSCTTY, 1)) syslog(LOG_ERR, _("TIOCSCTTY failed: %m"));#endif signal(SIGINT, SIG_DFL); /* discard permissions last so can't get killed and drop core */ if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) { syslog(LOG_ALERT, _("setuid() failed")); exit(1); } /* wait until here to change directory! */ if (chdir(pwd->pw_dir) < 0) { printf(_("No directory %s!\n"), pwd->pw_dir); if (chdir("/")) exit(0); pwd->pw_dir = "/"; printf(_("Logging in with home = \"/\".\n")); } /* if the shell field has a space: treat it like a shell script */ if (strchr(pwd->pw_shell, ' ')) { buff = malloc(strlen(pwd->pw_shell) + 6); if (!buff) { fprintf(stderr, _("login: no memory for shell script.\n")); exit(0); } strcpy(buff, "exec "); strcat(buff, pwd->pw_shell); childArgv[childArgc++] = "/bin/sh"; childArgv[childArgc++] = "-sh"; childArgv[childArgc++] = "-c"; childArgv[childArgc++] = buff; } else { tbuf[0] = '-'; xstrncpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ? p + 1 : pwd->pw_shell), sizeof(tbuf)-1); childArgv[childArgc++] = pwd->pw_shell; childArgv[childArgc++] = tbuf; } childArgv[childArgc++] = NULL; execvp(childArgv[0], childArgv + 1); errsv = errno; if (!strcmp(childArgv[0], "/bin/sh")) fprintf(stderr, _("login: couldn't exec shell script: %s.\n"), strerror(errsv)); else fprintf(stderr, _("login: no shell: %s.\n"), strerror(errsv)); exit(0);}#ifndef USE_PAMstatic voidgetloginname(void) { int ch, cnt, cnt2; char *p; static char nbuf[UT_NAMESIZE + 1]; cnt2 = 0; for (;;) { cnt = 0; printf(_("\n%s login: "), thishost); fflush(stdout); for (p = nbuf; (ch = getchar()) != '\n'; ) { if (ch == EOF) { badlogin("EOF"); exit(0); } if (p < nbuf + UT_NAMESIZE) *p++ = ch; cnt++; if (cnt > UT_NAMESIZE + 20) { fprintf(stderr, _("login name much too long.\n")); badlogin(_("NAME too long")); exit(0); } } if (p > nbuf) { if (nbuf[0] == '-') fprintf(stderr, _("login names may not start with '-'.\n")); else { *p = '\0'; username = nbuf; break; } } cnt2++; if (cnt2 > 50) { fprintf(stderr, _("too many bare linefeeds.\n")); badlogin(_("EXCESSIVE linefeeds")); exit(0); } }}#endif/* * Robert Ambrose writes: * A couple of my users have a problem with login processes hanging around * soaking up pts's. What they seem to hung up on is trying to write out the * message 'Login timed out after %d seconds' when the connection has already * been dropped. * What I did was add a second timeout while trying to write the message so * the process just exits if the second timeout expires. */static voidtimedout2(int sig) { struct termio ti; /* reset echo */ ioctl(0, TCGETA, &ti); ti.c_lflag |= ECHO; ioctl(0, TCSETA, &ti); exit(0); /* %% */}static voidtimedout(int sig) { signal(SIGALRM, timedout2); alarm(10); fprintf(stderr, _("Login timed out after %d seconds\n"), timeout); signal(SIGALRM, SIG_IGN); alarm(0); timedout2(0);}#ifndef USE_PAMintrootterm(char * ttyn){ int fd; char buf[100],*p; int cnt, more = 0; fd = open(SECURETTY, O_RDONLY); if(fd < 0) return 1; /* read each line in /etc/securetty, if a line matches our ttyline then root is allowed to login on this tty, and we should return true. */ for(;;) { p = buf; cnt = 100; while(--cnt >= 0 && (more = read(fd, p, 1)) == 1 && *p != '\n') p++; if(more && *p == '\n') { *p = '\0'; if(!strcmp(buf, ttyn)) { close(fd); return 1; } else continue; } else { close(fd); return 0; } }}#endif /* !USE_PAM */jmp_buf motdinterrupt;voidmotd(void) { int fd, nchars; void (*oldint)(int); char tbuf[8192]; if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) return; oldint = signal(SIGINT, sigint); if (setjmp(motdinterrupt) == 0) while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) write(fileno(stdout), tbuf, nchars); signal(SIGINT, oldint); close(fd);}voidsigint(int sig) { longjmp(motdinterrupt, 1);}#ifndef USE_PAM /* PAM takes care of this */voidchecknologin(void) { int fd, nchars; char tbuf[8192]; if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) write(fileno(stdout), tbuf, nchars); close(fd); sleepexit(0); }}#endifvoiddolastlog(int quiet) { struct lastlog ll; int fd; if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); if (!quiet) { if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) { time_t ll_time = (time_t) ll.ll_time; printf(_("Last login: %.*s "), 24-5, ctime(&ll_time)); if (*ll.ll_host != '\0') printf(_("from %.*s\n"), (int)sizeof(ll.ll_host), ll.ll_host); else printf(_("on %.*s\n"), (int)sizeof(ll.ll_line), ll.ll_line); } lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); } memset((char *)&ll, 0, sizeof(ll)); time(&ll.ll_time); xstrncpy(ll.ll_line, tty_name, sizeof(ll.ll_line)); if (hostname) xstrncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); write(fd, (char *)&ll, sizeof(ll)); close(fd); }}voidbadlogin(const char *name) { if (failures == 1) { if (hostname) syslog(LOG_NOTICE, _("LOGIN FAILURE FROM %s, %s"), hostname, name); else syslog(LOG_NOTICE, _("LOGIN FAILURE ON %s, %s"), tty_name, name); } else { if (hostname) syslog(LOG_NOTICE, _("%d LOGIN FAILURES FROM %s, %s"), failures, hostname, name); else syslog(LOG_NOTICE, _("%d LOGIN FAILURES ON %s, %s"), failures, tty_name, name); }}/* Should not be called from PAM code... */voidsleepexit(int eval) { sleep(SLEEP_EXIT_TIMEOUT); exit(eval);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -