📄 deslogind.c
字号:
} if (getRemoteAddr(0, rhostName, sizeof rhostName, &rport) == 0) { nfd = 0; /* From inetd. 0 and 1 is our socket. */ close(2); /* inetd leaves it open */ } else { /* Interactive invocation */ if (port == 0) { port = getServicePort(SERVICE_NAME); if ((int) port < 0) { port = DESLOGIN_PORT; log( "%s: WARNING--no \"%s\" service; using port %u\n", progName, SERVICE_NAME, port); } } log("%s: Starting daemon pid %ld port %d\n", progName, (unsigned long) getpid(), port); /* * Must close fds 0,1, and 2 *before* openServer and becomeDaemon */ close(0); close(1); close(2); pid = becomeDaemon(); if (pid < 0) { return 1; /* messages already logged */ } nfd = openServer(port, rhostName, sizeof rhostName, &rport, (debug < 2)); if (nfd < 0) { log("%s: open network port %d failed--%s\n", progName, port, ERRMSG); return 1; } setProgName(); /* Openserver did a fork when it returned successfully */ /* * Openserver handed us nfd as fd 1, 0 is now available */ } log("%s: connect %s:%d\n", progName, rhostName, rport); protocol = serverHandshake(nfd, rhostName, rport, SETUP_TIMEOUT); if (!protocol) { return 1; /* log already done */ } count = getString(nfd, ruser, USERNAME_SIZE-1, SETUP_TIMEOUT); if (count == 0) { log("%s: NORUSER %s:%d\n", progName, rhostName, rport); return 1; } count = getString(nfd, userName, USERNAME_SIZE-1, SETUP_TIMEOUT); if (count == 0) { log("%s: NOLUSER %s@%s:%d\n", progName, ruser, rhostName, rport); return 1; } /* * Minimize the the time the phrase must me visible in memory. */ res = getUserPhrase(userFile, passPhrase, PHRASE_SIZE, userName, userKey); if (res == -1) { log("%s: cannot open \"%s\" for user database\n", progName, userFile); return 1; } if (res == -2) { log("%s: incorrect decryption key for user database \"%s\"\n", progName, userFile); return 1; } if (res == 0) { log("%s: NOPHRASE %s@%s:%d->\"%s\"\n", progName, ruser, rhostName, rport, userName); return 1; } key = challenge(nfd, passPhrase, loginTimeout); if (key == (keyType) 0) { log("%s: BADLOGIN %s@%s:%d->\"%s\"\n", progName, ruser, rhostName, rport, userName); return 1; } memset(passPhrase, '\0', PHRASE_SIZE); res = getUserInfo(userName, &shell, &cwd, &uid, &gid); if (res < 0) { log("%s: NOUSER %s@%s:%d->\"%s\"\n", progName, ruser, rhostName, rport, userName); return 1; } /* * If /etc/nologin exists, just copy it to the port and terminate. */#ifdef NOLOGIN_FILE res = open(NOLOGIN_FILE, O_RDONLY, 0); if (res >= 0) { log("%s: NOLOGIN %s@%s:%d->%s\n", progName, ruser, rhostName, rport, userName); cipherCopy(nfd, res, 2, key); /* two seconds max to blast it out */ close(res); exit(1); }#endif /* * We really should log the tty assigned, and pid of the shell as well */ log("%s: Login %s@%s:%d\n", progName, ruser, rhostName, rport); log("%s: %s uid(%u) gid(%u) %s %s\n", progName, userName, uid, gid, cwd, shell); time(&loginTime); if (pty) { /* * We only need to do all this pty stuff and forking, if we want * the local process to use a the slave tty interface. This will * not always be the case. We should add a feature to eliminate it * for remote commands that do not need a tty as stdin, stdout & stderr. * * The openPty below my make the slave the controlling terminal for * this process, unless we use O_NOCTTY. */ masterpty = openPty(O_RDWR | O_NOCTTY, sname, mname, PTY_NAMESIZE, &slavepty); if (masterpty < 0) { log("%s: no pty's available\n", progName); exit(1); } /* * Better make sure this close relinquishes the slavepty as the * controlling terminal if it was. Otherwise, the child will be unable * to reacquire it as the controlling terminal and exit. * * DEC Ultrix 4.3 definitely ignores O_NOCTTY, but this code makes * sure that is harmless by closing the slave before the fork below. * * In fact, I can't figure out a way to force Ultrix to give me * a controlling terminal. It claims I got one, but then when I * try to relinquish it, it fails ENOTTY. tcgetpgrp is really busted * on this machine. */ pid_res = tcgetpgrp(slavepty); if (debug > 1) { log("%s: tcgetpgrp(%d) returned pid %d\n", progName, slavepty, pid_res); } if (debug && (pid_res >= (pid_t) 0)) { log("%s: WARNING--%s fd %d is controlling terminal of daemon!\n", progName, sname, slavepty); res = mkCtrlTty(slavepty, 0); if (debug > 1) { log("%s: mkCtrlTty(%d) returned %d\n", progName, slavepty, res); } if (res < 0) { log("%s: WARNING--couldn't relinquish control terminal--%s\n", progName, ERRMSG); } } close(slavepty); /* * The next three calls can fail when running as a normal user */ res = chmod(sname, TTY_MODE); if (res < 0) { log("%s: WARNING--chmod(\"%s\",0%o) failed--%s\n", progName, sname, TTY_MODE, ERRMSG); } res = chown(sname, uid, gid); if (res < 0) { log("%s: WARNING--chown(\"%s\",%d,%d) failed--%s\n", progName, sname, uid, gid, ERRMSG); } if (debug) { log("%s: \"%s\" %d->%d \"%s\"\n", progName, mname, masterpty, slavepty, sname); } } else { /* pipe */ /* * We must make sure these are not fd's 0, 1, or 2, so this first * call is just to use them up if necessary. */ res = pipe(pipe2); if (res < 0) { log("%s: pipe failed--%s\n", progName, ERRMSG); exit(1); } res = pipe(pipe1); if (res < 0) { log("%s: pipe failed--%s\n", progName, ERRMSG); exit(1); } res = pipe(pipe0); if (res < 0) { log("%s: pipe failed--%s\n", progName, ERRMSG); exit(1); } close(pipe2[0]); close(pipe2[1]); if (debug) { log("%s: pipe (%d>%d) (%d<%d)\n", progName, pipe0[1], pipe0[1], pipe1[0], pipe1[1]); } } /* * POSIX states default is not to receive signal when child dies (or stops) * We want to know when it happens. We must do this before the fork * to prevent a race condition. We must catch this signal to force * the select call in txfr to interrupt when the child dies. Note thhat * this may do nothing if on systems where sysconf(_SC_JOB_CONTROL) * returns 0 (although System V may implement SIGCHLD as SIGCLD.). We'll * just have to assume that this will allow us to detect when the child * dies. If not, the symptom is that exiting the remote shell will just * hang until the INACTIVITY_TIMEOUT (connTimeout) expires. */ chp = (char *) psignal(SIGCHLD, sigHandler); if (chp == (char *) SIG_ERR) { log("%s: sigaction SIGCHLD failed--%s\n", progName, ERRMSG); return 1; } /* * This fork is necessary to reset much of the process state and * to ensure that setsid won't fail because we're a process group leader * It is also needed to transport data from the pty to the socket * (or control terminal) from the remote shell. * * Sect3:15: fork() ensures that child pid != any active pgid */ pid = fork(); if (pid != 0) { /* parent */ if (pid < 0) { /* fork failure */ log("%s: fork failed--%s\n", progName, ERRMSG); exit(1); } setProgName(); if (debug) { log("%s: parent pid %d; child pid %ld\n", progName, getpid(), (long) pid); } /* * This must be done after we have a pty, and before we to a setuid. * It updates the utmp file so getlogin and who will work corretly. * It should be done only by the parent. */ if (pty) { res = setlogin(sname, userName, rhostName); if (res < 0) { log("%s: WARNING--setlogin %s to %s@%s failed--%s\n", progName, sname, userName, rhostName, ERRMSG); } res = atexit(eraselogin); if (res < 0) { log("%s: WARNING--atexit of eraselogin failed--%s\n", progName, ERRMSG); } /* * There is a race condition between the parent and the child. * On DEC, if the parent executes txfr before the child opens the * slave, we'll abort with an I/O error. Wait until pty is ready. */ res = waitReady(masterpty, buf, 1, SETUP_TIMEOUT); if (debug > 1) { log("%s: waitReady(%d,%u)=%d\n", progName, masterpty, SETUP_TIMEOUT, res); } if (res <= 0) { if (res < 0 && errno != EINTR) { /* fail, and not SIGCHLD */ log("%s: master pty handshake failed--%s\n", progName, res, ERRMSG); } else if (res == 0) { log("%s: master pty handshake failed\n", progName, res); } } else { if (debug) { log("%s: txfr %d-decrypt->%d\n", progName, nfd, masterpty); } res = txfr(nfd, masterpty, masterpty, bufSize, connTimeout, key); } } else { /* pipe */ close(pipe0[1]); close(pipe1[0]); if (debug) { log("%s: txfr pipe %d->%d<-%d\n", progName, pipe0[0], nfd, pipe1[1]); } res = txfr(nfd, pipe0[0], pipe1[1], bufSize, connTimeout, key); } /* * Really should be registered with atexit, but since it's just * a session key anyway, it's not insecure to let's its carcass * rot in inaccessible bits of free space. */ destroyKey(&key); /* * Reap all terminated children so we don't leave zombie processes * and make sure our child CPU times are updated. Waitpid returns * -1 when all children have been reaped, and 0 if still have * unterminated children. */ do { pid = waitpid(-1, &chldStat, WNOHANG); if (debug) { log("%s: waitpid returned %ld\n", progName, (long) pid); } } while (pid > 0); cpuUsed = cpuTime(); loginTime = time((time_t *) 0) - loginTime, log("%s: Logout %s@%s:%d\n", progName, ruser, rhostName, rport); log("%s: %s on %u sec; CPU %ld%c%ld sec; %lu bytes in, %lu bytes out\n", progName, userName, loginTime, cpuUsed / 10, '.', cpuUsed % 10, inBytes, outBytes); if (res == 0) { log("%s: inactive for %u sec\n", progName, connTimeout / 1000); } exit(0); } /* child */ setProgName(); res = chdir(cwd); if (res != 0) { log("%s: chdir to %s failed \"%s\"--%s\n", progName, cwd, ERRMSG); return 1; } oldmask = umask(newmask); /* documentation says umask cannot fail! */ tz = getenv("TZ"); /* may fail by returning NULL; OK though */ if (uid == 0) { /* root user gets special path */ path = SYSTEMPATH; } cenv = setupEnv(userName, shell, cwd, path, tz); if ((chp = strrchr(shell, '/')) == (char *) 0) chp = shell-1; chp++; arg0 = (char *) malloc(strlen(chp)+2); if (arg0 == (char *) 0) { log("%s: couldn't allocate %d bytes for arg0\n", progName, strlen(chp)+2); exit(1); } arg0[0] = '-'; /* make this a login shell */ memcpy(&arg0[1], chp, strlen(chp)+1); cargv[0] = arg0; /* * This code must be placed only in the child because of the atexit call * in the parent for updating utmp. */ res = setgid(gid); /* must setgid before setuid */ if (res != 0) { log("%s: setgid to %d failed--%s\n", progName, gid, ERRMSG); exit(1); } /* * Supplementary group ids are inherited from the parent. They * should be changed if they exist. Supplementary group id's are * checked against the target gid of chmod(), chown(). */ ngroups = (int) sysconf(_SC_NGROUPS_MAX); if (ngroups >= 0) { gidset = (gid_t *) malloc(ngroups+1); if (gidset == (gid_t *) 0) { log(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -