1 /* 2 * Copyright (c) 2001 Damien Miller. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include "includes.h" 26 27 RCSID("$OpenBSD: sftp.c,v 1.22 2001/12/19 07:18:56 deraadt Exp $"); 28 29 /* XXX: commandline mode */ 30 /* XXX: short-form remote directory listings (like 'ls -C') */ 31 32 #include "buffer.h" 33 #include "xmalloc.h" 34 #include "log.h" 35 #include "pathnames.h" 36 #include "misc.h" 37 38 #include "sftp.h" 39 #include "sftp-common.h" 40 #include "sftp-client.h" 41 #include "sftp-int.h" 42 43 char *ssh_program = _PATH_SSH_PROGRAM; 44 FILE* infile; 45 46 static void 47 connect_to_server(char **args, int *in, int *out, pid_t *sshpid) 48 { 49 int c_in, c_out; 50 #ifdef USE_PIPES 51 int pin[2], pout[2]; 52 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 53 fatal("pipe: %s", strerror(errno)); 54 *in = pin[0]; 55 *out = pout[1]; 56 c_in = pout[0]; 57 c_out = pin[1]; 58 #else /* USE_PIPES */ 59 int inout[2]; 60 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 61 fatal("socketpair: %s", strerror(errno)); 62 *in = *out = inout[0]; 63 c_in = c_out = inout[1]; 64 #endif /* USE_PIPES */ 65 66 if ((*sshpid = fork()) == -1) 67 fatal("fork: %s", strerror(errno)); 68 else if (*sshpid == 0) { 69 if ((dup2(c_in, STDIN_FILENO) == -1) || 70 (dup2(c_out, STDOUT_FILENO) == -1)) { 71 fprintf(stderr, "dup2: %s\n", strerror(errno)); 72 exit(1); 73 } 74 close(*in); 75 close(*out); 76 close(c_in); 77 close(c_out); 78 execv(ssh_program, args); 79 fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno)); 80 exit(1); 81 } 82 83 close(c_in); 84 close(c_out); 85 } 86 87 static void 88 usage(void) 89 { 90 fprintf(stderr, 91 "usage: sftp [-1Cv] [-b batchfile] [-F config] [-o option] [-s subsystem|path]\n" 92 " [-S program] [user@]host[:file [file]]\n"); 93 exit(1); 94 } 95 96 int 97 main(int argc, char **argv) 98 { 99 int in, out, ch; 100 pid_t sshpid; 101 char *host, *userhost, *cp, *file2; 102 int debug_level = 0, sshver = 2; 103 char *file1 = NULL, *sftp_server = NULL; 104 LogLevel ll = SYSLOG_LEVEL_INFO; 105 arglist args; 106 extern int optind; 107 extern char *optarg; 108 109 args.list = NULL; 110 addargs(&args, "ssh"); /* overwritten with ssh_program */ 111 addargs(&args, "-oFallBackToRsh no"); 112 addargs(&args, "-oForwardX11 no"); 113 addargs(&args, "-oForwardAgent no"); 114 addargs(&args, "-oClearAllForwardings yes"); 115 ll = SYSLOG_LEVEL_INFO; 116 infile = stdin; /* Read from STDIN unless changed by -b */ 117 118 while ((ch = getopt(argc, argv, "1hvCo:s:S:b:F:")) != -1) { 119 switch (ch) { 120 case 'C': 121 addargs(&args, "-C"); 122 break; 123 case 'v': 124 if (debug_level < 3) { 125 addargs(&args, "-v"); 126 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 127 } 128 debug_level++; 129 break; 130 case 'F': 131 case 'o': 132 addargs(&args, "-%c%s", ch, optarg); 133 break; 134 case '1': 135 sshver = 1; 136 if (sftp_server == NULL) 137 sftp_server = _PATH_SFTP_SERVER; 138 break; 139 case 's': 140 sftp_server = optarg; 141 break; 142 case 'S': 143 ssh_program = optarg; 144 break; 145 case 'b': 146 if (infile == stdin) { 147 infile = fopen(optarg, "r"); 148 if (infile == NULL) 149 fatal("%s (%s).", strerror(errno), optarg); 150 } else 151 fatal("Filename already specified."); 152 break; 153 case 'h': 154 default: 155 usage(); 156 } 157 } 158 159 if (optind == argc || argc > (optind + 2)) 160 usage(); 161 162 userhost = xstrdup(argv[optind]); 163 file2 = argv[optind+1]; 164 165 if ((cp = colon(userhost)) != NULL) { 166 *cp++ = '\0'; 167 file1 = cp; 168 } 169 170 if ((host = strchr(userhost, '@')) == NULL) 171 host = userhost; 172 else { 173 *host++ = '\0'; 174 if (!userhost[0]) { 175 fprintf(stderr, "Missing username\n"); 176 usage(); 177 } 178 addargs(&args, "-l%s",userhost); 179 } 180 181 host = cleanhostname(host); 182 if (!*host) { 183 fprintf(stderr, "Missing hostname\n"); 184 usage(); 185 } 186 187 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 188 addargs(&args, "-oProtocol %d", sshver); 189 190 /* no subsystem if the server-spec contains a '/' */ 191 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 192 addargs(&args, "-s"); 193 194 addargs(&args, "%s", host); 195 addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); 196 args.list[0] = ssh_program; 197 198 fprintf(stderr, "Connecting to %s...\n", host); 199 200 connect_to_server(args.list, &in, &out, &sshpid); 201 202 interactive_loop(in, out, file1, file2); 203 204 close(in); 205 close(out); 206 if (infile != stdin) 207 fclose(infile); 208 209 if (waitpid(sshpid, NULL, 0) == -1) 210 fatal("Couldn't wait for ssh process: %s", strerror(errno)); 211 212 exit(0); 213 } 214