[BACK]Return to scp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/scp.c between version 1.215 and 1.216

version 1.215, 2021/07/05 00:25:42 version 1.216, 2021/08/02 23:38:27
Line 83 
Line 83 
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <fnmatch.h>  #include <fnmatch.h>
   #include <glob.h>
   #include <libgen.h>
 #include <locale.h>  #include <locale.h>
 #include <pwd.h>  #include <pwd.h>
 #include <signal.h>  #include <signal.h>
Line 105 
Line 107 
 #include "progressmeter.h"  #include "progressmeter.h"
 #include "utf8.h"  #include "utf8.h"
   
   #include "sftp-common.h"
   #include "sftp-client.h"
   
 #define COPY_BUFLEN     16384  #define COPY_BUFLEN     16384
   
 int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout);  int do_cmd(char *program, char *host, char *remuser, int port, char *cmd,
 int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout);      int *fdin, int *fdout);
   int do_cmd2(char *host, char *remuser, int port, char *cmd,
       int fdin, int fdout);
   
 /* Struct for addargs */  /* Struct for addargs */
 arglist args;  arglist args;
Line 123 
Line 130 
   
 /* This is set to non-zero to enable verbose mode. */  /* This is set to non-zero to enable verbose mode. */
 int verbose_mode = 0;  int verbose_mode = 0;
   LogLevel log_level = SYSLOG_LEVEL_INFO;
   
 /* This is set to zero if the progressmeter is not desired. */  /* This is set to zero if the progressmeter is not desired. */
 int showprogress = 1;  int showprogress = 1;
Line 142 
Line 150 
 /* This is used to store the pid of ssh_program */  /* This is used to store the pid of ssh_program */
 pid_t do_cmd_pid = -1;  pid_t do_cmd_pid = -1;
   
   /* Needed for sftp */
   volatile sig_atomic_t interrupted = 0;
   
   int remote_glob(struct sftp_conn *, const char *, int,
       int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
   
 static void  static void
 killchild(int signo)  killchild(int signo)
 {  {
Line 218 
Line 232 
  */   */
   
 int  int
 do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)  do_cmd(char *program, char *host, char *remuser, int port, char *cmd,
       int *fdin, int *fdout)
 {  {
         int pin[2], pout[2], reserved[2];          int pin[2], pout[2], reserved[2];
   
         if (verbose_mode)          if (verbose_mode)
                 fmprintf(stderr,                  fmprintf(stderr,
                     "Executing: program %s host %s, user %s, command %s\n",                      "Executing: program %s host %s, user %s, command %s\n",
                     ssh_program, host,                      program, host,
                     remuser ? remuser : "(unspecified)", cmd);                      remuser ? remuser : "(unspecified)", cmd);
   
         if (port == -1)          if (port == -1)
Line 263 
Line 278 
                 close(pin[0]);                  close(pin[0]);
                 close(pout[1]);                  close(pout[1]);
   
                 replacearg(&args, 0, "%s", ssh_program);                  replacearg(&args, 0, "%s", program);
                 if (port != -1) {                  if (port != -1) {
                         addargs(&args, "-p");                          addargs(&args, "-p");
                         addargs(&args, "%d", port);                          addargs(&args, "%d", port);
Line 276 
Line 291 
                 addargs(&args, "%s", host);                  addargs(&args, "%s", host);
                 addargs(&args, "%s", cmd);                  addargs(&args, "%s", cmd);
   
                 execvp(ssh_program, args.list);                  execvp(program, args.list);
                 perror(ssh_program);                  perror(program);
                 exit(1);                  exit(1);
         } else if (do_cmd_pid == -1) {          } else if (do_cmd_pid == -1) {
                 fatal("fork: %s", strerror(errno));                  fatal("fork: %s", strerror(errno));
Line 368 
Line 383 
 #define CMDNEEDS        64  #define CMDNEEDS        64
 char cmd[CMDNEEDS];             /* must hold "rcp -r -p -d\0" */  char cmd[CMDNEEDS];             /* must hold "rcp -r -p -d\0" */
   
   enum scp_mode_e {
           MODE_SCP,
           MODE_SFTP
   };
   
 int response(void);  int response(void);
 void rsource(char *, struct stat *);  void rsource(char *, struct stat *);
 void sink(int, char *[], const char *);  void sink(int, char *[], const char *);
 void source(int, char *[]);  void source(int, char *[]);
 void tolocal(int, char *[]);  void tolocal(int, char *[], enum scp_mode_e, char *sftp_direct);
 void toremote(int, char *[]);  void toremote(int, char *[], enum scp_mode_e, char *sftp_direct);
 void usage(void);  void usage(void);
   
   void source_sftp(int, char *, char *, struct sftp_conn *, char **);
   void sink_sftp(int, char *, const char *, struct sftp_conn *);
   
 int  int
 main(int argc, char **argv)  main(int argc, char **argv)
 {  {
         int ch, fflag, tflag, status, n;          int ch, fflag, tflag, status, n;
         char **newargv;          char **newargv, *argv0;
         const char *errstr;          const char *errstr;
         extern char *optarg;          extern char *optarg;
         extern int optind;          extern int optind;
           /* For now, keep SCP as default */
           enum scp_mode_e mode = MODE_SCP;
           char *sftp_direct = NULL;
   
         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */          /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
         sanitise_stdfd();          sanitise_stdfd();
Line 391 
Line 417 
         setlocale(LC_CTYPE, "");          setlocale(LC_CTYPE, "");
   
         /* Copy argv, because we modify it */          /* Copy argv, because we modify it */
           argv0 = argv[0];
         newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));          newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
         for (n = 0; n < argc; n++)          for (n = 0; n < argc; n++)
                 newargv[n] = xstrdup(argv[n]);                  newargv[n] = xstrdup(argv[n]);
Line 408 
Line 435 
   
         fflag = Tflag = tflag = 0;          fflag = Tflag = tflag = 0;
         while ((ch = getopt(argc, argv,          while ((ch = getopt(argc, argv,
             "12346ABCTdfpqrtvF:J:P:S:c:i:l:o:")) != -1) {              "12346ABCTdfpqrtvD:F:J:M:P:S:c:i:l:o:")) != -1) {
                 switch (ch) {                  switch (ch) {
                 /* User-visible flags. */                  /* User-visible flags. */
                 case '1':                  case '1':
Line 424 
Line 451 
                         addargs(&args, "-%c", ch);                          addargs(&args, "-%c", ch);
                         addargs(&remote_remote_args, "-%c", ch);                          addargs(&remote_remote_args, "-%c", ch);
                         break;                          break;
                   case 'D':
                           sftp_direct = optarg;
                           break;
                 case '3':                  case '3':
                         throughlocal = 1;                          throughlocal = 1;
                         break;                          break;
Line 446 
Line 476 
                         addargs(&remote_remote_args, "-oBatchmode=yes");                          addargs(&remote_remote_args, "-oBatchmode=yes");
                         addargs(&args, "-oBatchmode=yes");                          addargs(&args, "-oBatchmode=yes");
                         break;                          break;
                   case 'M':
                           if (strcmp(optarg, "sftp") == 0)
                                   mode = MODE_SFTP;
                           else if (strcmp(optarg, "scp") == 0)
                                   mode = MODE_SCP;
                           else
                                   usage();
                           break;
                 case 'l':                  case 'l':
                         limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,                          limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
                             &errstr);                              &errstr);
Line 466 
Line 504 
                 case 'v':                  case 'v':
                         addargs(&args, "-v");                          addargs(&args, "-v");
                         addargs(&remote_remote_args, "-v");                          addargs(&remote_remote_args, "-v");
                           if (verbose_mode == 0)
                                   log_level = SYSLOG_LEVEL_DEBUG1;
                           else if (log_level < SYSLOG_LEVEL_DEBUG3)
                                   log_level++;
                         verbose_mode = 1;                          verbose_mode = 1;
                         break;                          break;
                 case 'q':                  case 'q':
Line 496 
Line 538 
         argc -= optind;          argc -= optind;
         argv += optind;          argv += optind;
   
           log_init(argv0, log_level, SYSLOG_FACILITY_USER, 1);
   
         /* Do this last because we want the user to be able to override it */          /* Do this last because we want the user to be able to override it */
         addargs(&args, "-oForwardAgent=no");          addargs(&args, "-oForwardAgent=no");
   
           if (mode != MODE_SFTP && sftp_direct != NULL)
                   fatal("SFTP direct can be used only in SFTP mode");
   
           if (mode == MODE_SFTP && iamremote)
                   fatal("The server can not be ran in SFTP mode");
   
         if ((pwd = getpwuid(userid = getuid())) == NULL)          if ((pwd = getpwuid(userid = getuid())) == NULL)
                 fatal("unknown user %u", (u_int) userid);                  fatal("unknown user %u", (u_int) userid);
   
Line 545 
Line 595 
         (void) ssh_signal(SIGPIPE, lostconn);          (void) ssh_signal(SIGPIPE, lostconn);
   
         if (colon(argv[argc - 1]))      /* Dest is remote host. */          if (colon(argv[argc - 1]))      /* Dest is remote host. */
                 toremote(argc, argv);                  toremote(argc, argv, mode, sftp_direct);
         else {          else {
                 if (targetshouldbedirectory)                  if (targetshouldbedirectory)
                         verifydir(argv[argc - 1]);                          verifydir(argv[argc - 1]);
                 tolocal(argc, argv);    /* Dest is local host. */                  tolocal(argc, argv, mode, sftp_direct); /* Dest is local host. */
         }          }
         /*          /*
          * Finally check the exit status of the ssh process, if one was forked           * Finally check the exit status of the ssh process, if one was forked
Line 860 
Line 910 
         return ret;          return ret;
 }  }
   
   static struct sftp_conn *
   do_sftp_connect(char *host, char *user, int port, char *sftp_direct)
   {
           if (sftp_direct == NULL) {
                   addargs(&args, "-s");
                   if (do_cmd(ssh_program, host, user, port, "sftp",
                       &remin, &remout) < 0)
                           return NULL;
   
           } else {
                   args.list = NULL;
                   addargs(&args, "sftp-server");
                   if (do_cmd(sftp_direct, host, NULL, -1, "sftp",
                       &remin, &remout) < 0)
                           return NULL;
           }
           return do_init(remin, remout, 32768, 64, limit_kbps);
   }
   
 void  void
 toremote(int argc, char **argv)  toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
 {  {
         char *suser = NULL, *host = NULL, *src = NULL;          char *suser = NULL, *host = NULL, *src = NULL;
         char *bp, *tuser, *thost, *targ;          char *bp, *tuser, *thost, *targ;
           char *remote_path = NULL;
         int sport = -1, tport = -1;          int sport = -1, tport = -1;
           struct sftp_conn *conn = NULL;
         arglist alist;          arglist alist;
         int i, r;          int i, r;
         u_int j;          u_int j;
Line 908 
Line 979 
                         continue;                          continue;
                 }                  }
                 if (host && throughlocal) {     /* extended remote to remote */                  if (host && throughlocal) {     /* extended remote to remote */
                           if (mode == MODE_SFTP) {
                                   /* TODO */
                                   fatal("Extended remote to remote through local "
                                       "is not yet supported with SFTP");
                           }
                         xasprintf(&bp, "%s -f %s%s", cmd,                          xasprintf(&bp, "%s -f %s%s", cmd,
                             *src == '-' ? "-- " : "", src);                              *src == '-' ? "-- " : "", src);
                         if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)                          if (do_cmd(ssh_program, host, suser, sport, bp,
                               &remin, &remout) < 0)
                                 exit(1);                                  exit(1);
                         free(bp);                          free(bp);
                         xasprintf(&bp, "%s -t %s%s", cmd,                          xasprintf(&bp, "%s -t %s%s", cmd,
Line 958 
Line 1035 
                         addargs(&alist, "--");                          addargs(&alist, "--");
                         addargs(&alist, "%s", host);                          addargs(&alist, "%s", host);
                         addargs(&alist, "%s", cmd);                          addargs(&alist, "%s", cmd);
                           /*
                            * This will work only if the first remote scp
                            * supports sftp mode
                            */
                           if (mode == MODE_SFTP) {
                                   addargs(&alist, "-M");
                                   addargs(&alist, "sftp");
                           }
                         addargs(&alist, "%s", src);                          addargs(&alist, "%s", src);
                         addargs(&alist, "%s%s%s:%s",                          addargs(&alist, "%s%s%s:%s",
                             tuser ? tuser : "", tuser ? "@" : "",                              tuser ? tuser : "", tuser ? "@" : "",
Line 965 
Line 1050 
                         if (do_local_cmd(&alist) != 0)                          if (do_local_cmd(&alist) != 0)
                                 errs = 1;                                  errs = 1;
                 } else {        /* local to remote */                  } else {        /* local to remote */
                           if (mode == MODE_SFTP) {
                                   if (remin == -1) {
                                           /* Connect to remote now */
                                           conn = do_sftp_connect(thost, tuser,
                                               tport, sftp_direct);
                                           if (conn == NULL) {
                                                   fatal("Unable to open sftp "
                                                       "connection");
                                           }
                                   }
   
                                   /* The protocol */
                                   source_sftp(1, argv[i], targ, conn,
                                       &remote_path);
                                   continue;
                           }
                           /* SCP */
                         if (remin == -1) {                          if (remin == -1) {
                                 xasprintf(&bp, "%s -t %s%s", cmd,                                  xasprintf(&bp, "%s -t %s%s", cmd,
                                     *targ == '-' ? "-- " : "", targ);                                      *targ == '-' ? "-- " : "", targ);
                                 if (do_cmd(thost, tuser, tport, bp, &remin,                                  if (do_cmd(ssh_program, thost, tuser, tport, bp,
                                     &remout) < 0)                                      &remin, &remout) < 0)
                                         exit(1);                                          exit(1);
                                 if (response() < 0)                                  if (response() < 0)
                                         exit(1);                                          exit(1);
Line 979 
Line 1081 
                 }                  }
         }          }
 out:  out:
           if (mode == MODE_SFTP) {
                   free(remote_path);
                   free(conn);
           }
         free(tuser);          free(tuser);
         free(thost);          free(thost);
         free(targ);          free(targ);
Line 988 
Line 1094 
 }  }
   
 void  void
 tolocal(int argc, char **argv)  tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
 {  {
         char *bp, *host = NULL, *src = NULL, *suser = NULL;          char *bp, *host = NULL, *src = NULL, *suser = NULL;
         arglist alist;          arglist alist;
           struct sftp_conn *conn = NULL;
         int i, r, sport = -1;          int i, r, sport = -1;
   
         memset(&alist, '\0', sizeof(alist));          memset(&alist, '\0', sizeof(alist));
Line 1028 
Line 1135 
                         continue;                          continue;
                 }                  }
                 /* Remote to local. */                  /* Remote to local. */
                   if (mode == MODE_SFTP) {
                           conn = do_sftp_connect(host, suser, sport, sftp_direct);
                           if (conn == NULL) {
                                   error("Couldn't make sftp connection "
                                       "to server");
                                   ++errs;
                                   continue;
                           }
   
                           /* The protocol */
                           sink_sftp(1, argv[argc - 1], src, conn);
   
                           free(conn);
                           (void) close(remin);
                           (void) close(remout);
                           remin = remout = -1;
                           continue;
                   }
                   /* SCP */
                 xasprintf(&bp, "%s -f %s%s",                  xasprintf(&bp, "%s -f %s%s",
                     cmd, *src == '-' ? "-- " : "", src);                      cmd, *src == '-' ? "-- " : "", src);
                 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {                  if (do_cmd(ssh_program, host, suser, sport, bp, &remin,
                       &remout) < 0) {
                         free(bp);                          free(bp);
                         ++errs;                          ++errs;
                         continue;                          continue;
Line 1046 
Line 1173 
 }  }
   
 void  void
   source_sftp(int argc, char *src, char *targ,
       struct sftp_conn *conn, char **remote_path)
   {
           char *target = NULL, *filename = NULL, *abs_dst = NULL;
           int target_is_dir;
   
           if (*remote_path == NULL) {
                   *remote_path = do_realpath(conn, ".");
                   if (*remote_path == NULL)
                           fatal("Unable to determine remote working directory");
           }
   
           if ((filename = basename(src)) == NULL)
                   fatal("basename %s: %s", src, strerror(errno));
   
           /*
            * No need to glob here - the local shell already took care of
            * the expansions
            */
           target = xstrdup(targ);
           target = make_absolute(target, *remote_path);
           target_is_dir = remote_is_dir(conn, target);
           if (targetshouldbedirectory && !target_is_dir) {
                   fatal("Target is not a directory, but more files selected "
                       "for upload");
           }
           if (target_is_dir)
                   abs_dst = path_append(target, filename);
           else {
                   abs_dst = target;
                   target = NULL;
           }
           debug3_f("copying local %s to remote %s", src, abs_dst);
   
           if (local_is_dir(src) && iamrecursive) {
                   if (upload_dir(conn, src, abs_dst, pflag, 1, 0, 0) != 0) {
                           fatal("failed to upload directory %s to %s",
                                   src, abs_dst);
                   }
           } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0)
                   fatal("failed to upload file %s to %s", src, abs_dst);
   
           free(abs_dst);
           free(target);
   }
   
   void
 source(int argc, char **argv)  source(int argc, char **argv)
 {  {
         struct stat stb;          struct stat stb;
Line 1206 
Line 1380 
         (void) response();          (void) response();
 }  }
   
   void
   sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
   {
           char *abs_src = NULL;
           char *abs_dst = NULL;
           glob_t g;
           char *filename, *tmp = NULL, *remote_path = NULL;
           int i, r, err = 0;
   
           /*
            * Here, we need remote glob as SFTP can not depend on remote shell
            * expansions
            */
   
           remote_path = do_realpath(conn, ".");
           if (remote_path == NULL) {
                   error("Could not obtain remote working directory");
                   /* TODO - gracefully degrade by using relative paths ? */
                   err = -1;
                   goto out;
           }
   
           abs_src = xstrdup(src);
           abs_src = make_absolute(abs_src, remote_path);
           free(remote_path);
           memset(&g, 0, sizeof(g));
   
           debug3_f("copying remote %s to local %s", abs_src, dst);
           if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
                   if (r == GLOB_NOSPACE)
                           error("Too many glob matches for \"%s\".", abs_src);
                   else
                           error("File \"%s\" not found.", abs_src);
                   err = -1;
                   goto out;
           }
   
           if (g.gl_matchc > 1 && !local_is_dir(dst)) {
                   error("Multiple files match pattern, but destination "
                       "\"%s\" is not a directory", dst);
                   err = -1;
                   goto out;
           }
   
           for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                   tmp = xstrdup(g.gl_pathv[i]);
                   if ((filename = basename(tmp)) == NULL) {
                           error("basename %s: %s", tmp, strerror(errno));
                           free(tmp);
                           err = -1;
                           goto out;
                   }
                   free(tmp);
   
                   if (local_is_dir(dst))
                           abs_dst = path_append(dst, filename);
                   else
                           abs_dst = xstrdup(dst);
   
                   debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
                   if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
                           if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
                               pflag, 1, 0, 0) == -1)
                                   err = -1;
                   } else {
                           if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
                               pflag, 0, 0) == -1)
                                   err = -1;
                   }
                   free(abs_dst);
                   abs_dst = NULL;
           }
   
   out:
           free(abs_src);
           globfree(&g);
           if (err == -1) {
                   fatal("Failed to download file '%s'", src);
           }
   }
   
   
 #define TYPE_OVERFLOW(type, val) \  #define TYPE_OVERFLOW(type, val) \
         ((sizeof(type) == 4 && (val) > INT32_MAX) || \          ((sizeof(type) == 4 && (val) > INT32_MAX) || \
          (sizeof(type) == 8 && (val) > INT64_MAX) || \           (sizeof(type) == 8 && (val) > INT64_MAX) || \
Line 1565 
Line 1821 
 usage(void)  usage(void)
 {  {
         (void) fprintf(stderr,          (void) fprintf(stderr,
             "usage: scp [-346ABCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n"              "usage: scp [-346ABCpqrTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n"
             "            [-J destination] [-l limit] [-o ssh_option] [-P port]\n"              "           [-i identity_file] [-J destination] [-l limit] [-M scp|sftp]\n"
             "            [-S program] source ... target\n");              "           [-o ssh_option] [-P port] [-S program] source ... target\n");
         exit(1);          exit(1);
 }  }
   

Legend:
Removed from v.1.215  
changed lines
  Added in v.1.216