📄 sys_term.c
字号:
char *user; int save_errno; char *buf; extern char *gettytab[2], *gettyent;#ifdef HAVE_UTMPX_H int pid = getpid(); struct utmpx utmpx; char *clean_tty; /* * Create utmp entry for child */ clean_tty = clean_ttyname(line); memset(&utmpx, 0, sizeof(utmpx)); strncpy(utmpx.ut_user, ".telnet", sizeof(utmpx.ut_user)); strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));#ifdef HAVE_STRUCT_UTMP_UT_ID strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));#endif utmpx.ut_pid = pid; utmpx.ut_type = LOGIN_PROCESS; gettimeofday (&utmpx.ut_tv, NULL); if (pututxline(&utmpx) == NULL) fatal(net, "pututxline failed");#endif#if 0 scrub_env();#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 */ /* init argv structure */ argv.size=0; argv.argc=0; argv.argv=malloc(0); /*so we can call realloc later */ addarg(&argv, "login"); addarg(&argv, "-h"); addarg(&argv, host); addarg(&argv, "-p"); if(name[0]) user = name; else user = getenv("USER");#ifdef AUTHENTICATION if (auth_level < 0 || autologin != AUTH_VALID) { if(!no_warn) { printf("User not authenticated. " "Using plaintext username and password\r\n"); } if(log_unauth) syslog(LOG_INFO, "unauthenticated access from %s (%s)", host, user ? user : "unknown user"); } if (auth_level >= 0 && autologin == AUTH_VALID) addarg(&argv, "-f");#endif if(user){ addarg(&argv, "--"); addarg(&argv, strdup(user)); } if (new_login == NULL && cgetent(&buf, gettytab, gettyent) >= 0) { cgetstr(buf, "lo", &new_login); cgetclose(); } if (new_login == NULL) new_login = _PATH_LOGIN; if (getenv("USER")) { /* * 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"); } closelog(); /* * This sleep(1) is in here so that telnetd can * finish up with the tty. There's a race condition * the login banner message gets lost... */ sleep(1); execv(new_login, (char *const*)argv.argv); save_errno = errno; syslog(LOG_ERR, "%s: %m", new_login); fatalperror_errno(net, new_login, save_errno); /*NOTREACHED*/}static voidaddarg(struct arg_val *argv, const char *val){ const char **tmp; if (argv->size <= argv->argc+1) { tmp = realloc(argv->argv, sizeof(char*) * (argv->size + 10)); if (tmp == NULL) { if (argv->argv) free(argv->argv); argv->argv = NULL; argv->size = 0; fatal (net, "realloc: out of memory"); } argv->argv = tmp; argv->size+=10; } argv->argv[argv->argc++] = val; argv->argv[argv->argc] = NULL;}/* * rmut() * * This is the function called by cleanup() to * remove the utmp entry for this person. */#ifdef HAVE_UTMPX_Hstatic voidrmut(void){ struct utmpx utmpx, *non_save_utxp; char *clean_tty = clean_ttyname(line); /* * This updates the utmpx and utmp entries and make a wtmp/x entry */ setutxent(); memset(&utmpx, 0, sizeof(utmpx)); strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line)); utmpx.ut_type = LOGIN_PROCESS; non_save_utxp = getutxline(&utmpx); if (non_save_utxp) { struct utmpx *utxp; char user0; utxp = malloc(sizeof(struct utmpx)); *utxp = *non_save_utxp; user0 = utxp->ut_user[0]; utxp->ut_user[0] = '\0'; utxp->ut_type = DEAD_PROCESS;#ifdef HAVE_STRUCT_UTMPX_UT_EXIT#ifdef _STRUCT___EXIT_STATUS utxp->ut_exit.__e_termination = 0; utxp->ut_exit.__e_exit = 0;#elif defined(__osf__) /* XXX */ utxp->ut_exit.ut_termination = 0; utxp->ut_exit.ut_exit = 0;#else utxp->ut_exit.e_termination = 0; utxp->ut_exit.e_exit = 0;#endif#endif gettimeofday(&utxp->ut_tv, NULL); pututxline(utxp);#ifdef WTMPX_FILE utxp->ut_user[0] = user0; updwtmpx(WTMPX_FILE, utxp);#elif defined(WTMP_FILE) /* This is a strange system with a utmpx and a wtmp! */ { int f = open(wtmpf, O_WRONLY|O_APPEND); struct utmp wtmp; if (f >= 0) { strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));#ifdef HAVE_STRUCT_UTMP_UT_HOST strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));#endif wtmp.ut_time = time(NULL); write(f, &wtmp, sizeof(wtmp)); close(f); } }#endif free (utxp); } endutxent();} /* end of rmut */#endif#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux))static voidrmut(void){ int f; int found = 0; struct utmp *u, *utmp; int nutmp; struct stat statbf; char *clean_tty = clean_ttyname(line); f = open(utmpf, O_RDWR); if (f >= 0) { 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, utmp, (int)statbf.st_size); nutmp /= sizeof(struct utmp); for (u = utmp ; u < &utmp[nutmp] ; u++) { if (strncmp(u->ut_line, clean_tty, sizeof(u->ut_line)) || u->ut_name[0]==0) continue; lseek(f, ((long)u)-((long)utmp), L_SET); strncpy(u->ut_name, "", sizeof(u->ut_name));#ifdef HAVE_STRUCT_UTMP_UT_HOST strncpy(u->ut_host, "", sizeof(u->ut_host));#endif u->ut_time = time(NULL); write(f, u, sizeof(wtmp)); found++; } } close(f); } if (found) { f = open(wtmpf, O_WRONLY|O_APPEND); if (f >= 0) { strncpy(wtmp.ut_line, clean_tty, sizeof(wtmp.ut_line)); strncpy(wtmp.ut_name, "", sizeof(wtmp.ut_name));#ifdef HAVE_STRUCT_UTMP_UT_HOST strncpy(wtmp.ut_host, "", sizeof(wtmp.ut_host));#endif wtmp.ut_time = time(NULL); write(f, &wtmp, sizeof(wtmp)); close(f); } } chmod(line, 0666); chown(line, 0, 0); line[strlen("/dev/")] = 'p'; chmod(line, 0666); chown(line, 0, 0);} /* end of rmut */#endif /* CRAY */#if defined(__hpux) && !defined(HAVE_UTMPX_H)static voidrmut (char *line){ struct utmp utmp; struct utmp *utptr; int fd; /* for /etc/wtmp */ utmp.ut_type = USER_PROCESS; strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line)); setutent(); utptr = getutline(&utmp); /* write it out only if it exists */ if (utptr) { utptr->ut_type = DEAD_PROCESS; utptr->ut_time = time(NULL); pututline(utptr); /* set wtmp entry if wtmp file exists */ if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) { write(fd, utptr, sizeof(utmp)); close(fd); } } endutent(); chmod(line, 0666); 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'; chmod(line, 0666); chown(line, 0, 0);}#endif/* * cleanup() * * This is the routine to call when we are all through, to * clean up anything that needs to be cleaned up. */#ifdef PARENT_DOES_UTMPvoidcleanup(int sig){#ifdef _CRAY static int incleanup = 0; int t; int child_status; /* status of child process as returned by waitpid */ int flags = WNOHANG|WUNTRACED; /* * 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, &child_status, flags) > 0) ; /* VOID */ /* Check if the child process was stopped * rather than exited. We want cleanup only if * the child has died. */ if (WIFSTOPPED(child_status)) { return; } } t = sigblock(sigmask(SIGCHLD)); if (incleanup) { sigsetmask(t); return; } incleanup = 1; sigsetmask(t); t = cleantmp(&wtmp); setutent(); /* just to make sure */#endif /* CRAY */ rmut(line); close(ourpty); shutdown(net, 2);#ifdef _CRAY if (t == 0) cleantmp(&wtmp);#endif /* CRAY */ exit(1);}#else /* PARENT_DOES_UTMP */voidcleanup(int sig){#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) rmut();#ifdef HAVE_VHANGUP#ifndef __sgi vhangup(); /* XXX */#endif#endif#else char *p; p = line + sizeof("/dev/") - 1; if (logout(p)) logwtmp(p, "", ""); chmod(line, 0666); chown(line, 0, 0); *p = 'p'; chmod(line, 0666); chown(line, 0, 0);#endif shutdown(net, 2); _exit(1);}#endif /* PARENT_DOES_UTMP */#ifdef PARENT_DOES_UTMP/* * _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; 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(){ signal(SIGUSR1, func); /* reset handler to default */}# ifdef __hpux# define sigoff() /* do nothing */# define sigon() /* do nothing */# endifvoidutmp_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;{ int jid; struct jobtemp *jp; while ((jid = waitjob(NULL)) != -1) { if (jid == 0) { return; } gotsigjob++; jobend(jid, NULL, NULL); }}/* * jid_getutid: * called by jobend() before calling cleantmp() * to find the correct $TMPDIR to cleanup. */struct utmp *jid_getutid(jid) int jid;{ struct utmp *cur = NULL; setutent(); /* just to make sure */ while (cur = getutent()) { if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) { return(cur); } } return(0);}/* * 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) struct utmp *wtp;{ struct utmp *utp; static int first = 1; int mask, omask, ret; extern struct utmp *getutid (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);}/* * jobend * Assumes that if path is not NULL, then user is also * not NULL. */intjobend(jid, path, user) int jid; char *path; char *user;{ static int saved_jid = 0; static int pty_saved_jid = 0; static char saved_path[sizeof(wtmp.ut_tpath)+1]; static char saved_user[sizeof(wtmp.ut_user)+1]; /* * this little piece of code comes into play * only when ptyreconnect is used to reconnect * to an previous session. * * this is the only time when the * "saved_jid != jid" code is executed. */ if ( saved_jid && saved_jid != jid ) { if (!path) { /* called from signal handler */ pty_saved_jid = jid; } else { pty_saved_jid = saved_jid; } } if (path) { strncpy(saved_path, path, sizeof(saved_path) - 1); strncpy(saved_user, path, sizeof(saved_user) - 1); saved_path[sizeof(saved_path) - 1] = '\0'; saved_user[sizeof(saved_user) - 1] = '\0'; } if (saved_jid == 0) { saved_jid = jid; return(0); } /* if the jid has changed, get the correct entry from the utmp file */ if ( saved_jid != jid ) { struct utmp *utp = NULL; struct utmp *jid_getutid(); utp = jid_getutid(pty_saved_jid); if (utp == 0) { syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR"); return(-1); } cleantmpdir(jid, utp->ut_tpath, utp->ut_user); return(1); } cleantmpdir(jid, saved_path, saved_user); return(1);}/* * Fork a child process to clean up the TMPDIR */cleantmpdir(jid, tpath, user) int jid; char *tpath; char *user;{ switch(fork()) { case -1: syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m", tpath); break; case 0: execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, (char *)NULL); syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m", 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) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -