📄 sys_term.c
字号:
request.signal = SIGCLD; request.pid = getpid();#endif#ifdef BFTPDAEMON /* * Are we working as the bftp daemon? */ if (bftpd) { SCPYN(request.exec_name, BFTPPATH); }#endif /* BFTPDAEMON */ if (write(i, (char *)&request, sizeof(request)) < 0) { char tbuf[128]; (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); fatalperror(net, tbuf); } (void) close(i); (void) signal(SIGALRM, nologinproc); for (i = 0; ; i++) { char tbuf[128]; alarm(15); n = read(pty, ptyip, BUFSIZ); if (i == 3 || n >= 0 || !gotalarm) break; gotalarm = 0; sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line); (void) write(net, tbuf, strlen(tbuf)); } if (n < 0 && gotalarm) fatal(net, "/etc/init didn't start login process"); pcc += n; alarm(0); (void) signal(SIGALRM, SIG_DFL); return;#endif /* NEWINIT */}char *envinit[3];extern char **environ; voidinit_env(){ extern char *getenv(); char **envp; envp = envinit; if (*envp = getenv("TZ")) *envp++ -= 3;#if defined(CRAY) || defined(__hpux) else *envp++ = "TZ=GMT0";#endif *envp = 0; environ = envinit;}#ifndef NEWINIT/* * start_login(host) * * Assuming that we are now running as a child processes, this * function will turn us into the login process. */ voidstart_login(host, autologin, name) char *host; int autologin; char *name;{ register char *cp; register char **argv; char **addarg(); extern char *getenv();#ifdef UTMPX register int pid = getpid(); struct utmpx utmpx;#endif#ifdef SOLARIS char *term; char termbuf[64];#endif#ifdef UTMPX /* * Create utmp entry for child */ bzero(&utmpx, sizeof(utmpx)); SCPYN(utmpx.ut_user, ".telnet"); SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); utmpx.ut_pid = pid; utmpx.ut_id[0] = 't'; utmpx.ut_id[1] = 'n'; utmpx.ut_id[2] = SC_WILDC; utmpx.ut_id[3] = SC_WILDC; utmpx.ut_type = LOGIN_PROCESS; (void) time(&utmpx.ut_tv.tv_sec); if (makeutx(&utmpx) == NULL) fatal(net, "makeutx failed");#endif /* * -h : pass on name of host. * WARNING: -h is accepted by login if and only if * getuid() == 0. * -p : don't clobber the environment (so terminal type stays set). * * -f : force this login, he has already been authenticated */ argv = addarg(0, "login");#if !defined(NO_LOGIN_H)# if defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) /* * Don't add the "-h host" option if we are going * to be adding the "-r host" option down below... */ if ((auth_level < 0) || (autologin != AUTH_VALID))# endif { argv = addarg(argv, "-h"); argv = addarg(argv, host);#ifdef SOLARIS /* * SVR4 version of -h takes TERM= as second arg, or - */ term = getenv("TERM"); if (term == NULL || term[0] == 0) { term = "-"; } else { strcpy(termbuf, "TERM="); strncat(termbuf, term, sizeof(termbuf) - 6); term = termbuf; } argv = addarg(argv, term);#endif }#endif#if !defined(NO_LOGIN_P) argv = addarg(argv, "-p");#endif#ifdef BFTPDAEMON /* * Are we working as the bftp daemon? If so, then ask login * to start bftp instead of shell. */ if (bftpd) { argv = addarg(argv, "-e"); argv = addarg(argv, BFTPPATH); } else #endif#if defined (SecurID) /* * don't worry about the -f that might get sent. * A -s is supposed to override it anyhow. */ if (require_SecurID) argv = addarg(argv, "-s");#endif#if defined (AUTHENTICATION) if (auth_level >= 0 && autologin == AUTH_VALID) {# if !defined(NO_LOGIN_F) argv = addarg(argv, "-f"); argv = addarg(argv, name);# else# if defined(LOGIN_R) /* * We don't have support for "login -f", but we * can fool /bin/login into thinking that we are * rlogind, and allow us to log in without a * password. The rlogin protocol expects * local-user\0remote-user\0term/speed\0 */ if (pty > 2) { register char *cp; char speed[128]; int isecho, israw, xpty, len; extern int def_rspeed;# ifndef LOGIN_HOST /* * Tell login that we are coming from "localhost". * If we passed in the real host name, then the * user would have to allow .rhost access from * every machine that they want authenticated * access to work from, which sort of defeats * the purpose of an authenticated login... * So, we tell login that the session is coming * from "localhost", and the user will only have * to have "localhost" in their .rhost file. */# define LOGIN_HOST "localhost"# endif argv = addarg(argv, "-r"); argv = addarg(argv, LOGIN_HOST); xpty = pty;# ifndef STREAMSPTY pty = 0;# else ttyfd = 0;# endif init_termbuf(); isecho = tty_isecho(); israw = tty_israw(); if (isecho || !israw) { tty_setecho(0); /* Turn off echo */ tty_setraw(1); /* Turn on raw */ set_termbuf(); } len = strlen(name)+1; write(xpty, name, len); write(xpty, name, len); sprintf(speed, "%s/%d", (cp = getenv("TERM")) ? cp : "", (def_rspeed > 0) ? def_rspeed : 9600); len = strlen(speed)+1; write(xpty, speed, len); if (isecho || !israw) { init_termbuf(); tty_setecho(isecho); tty_setraw(israw); set_termbuf(); if (!israw) { /* * Write a newline to ensure * that login will be able to * read the line... */ write(xpty, "\n", 1); } } pty = xpty; }# else argv = addarg(argv, name);# endif# endif } else#endif if (getenv("USER")) { argv = addarg(argv, getenv("USER"));#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P) { register char **cpp; for (cpp = environ; *cpp; cpp++) argv = addarg(argv, *cpp); }#endif /* * Assume that login will set the USER variable * correctly. For SysV systems, this means that * USER will no longer be set, just LOGNAME by * login. (The problem is that if the auto-login * fails, and the user then specifies a different * account name, he can get logged in with both * LOGNAME and USER in his environment, but the * USER value will be wrong. */ unsetenv("USER"); }#if defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R) if (pty > 2) close(pty);#endif closelog(); execv(_PATH_LOGIN, argv); syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); fatalperror(net, _PATH_LOGIN); /*NOTREACHED*/} char **addarg(argv, val) register char **argv; register char *val;{ register char **cpp; if (argv == NULL) { /* * 10 entries, a leading length, and a null */ argv = (char **)malloc(sizeof(*argv) * 12); if (argv == NULL) return(NULL); *argv++ = (char *)10; *argv = (char *)0; } for (cpp = argv; *cpp; cpp++) ; if (cpp == &argv[(int)argv[-1]]) { --argv; *argv = (char *)((int)(*argv) + 10); argv = (char **)realloc(argv, (int)(*argv) + 2); if (argv == NULL) return(NULL); argv++; cpp = &argv[(int)argv[-1] - 10]; } *cpp++ = val; *cpp = 0; return(argv);}#endif /* NEWINIT *//* * cleanup() * * This is the routine to call when we are all through, to * clean up anything that needs to be cleaned up. */ /* ARGSUSED */ voidcleanup(sig) int sig;{#ifndef PARENT_DOES_UTMP# if (BSD > 43) || defined(convex) char *p; p = line + sizeof("/dev/") - 1; if (logout(p)) logwtmp(p, "", ""); (void)chmod(line, 0666); (void)chown(line, 0, 0); *p = 'p'; (void)chmod(line, 0666); (void)chown(line, 0, 0); (void) shutdown(net, 2); exit(1);# else void rmut(); rmut(); vhangup(); /* XXX */ (void) shutdown(net, 2); exit(1);# endif#else /* PARENT_DOES_UTMP */# ifdef NEWINIT (void) shutdown(net, 2); exit(1);# else /* NEWINIT */# ifdef CRAY static int incleanup = 0; register int t; /* * 1: Pick up the zombie, if we are being called * as the signal handler. * 2: If we are a nested cleanup(), return. * 3: Try to clean up TMPDIR. * 4: Fill in utmp with shutdown of process. * 5: Close down the network and pty connections. * 6: Finish up the TMPDIR cleanup, if needed. */ if (sig == SIGCHLD) while (waitpid(-1, 0, WNOHANG) > 0) ; /* VOID */ t = sigblock(sigmask(SIGCHLD)); if (incleanup) { sigsetmask(t); return; } incleanup = 1; sigsetmask(t); if (secflag) { /* * We need to set ourselves back to a null * label to clean up. */ setulvl(sysv.sy_minlvl); setucmp((long)0); } t = cleantmp(&wtmp); setutent(); /* just to make sure */# endif /* CRAY */ rmut(line); close(pty); (void) shutdown(net, 2);# ifdef CRAY if (t == 0) cleantmp(&wtmp);# endif /* CRAY */ exit(1);# endif /* NEWINT */#endif /* PARENT_DOES_UTMP */}#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)/* * _utmp_sig_rcv * utmp_sig_init * utmp_sig_wait * These three functions are used to coordinate the handling of * the utmp file between the server and the soon-to-be-login shell. * The server actually creates the utmp structure, the child calls * utmp_sig_wait(), until the server calls utmp_sig_notify() and * signals the future-login shell to proceed. */static int caught=0; /* NZ when signal intercepted */static void (*func)(); /* address of previous handler */ void_utmp_sig_rcv(sig) int sig;{ caught = 1; (void) signal(SIGUSR1, func);} voidutmp_sig_init(){ /* * register signal handler for UTMP creation */ if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) fatalperror(net, "telnetd/signal");} voidutmp_sig_reset(){ (void) signal(SIGUSR1, func); /* reset handler to default */}# ifdef __hpux# define sigoff() /* do nothing */# define sigon() /* do nothing */# endif voidutmp_sig_wait(){ /* * Wait for parent to write our utmp entry. */ sigoff(); while (caught == 0) { pause(); /* wait until we get a signal (sigon) */ sigoff(); /* turn off signals while we check caught */ } sigon(); /* turn on signals again */} voidutmp_sig_notify(pid){ kill(pid, SIGUSR1);}# ifdef CRAYstatic int gotsigjob = 0; /*ARGSUSED*/ voidsigjob(sig) int sig;{ register int jid; register struct jobtemp *jp; while ((jid = waitjob(NULL)) != -1) { if (jid == 0) { return; } gotsigjob++; jobend(jid, NULL, NULL); }}/* * Clean up the TMPDIR that login created. * The first time this is called we pick up the info * from the utmp. If the job has already gone away, * then we'll clean up and be done. If not, then * when this is called the second time it will wait * for the signal that the job is done. */ intcleantmp(wtp) register struct utmp *wtp;{ struct utmp *utp; static int first = 1; register int mask, omask, ret; extern struct utmp *getutid P((const struct utmp *_Id)); mask = sigmask(WJSIGNAL); if (first == 0) { omask = sigblock(mask); while (gotsigjob == 0) sigpause(omask); return(1); } first = 0; setutent(); /* just to make sure */ utp = getutid(wtp); if (utp == 0) { syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); return(-1); } /* * Nothing to clean up if the user shell was never started. */ if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0) return(1); /* * Block the WJSIGNAL while we are in jobend(). */ omask = sigblock(mask); ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user); sigsetmask(omask); return(ret);} intjobend(jid, path, user) register int jid; register char *path; register char *user;{ static int saved_jid = 0; static char saved_path[sizeof(wtmp.ut_tpath)+1]; static char saved_user[sizeof(wtmp.ut_user)+1]; if (path) { strncpy(saved_path, path, sizeof(wtmp.ut_tpath)); strncpy(saved_user, user, sizeof(wtmp.ut_user)); saved_path[sizeof(saved_path)] = '\0'; saved_user[sizeof(saved_user)] = '\0'; } if (saved_jid == 0) { saved_jid = jid; return(0); } cleantmpdir(jid, saved_path, saved_user); return(1);}/* * Fork a child process to clean up the TMPDIR */cleantmpdir(jid, tpath, user) register int jid; register char *tpath; register char *user;{ switch(fork()) { case -1: syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n", tpath); break; case 0: execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n", tpath, CLEANTMPCMD); exit(1); default: /* * Forget about child. We will exit, and * /etc/init will pick it up. */ break; }}# endif /* CRAY */#endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) *//* * rmut() * * This is the function called by cleanup() to * remove the utmp entry for this person. */#ifdef UTMPX voidrmut(){ register f; int found = 0; struct utmp *u, *utmp; int nutmp; struct stat statbf; struct utmpx *utxp, utmpx; /* * This updates the utmpx and utmp entries and make a wtmp/x entry */ SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1); utxp = getutxline(&utmpx); if (utxp) { utxp->ut_type = DEAD_PROCESS; utxp->ut_exit.e_termination = 0; utxp->ut_exit.e_exit = 0; (void) time(&utmpx.ut_tv.tv_sec); utmpx.ut_tv.tv_usec = 0; modutx(utxp); } endutxent();} /* end of rmut */#endif#if !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43 voidrmut(){ register f; int found = 0; struct utmp *u, *utmp; int nutmp; struct stat statbf; f = open(utmpf, O_RDWR); if (f >= 0) { (void) fstat(f, &statbf); utmp = (struct utmp *)malloc((unsigned)statbf.st_size); if (!utmp) syslog(LOG_ERR, "utmp malloc failed"); if (statbf.st_size && utmp) { nutmp = read(f, (char *)utmp, (int)statbf.st_size); nutmp /= sizeof(struct utmp); for (u = utmp ; u < &utmp[nutmp] ; u++) { if (SCMPN(u->ut_line, line+5) || u->ut_name[0]==0) continue; (void) lseek(f, ((long)u)-((long)utmp), L_SET); SCPYN(u->ut_name, ""); SCPYN(u->ut_host, ""); (void) time(&u->ut_time); (void) write(f, (char *)u, sizeof(wtmp)); found++; } } (void) close(f); } if (found) { f = open(wtmpf, O_WRONLY|O_APPEND); if (f >= 0) { SCPYN(wtmp.ut_line, line+5); SCPYN(wtmp.ut_name, ""); SCPYN(wtmp.ut_host, ""); (void) time(&wtmp.ut_time); (void) write(f, (char *)&wtmp, sizeof(wtmp)); (void) close(f); } } (void) chmod(line, 0666); (void) chown(line, 0, 0); line[strlen("/dev/")] = 'p'; (void) chmod(line, 0666); (void) chown(line, 0, 0);} /* end of rmut */#endif /* CRAY */#ifdef __hpuxrmut (line)char *line;{ struct utmp utmp; struct utmp *utptr; int fd; /* for /etc/wtmp */ utmp.ut_type = USER_PROCESS; (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id)); (void) setutent(); utptr = getutid(&utmp); /* write it out only if it exists */ if (utptr) { utptr->ut_type = DEAD_PROCESS; utptr->ut_time = time((long *) 0); (void) pututline(utptr); /* set wtmp entry if wtmp file exists */ if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { (void) write(fd, utptr, sizeof(utmp)); (void) close(fd); } } (void) endutent(); (void) chmod(line, 0666); (void) chown(line, 0, 0); line[14] = line[13]; line[13] = line[12]; line[8] = 'm'; line[9] = '/'; line[10] = 'p'; line[11] = 't'; line[12] = 'y'; (void) chmod(line, 0666); (void) chown(line, 0, 0);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -