📄 sd_rexd.c
字号:
if (ioctl(OutputSocket, SIOCATMARK, &atmark) < 0) { perror("ioctl"); break; } if (atmark) break; (void) read(OutputSocket, waste, sizeof (waste)); } (void) recv(OutputSocket, &mark, 1, MSG_OOB);}/* * rex_wait - wait for command to finish, unmount the file system, * and return the exit status. * message gets an optional string error message. */rex_wait(message) char **message;{ static char error[1024]; int count; *message = error; strcpy("",error); if (child == 0) { errprintf(error,"No process to wait for!\n"); rex_cleanup(); return (1); } kill(child, SIGHUP); for (count=0;!ChildDied && count<WaitLimit;count++) sleep(1); if (ChildStatus & 0xFF) return (ChildStatus); return (ChildStatus >> 8);}/* * cleanup - unmount and remove our temporary directory */rex_cleanup(){ if (tmpdir) { if (child && !ChildDied) { fprintf(stderr, "sd_rexd: child killed to unmount %s\r\n", nfsdir); kill(child, SIGKILL); } chdir("/"); if (nfsdir[0] && umount_nfs(nfsdir, tmpdir)) fprintf(stderr, "sd_rexd: couldn't umount %s from %s\r\n", nfsdir, tmpdir); if (rmdir(tmpdir) < 0) if (errno != EBUSY) perror("rmdir"); tmpdir = NULL; } if (HasHelper) KillHelper(child); HasHelper = 0;}/* * This function does the server work to get a command executed * Returns 0 if OK, nonzero if error */rex_start(rst, ucred, message, sock) struct rex_start *rst; struct authunix_parms *ucred; char **message; int sock;{ char *index(), *mktemp(); char hostname[255]; char *p, *wdhost, *fsname, *subdir; char dirbuf[1024]; static char error[1024]; char defaultShell[1024]; /* command executed if none given */ char defaultDir[1024]; /* directory used if none given */ struct sockaddr_in sin; int len; int fd0, fd1, fd2; extern char **environ; int icount = 0; if (child) { /* already started */ killpg(child, SIGKILL); return (1); } *message = error; (void) strcpy(error, ""); signal(SIGCHLD, CatchChild); if (ValidUser(ucred->aup_machname, ucred->aup_uid,error, defaultShell, defaultDir, rst->rst_cmd[0])) return(1); if (rst->rst_fsname && strlen(rst->rst_fsname)) { fsname = rst->rst_fsname; subdir = rst->rst_dirwithin; wdhost = rst->rst_host; } else { fsname = defaultDir; subdir = ""; wdhost = hostname; } gethostname(hostname, 255); if (strcmp(wdhost, hostname) == 0) { /* * The requested directory is local to our machine, * so just change to it. */ strcpy(dirbuf,fsname); } else { static char wanted[1024]; static char mountedon[1024]; strcpy(wanted,wdhost); strcat(wanted,":"); strcat(wanted,fsname); if (AlreadyMounted(wanted,mountedon)) { /* * The requested directory is already mounted. If the * mount is not by another rexd, just change to it. * Otherwise, mount it again. If just changeing to * the mounted directy, be careful. It might be mounted * in a different place. * (dirbuf is modified in place!) */ if (strncmp(mountedon, TempName, TempMatch) == 0) { /* */ tmpdir = mktemp (TempName); if (mkdir (tmpdir, 0777)) { perror (tmpdir); audit_note (2, tmpdir); return (1); } strcpy(nfsdir, wanted); if (mount_nfs (wanted, tmpdir, error)) { audit_note (1,error); return (1); } strcpy (dirbuf, tmpdir); } else strcpy(dirbuf, mountedon); } else { /* * The requested directory is not mounted anywhere, * so try to mount our own copy of it. We set nfsdir * so that it gets unmounted later, and tmpdir so that * it also gets removed when we are done. */ tmpdir = mktemp(TempName); if (mkdir(tmpdir, 0777)) { perror(tmpdir); audit_note(1, tmpdir ); return(1); } strcpy(nfsdir, wanted); if (mount_nfs(wanted, tmpdir, error)) { audit_note(1, error); return(1); } strcpy(dirbuf, tmpdir); } } /* * "dirbuf" now contains the local mount point, so just tack on * the subdirectory to get the pathname to which we "chdir" */ strcat(dirbuf, subdir); len = sizeof sin; if (getpeername(sock, &sin, &len)) { perror("getpeername"); audit_note(1, "getpeername" ); return(1); } fd0 = socket(AF_INET, SOCK_STREAM, 0); fd0 = doconnect(&sin, rst->rst_port0,fd0); OutputSocket = fd0; /* * Arrange for fd0 to send the SIGURG signal when out-of-band data * arrives, which indicates that we should send the stopped child a * SIGCONT signal so that we can resume work. */ (void) fcntl(fd0, F_SETOWN, getpid()); signal(SIGURG, oob); if (rst->rst_port0 == rst->rst_port1) { /* * use the same connection for both stdin and stdout */ fd1 = fd0; } if (rst->rst_flags & REX_INTERACTIVE) { /* * allocate a pseudo-terminal if necessary */ if (AllocatePtyMaster(fd0,fd1)) { errprintf(error,"sd_rexd: cannot allocate a pty\n"); audit_note(1, error); return (1); } HasHelper = 1; } child = fork(); if (child < 0) { errprintf(error, "sd_rexd: can't fork\n"); audit_note(1, error); return (1); } if (child) { /* * parent sd_rexd: close network connections if needed, * then return to the main loop. */ if ((rst->rst_flags & REX_INTERACTIVE)==0) { close(fd0); close(fd1); } return (0); } /* child rexd */ if (rst->rst_flags & REX_INTERACTIVE) AllocatePtySlave(); if (rst->rst_port0 != rst->rst_port1) { fd1 = socket(AF_INET, SOCK_STREAM, 0); shutdown(fd0, 1); fd1 = doconnect(&sin, rst->rst_port1,fd1); shutdown(fd1, 0); } if (rst->rst_port1 == rst->rst_port2) { /* * Use the same connection for both stdout and stderr */ fd2 = fd1; } else { fd2 = socket(AF_INET, SOCK_STREAM, 0); fd2 = doconnect(&sin, rst->rst_port2,fd2); shutdown(fd2, 0); } if (rst->rst_flags & REX_INTERACTIVE) { /* * use ptys instead of sockets in interactive mode */ DoHelper(&fd0, &fd1, &fd2); } dup2(fd0, 0); dup2(fd1, 1); dup2(fd2, 2); for (fd0 = 3; fd0 < getdtablesize(); fd0++) close(fd0); environ = rst->rst_env; setgid(ucred->aup_gid); setgroups(ucred->aup_len,ucred->aup_gids); /* * write audit record before making uid switch */ audit_note(0, "successful"); setuid(ucred->aup_uid); if (debug) { printf("ucred->aup_machname = %s\n", ucred->aup_machname); printf("ucred->aup_uid = %d\n", ucred->aup_uid); printf("ucred->aup_gid = %d\n", ucred->aup_gid); } if (chdir(dirbuf)) { perror("rex_start"); fprintf(stderr, "sd_rexd: can't chdir to %s\n", dirbuf); exit(1); } signal( SIGINT, SIG_DFL); signal( SIGHUP, SIG_DFL); signal( SIGQUIT, SIG_DFL); if (rst->rst_cmd[0]==NULL) { /* * Null command means execute the default shell for this user */ char *args[2]; args[0] = defaultShell; args[1] = NULL; execvp(defaultShell, args); fprintf(stderr, "sd_rexd: can't exec shell %s\n", defaultShell); exit(1); } if (debug) { printf("command line: "); icount = 0; while (rst->rst_cmd[icount] != NULL) { printf("%s ", rst->rst_cmd[icount]); icount++; } printf("\n"); } execvp(rst->rst_cmd[0], rst->rst_cmd); perror("sd_rexd: rex_start:"); fprintf(stderr, "sd_rexd: can't exec %s\n", rst->rst_cmd[0]); exit(1);}AlreadyMounted(fsname, mountedon) char *fsname; char *mountedon;{ /* * Search the mount table to see if the given file system is already * mounted. If so, return the place that it is mounted on. */ FILE *table; register struct mntent *mt; table = setmntent(MOUNTED,"r"); if (debug) printf("MOUNTED = %s; fsname = %s; mountedon = %s\n", MOUNTED, fsname, mountedon); if (table == NULL) return (0); while ( (mt = getmntent(table)) != NULL) { if (strcmp(mt->mnt_fsname,fsname) == 0) { if (debug) printf("mt->mnt_fsname = %s; mt->mnt_dir = %s\n", mt->mnt_fsname, mt->mnt_dir); strcpy(mountedon,mt->mnt_dir); endmntent(table); return(1); } } endmntent(table); return(0);}/* * connect to the indicated IP address/port, and return the * resulting file descriptor. */doconnect(sin, port, fd) struct sockaddr_in *sin; short port; int fd;{ sin->sin_port = ntohs(port); if (connect(fd, sin, sizeof *sin)) { perror("sd_rexd: connect"); exit(1); } return (fd);}/** SETPROCTITLE -- set the title of this process for "ps"** Does nothing if there were not enough arguments on the command* line for the information.** Side Effects:* Clobbers argv[] of our main procedure.*/setproctitle(user, host) char *user, *host;{ register char *tohere; tohere = Argv[0]; if (LastArgv == NULL || strlen(user)+strlen(host)+3 > (LastArgv - tohere)) return; *tohere++ = '-'; /* So ps prints (rpc.rexd) */ sprintf(tohere, "%s@%s", user, host); while (*tohere++) ; /* Skip to end of printf output */ while (tohere < LastArgv) *tohere++ = ' '; /* Avoid confusing ps */}/* * Determine if a descriptor belongs to a socket or not */issock(fd) int fd;{ struct stat st; if (fstat(fd, &st) < 0) { return (0); } /* * SunOS returns S_IFIFO for sockets, while 4.3 returns 0 and does not * even have an S_IFIFO mode. Since there is confusion about what the * mode is, we check for what it is not instead of what it is. */ switch (st.st_mode & S_IFMT) { case S_IFCHR: case S_IFREG: case S_IFLNK: case S_IFDIR: case S_IFBLK: return (0); default: return (1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -