int __rmt_open (const char *path, int oflag, int bias, const char *remote_shell) { int remote_pipe_number; /* pseudo, biased file descriptor */ char *path_copy; /* copy of path string */ char *cursor; /* cursor in path_copy */ char *remote_host; /* remote host name */ char *remote_file; /* remote file name (often a device) */ char *remote_user; /* remote user name */ char command_buffer[CMDBUFSIZE]; #ifndef HAVE_NETDB_H const char *remote_shell_basename; int status; #endif /* Find an unused pair of file descriptors. */ for (remote_pipe_number = 0; remote_pipe_number < MAXUNIT; remote_pipe_number++) if (READ (remote_pipe_number) == -1 && WRITE (remote_pipe_number) == -1) break; if (remote_pipe_number == MAXUNIT) { errno = EMFILE; return -1; } /* Pull apart the system and device, and optional user. */ path_copy = xstrdup (path); remote_host = path_copy; remote_user = NULL; remote_file = NULL; for (cursor = path_copy; *cursor; cursor++) switch (*cursor) { default: break; case '@': if (!remote_user) { remote_user = remote_host; *cursor = '\0'; remote_host = cursor + 1; } break; case ':': if (!remote_file) { *cursor = '\0'; remote_file = cursor + 1; } break; } /* FIXME: Should somewhat validate the decoding, here. */ if (*remote_user == '\0') remote_user = NULL; #ifdef HAVE_NETDB_H /* Execute the remote command using rexec. */ READ (remote_pipe_number) = _rmt_rexec (remote_host, remote_user); if (READ (remote_pipe_number) < 0) { free (path_copy); return -1; } WRITE (remote_pipe_number) = READ (remote_pipe_number); #else /* not HAVE_NETDB_H */ /* Identify the remote command to be executed. */ if (!remote_shell) { #ifdef REMOTE_SHELL remote_shell = REMOTE_SHELL; #else errno = EIO; free (path_copy); return -1; #endif } remote_shell_basename = strrchr (remote_shell, '/'); if (remote_shell_basename) remote_shell_basename++; else remote_shell_basename = remote_shell; /* Set up the pipes for the `rsh' command, and fork. */ if (pipe (to_remote[remote_pipe_number]) == -1 || pipe (from_remote[remote_pipe_number]) == -1) { free (path_copy); return -1; } status = fork (); if (status == -1) { free (path_copy); return -1; } if (status == 0) { /* Child. */ close (0); dup (to_remote[remote_pipe_number][0]); close (to_remote[remote_pipe_number][0]); close (to_remote[remote_pipe_number][1]); close (1); dup (from_remote[remote_pipe_number][1]); close (from_remote[remote_pipe_number][0]); close (from_remote[remote_pipe_number][1]); setuid (getuid ()); setgid (getgid ()); if (remote_user) execl (remote_shell, remote_shell_basename, remote_host, "-l", remote_user, "/etc/rmt", (char *) 0); else execl (remote_shell, remote_shell_basename, remote_host, "/etc/rmt", (char *) 0); /* Bad problems if we get here. */ /* In a previous version, _exit was used here instead of exit. */ error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell")); } /* Parent. */ close (from_remote[remote_pipe_number][1]); close (to_remote[remote_pipe_number][0]); #endif /* not HAVE_NETDB_H */ /* Attempt to open the tape device. */ sprintf (command_buffer, "O%s\n%d\n", remote_file, oflag); if (do_command (remote_pipe_number, command_buffer) == -1 || get_status (remote_pipe_number) == -1) { free (path_copy); return -1; } free (path_copy); return remote_pipe_number + bias; }
/* Open a file (a magnetic tape device?) on the system specified in FILE_NAME, as the given user. FILE_NAME has the form `[USER@]HOST:FILE'. OPEN_MODE is O_RDONLY, O_WRONLY, etc. If successful, return the remote pipe number plus BIAS. REMOTE_SHELL may be overridden. On error, return -1. */ int rmt_open__ (const char *file_name, int open_mode, int bias, const char *remote_shell) { int remote_pipe_number; /* pseudo, biased file descriptor */ char *file_name_copy; /* copy of file_name string */ char *remote_host; /* remote host name */ char *remote_file; /* remote file name (often a device) */ char *remote_user; /* remote user name */ /* Find an unused pair of file descriptors. */ for (remote_pipe_number = 0; remote_pipe_number < MAXUNIT; remote_pipe_number++) if (READ_SIDE (remote_pipe_number) == -1 && WRITE_SIDE (remote_pipe_number) == -1) break; if (remote_pipe_number == MAXUNIT) { errno = EMFILE; return -1; } /* Pull apart the system and device, and optional user. */ { char *cursor; file_name_copy = xstrdup (file_name); remote_host = file_name_copy; remote_user = 0; remote_file = 0; for (cursor = file_name_copy; *cursor; cursor++) switch (*cursor) { default: break; case '\n': /* Do not allow newlines in the file_name, since the protocol uses newline delimiters. */ free (file_name_copy); errno = ENOENT; return -1; case '@': if (!remote_user) { remote_user = remote_host; *cursor = '\0'; remote_host = cursor + 1; } break; case ':': if (!remote_file) { *cursor = '\0'; remote_file = cursor + 1; } break; } } /* FIXME: Should somewhat validate the decoding, here. */ if (gethostbyname (remote_host) == NULL) error (EXIT_ON_EXEC_ERROR, 0, _("Cannot connect to %s: resolve failed"), remote_host); if (remote_user && *remote_user == '\0') remote_user = 0; #if WITH_REXEC /* Execute the remote command using rexec. */ READ_SIDE (remote_pipe_number) = _rmt_rexec (remote_host, remote_user); if (READ_SIDE (remote_pipe_number) < 0) { int e = errno; free (file_name_copy); errno = e; return -1; } WRITE_SIDE (remote_pipe_number) = READ_SIDE (remote_pipe_number); #else /* not WITH_REXEC */ { const char *remote_shell_basename; pid_t status; /* Identify the remote command to be executed. */ if (!remote_shell) { #ifdef REMOTE_SHELL remote_shell = REMOTE_SHELL; #else free (file_name_copy); errno = EIO; return -1; #endif } remote_shell_basename = last_component (remote_shell); /* Set up the pipes for the `rsh' command, and fork. */ if (pipe (to_remote[remote_pipe_number]) == -1 || pipe (from_remote[remote_pipe_number]) == -1) { int e = errno; free (file_name_copy); errno = e; return -1; } status = fork (); if (status == -1) { int e = errno; free (file_name_copy); errno = e; return -1; } if (status == 0) { /* Child. */ if (dup2 (to_remote[remote_pipe_number][PREAD], STDIN_FILENO) < 0 || (to_remote[remote_pipe_number][PREAD] != STDIN_FILENO && close (to_remote[remote_pipe_number][PREAD]) != 0) || (to_remote[remote_pipe_number][PWRITE] != STDIN_FILENO && close (to_remote[remote_pipe_number][PWRITE]) != 0) || dup2 (from_remote[remote_pipe_number][PWRITE], STDOUT_FILENO) < 0 || close (from_remote[remote_pipe_number][PREAD]) != 0 || close (from_remote[remote_pipe_number][PWRITE]) != 0) error (EXIT_ON_EXEC_ERROR, errno, _("Cannot redirect files for remote shell")); sys_reset_uid_gid (); if (remote_user) execl (remote_shell, remote_shell_basename, remote_host, "-l", remote_user, rmt_command, (char *) 0); else execl (remote_shell, remote_shell_basename, remote_host, rmt_command, (char *) 0); /* Bad problems if we get here. */ /* In a previous version, _exit was used here instead of exit. */ error (EXIT_ON_EXEC_ERROR, errno, _("Cannot execute remote shell")); } /* Parent. */ close (from_remote[remote_pipe_number][PWRITE]); close (to_remote[remote_pipe_number][PREAD]); } #endif /* not WITH_REXEC */ /* Attempt to open the tape device. */ { size_t remote_file_len = strlen (remote_file); char *command_buffer = xmalloc (remote_file_len + 1000); sprintf (command_buffer, "O%s\n", remote_file); encode_oflag (command_buffer + remote_file_len + 2, open_mode); strcat (command_buffer, "\n"); if (do_command (remote_pipe_number, command_buffer) == -1 || get_status (remote_pipe_number) == -1) { int e = errno; free (command_buffer); free (file_name_copy); _rmt_shutdown (remote_pipe_number, e); return -1; } free (command_buffer); } free (file_name_copy); return remote_pipe_number + bias; }
static int /*ARGSUSED*/ _rmt_open(const char *path, int oflag, int mode) { int i; char buffer[BUFMAGIC]; char host[MAXHOSTLEN]; char device[BUFMAGIC]; char login[BUFMAGIC]; char *sys, *dev, *user; const char *rshpath, *rsh; _DIAGASSERT(path != NULL); sys = host; dev = device; user = login; /* * first, find an open pair of file descriptors */ for (i = 0; i < MAXUNIT; i++) if (READ(i) == -1 && WRITE(i) == -1) break; if (i == MAXUNIT) { errno = EMFILE; return -1; } /* * pull apart system and device, and optional user * don't munge original string * if COMPAT is defined, also handle old (4.2) style person.site notation. */ while (*path != '@' #ifdef COMPAT && *path != '.' #endif && *path != ':') { *sys++ = *path++; } *sys = '\0'; path++; if (*(path - 1) == '@') { (void)strncpy(user, host, sizeof(login) - 1); /* saw user part of user@host */ sys = host; /* start over */ while (*path != ':') { *sys++ = *path++; } *sys = '\0'; path++; } #ifdef COMPAT else if (*(path - 1) == '.') { while (*path != ':') { *user++ = *path++; } *user = '******'; path++; } #endif else *user = '******'; while (*path) { *dev++ = *path++; } *dev = '\0'; #ifdef USE_REXEC /* * Execute the remote command using rexec */ READ(i) = WRITE(i) = _rmt_rexec(host, login); if (READ(i) < 0) return -1; #else /* * setup the pipes for the 'rsh' command and fork */ if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1) return -1; switch (fork()) { case -1: return -1; case 0: close(0); dup(Ptc[i][0]); close(Ptc[i][0]); close(Ptc[i][1]); close(1); dup(Ctp[i][1]); close(Ctp[i][0]); close(Ctp[i][1]); (void) setuid(getuid()); (void) setgid(getgid()); if ((rshpath = getenv("RCMD_CMD")) == NULL) rshpath = _PATH_RSH; if ((rsh = strrchr(rshpath, '/')) == NULL) rsh = rshpath; else rsh++; if (*login) { execl(rshpath, rsh, host, "-l", login, _PATH_RMT, NULL); } else { execl(rshpath, rsh, host, _PATH_RMT, NULL); } /* * bad problems if we get here */ err(1, "Cannnot exec %s", rshpath); /*FALLTHROUGH*/ default: break; } close(Ptc[i][0]); close(Ctp[i][1]); #endif /* * now attempt to open the tape device */ (void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag); if (command(i, buffer) == -1 || status(i) == -1) return -1; return i; }