2 * psftp.c: front end for PSFTP.
12 #define PUTTY_DO_GLOBALS
20 * Since SFTP is a request-response oriented protocol, it requires
21 * no buffer management: when we send data, we stop and wait for an
22 * acknowledgement _anyway_, and so we can't possibly overfill our
26 /* ----------------------------------------------------------------------
27 * String handling routines.
33 char *p = smalloc(len + 1);
38 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */
39 char *dupcat(char *s1, ...)
48 sn = va_arg(ap, char *);
61 sn = va_arg(ap, char *);
72 /* ----------------------------------------------------------------------
78 /* ----------------------------------------------------------------------
79 * Higher-level helper functions used in commands.
83 * Attempt to canonify a pathname starting from the pwd. If
84 * canonification fails, at least fall back to returning a _valid_
85 * pathname (though it may be ugly, eg /home/simon/../foobar).
87 char *canonify(char *name)
89 char *fullname, *canonname;
92 fullname = dupstr(name);
95 if (pwd[strlen(pwd) - 1] == '/')
99 fullname = dupcat(pwd, slash, name, NULL);
102 canonname = fxp_realpath(fullname);
109 * Attempt number 2. Some FXP_REALPATH implementations
110 * (glibc-based ones, in particular) require the _whole_
111 * path to point to something that exists, whereas others
112 * (BSD-based) only require all but the last component to
113 * exist. So if the first call failed, we should strip off
114 * everything from the last slash onwards and try again,
115 * then put the final component back on.
119 * - if the last component is "/." or "/..", then we don't
120 * bother trying this because there's no way it can work.
122 * - if the thing actually ends with a "/", we remove it
123 * before we start. Except if the string is "/" itself
124 * (although I can't see why we'd have got here if so,
125 * because surely "/" would have worked the first
126 * time?), in which case we don't bother.
128 * - if there's no slash in the string at all, give up in
129 * confusion (we expect at least one because of the way
130 * we constructed the string).
136 i = strlen(fullname);
137 if (i > 2 && fullname[i - 1] == '/')
138 fullname[--i] = '\0'; /* strip trailing / unless at pos 0 */
139 while (i > 0 && fullname[--i] != '/');
142 * Give up on special cases.
144 if (fullname[i] != '/' || /* no slash at all */
145 !strcmp(fullname + i, "/.") || /* ends in /. */
146 !strcmp(fullname + i, "/..") || /* ends in /.. */
147 !strcmp(fullname, "/")) {
152 * Now i points at the slash. Deal with the final special
153 * case i==0 (ie the whole path was "/nonexistentfile").
155 fullname[i] = '\0'; /* separate the string */
157 canonname = fxp_realpath("/");
159 canonname = fxp_realpath(fullname);
163 return fullname; /* even that failed; give up */
166 * We have a canonical name for all but the last path
167 * component. Concatenate the last component and return.
169 returnname = dupcat(canonname,
170 canonname[strlen(canonname) - 1] ==
171 '/' ? "" : "/", fullname + i + 1, NULL);
178 /* ----------------------------------------------------------------------
179 * Actual sftp commands.
181 struct sftp_command {
183 int nwords, wordssize;
184 int (*obey) (struct sftp_command *); /* returns <0 to quit */
187 int sftp_cmd_null(struct sftp_command *cmd)
192 int sftp_cmd_unknown(struct sftp_command *cmd)
194 printf("psftp: unknown command \"%s\"\n", cmd->words[0]);
198 int sftp_cmd_quit(struct sftp_command *cmd)
204 * List a directory. If no arguments are given, list pwd; otherwise
205 * list the directory given in words[1].
207 static int sftp_ls_compare(const void *av, const void *bv)
209 const struct fxp_name *a = (const struct fxp_name *) av;
210 const struct fxp_name *b = (const struct fxp_name *) bv;
211 return strcmp(a->filename, b->filename);
213 int sftp_cmd_ls(struct sftp_command *cmd)
215 struct fxp_handle *dirh;
216 struct fxp_names *names;
217 struct fxp_name *ournames;
218 int nnames, namesize;
227 cdir = canonify(dir);
229 printf("%s: %s\n", dir, fxp_error());
233 printf("Listing directory %s\n", cdir);
235 dirh = fxp_opendir(cdir);
237 printf("Unable to open %s: %s\n", dir, fxp_error());
239 nnames = namesize = 0;
244 names = fxp_readdir(dirh);
246 if (fxp_error_type() == SSH_FX_EOF)
248 printf("Reading directory %s: %s\n", dir, fxp_error());
251 if (names->nnames == 0) {
252 fxp_free_names(names);
256 if (nnames + names->nnames >= namesize) {
257 namesize += names->nnames + 128;
259 srealloc(ournames, namesize * sizeof(*ournames));
262 for (i = 0; i < names->nnames; i++)
263 ournames[nnames++] = names->names[i];
265 names->nnames = 0; /* prevent free_names */
266 fxp_free_names(names);
271 * Now we have our filenames. Sort them by actual file
272 * name, and then output the longname parts.
274 qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
279 for (i = 0; i < nnames; i++)
280 printf("%s\n", ournames[i].longname);
289 * Change directories. We do this by canonifying the new name, then
290 * trying to OPENDIR it. Only if that succeeds do we set the new pwd.
292 int sftp_cmd_cd(struct sftp_command *cmd)
294 struct fxp_handle *dirh;
298 dir = dupstr(homedir);
300 dir = canonify(cmd->words[1]);
303 printf("%s: %s\n", dir, fxp_error());
307 dirh = fxp_opendir(dir);
309 printf("Directory %s: %s\n", dir, fxp_error());
318 printf("Remote directory is now %s\n", pwd);
324 * Get a file and save it at the local end.
326 int sftp_cmd_get(struct sftp_command *cmd)
328 struct fxp_handle *fh;
329 char *fname, *outfname;
333 if (cmd->nwords < 2) {
334 printf("get: expects a filename\n");
338 fname = canonify(cmd->words[1]);
340 printf("%s: %s\n", cmd->words[1], fxp_error());
343 outfname = (cmd->nwords == 2 ? cmd->words[1] : cmd->words[2]);
345 fh = fxp_open(fname, SSH_FXF_READ);
347 printf("%s: %s\n", fname, fxp_error());
351 fp = fopen(outfname, "wb");
353 printf("local: unable to open %s\n", outfname);
359 printf("remote:%s => local:%s\n", fname, outfname);
361 offset = uint64_make(0, 0);
364 * FIXME: we can use FXP_FSTAT here to get the file size, and
365 * thus put up a progress bar.
372 len = fxp_read(fh, buffer, offset, sizeof(buffer));
373 if ((len == -1 && fxp_error_type() == SSH_FX_EOF) || len == 0)
376 printf("error while reading: %s\n", fxp_error());
382 wlen = fwrite(buffer, 1, len - wpos, fp);
384 printf("error while writing local file\n");
389 if (wpos < len) /* we had an error */
391 offset = uint64_add32(offset, len);
402 * Send a file and store it at the remote end.
404 int sftp_cmd_put(struct sftp_command *cmd)
406 struct fxp_handle *fh;
407 char *fname, *origoutfname, *outfname;
411 if (cmd->nwords < 2) {
412 printf("put: expects a filename\n");
416 fname = cmd->words[1];
417 origoutfname = (cmd->nwords == 2 ? cmd->words[1] : cmd->words[2]);
418 outfname = canonify(origoutfname);
420 printf("%s: %s\n", origoutfname, fxp_error());
424 fp = fopen(fname, "rb");
426 printf("local: unable to open %s\n", fname);
430 fh = fxp_open(outfname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
432 printf("%s: %s\n", outfname, fxp_error());
437 printf("local:%s => remote:%s\n", fname, outfname);
439 offset = uint64_make(0, 0);
442 * FIXME: we can use FXP_FSTAT here to get the file size, and
443 * thus put up a progress bar.
449 len = fread(buffer, 1, sizeof(buffer), fp);
451 printf("error while reading local file\n");
453 } else if (len == 0) {
456 if (!fxp_write(fh, buffer, offset, len)) {
457 printf("error while writing: %s\n", fxp_error());
460 offset = uint64_add32(offset, len);
470 int sftp_cmd_mkdir(struct sftp_command *cmd)
476 if (cmd->nwords < 2) {
477 printf("mkdir: expects a directory\n");
481 dir = canonify(cmd->words[1]);
483 printf("%s: %s\n", dir, fxp_error());
487 result = fxp_mkdir(dir);
489 printf("mkdir %s: %s\n", dir, fxp_error());
499 int sftp_cmd_rmdir(struct sftp_command *cmd)
505 if (cmd->nwords < 2) {
506 printf("rmdir: expects a directory\n");
510 dir = canonify(cmd->words[1]);
512 printf("%s: %s\n", dir, fxp_error());
516 result = fxp_rmdir(dir);
518 printf("rmdir %s: %s\n", dir, fxp_error());
528 int sftp_cmd_rm(struct sftp_command *cmd)
534 if (cmd->nwords < 2) {
535 printf("rm: expects a filename\n");
539 fname = canonify(cmd->words[1]);
541 printf("%s: %s\n", fname, fxp_error());
545 result = fxp_rm(fname);
547 printf("rm %s: %s\n", fname, fxp_error());
558 static struct sftp_cmd_lookup {
560 int (*obey) (struct sftp_command *);
563 * List of sftp commands. This is binary-searched so it MUST be
567 "bye", sftp_cmd_quit}, {
568 "cd", sftp_cmd_cd}, {
569 "dir", sftp_cmd_ls}, {
570 "exit", sftp_cmd_quit}, {
571 "get", sftp_cmd_get}, {
572 "ls", sftp_cmd_ls}, {
573 "mkdir", sftp_cmd_mkdir}, {
574 "put", sftp_cmd_put}, {
575 "quit", sftp_cmd_quit}, {
576 "rm", sftp_cmd_rm}, {
577 "rmdir", sftp_cmd_rmdir},};
579 /* ----------------------------------------------------------------------
580 * Command line reading and parsing.
582 struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
585 int linelen, linesize;
586 struct sftp_command *cmd;
590 if ((mode == 0) || (modeflags & 1)) {
595 cmd = smalloc(sizeof(struct sftp_command));
601 linesize = linelen = 0;
607 line = srealloc(line, linesize);
608 ret = fgets(line + linelen, linesize - linelen, fp);
613 if (!ret || (linelen == 0 && line[0] == '\0')) {
614 cmd->obey = sftp_cmd_quit;
616 return cmd; /* eof */
618 len = linelen + strlen(line + linelen);
620 if (line[linelen - 1] == '\n') {
622 line[linelen] = '\0';
628 * Parse the command line into words. The syntax is:
629 * - double quotes are removed, but cause spaces within to be
630 * treated as non-separating.
631 * - a double-doublequote pair is a literal double quote, inside
632 * _or_ outside quotes. Like this:
634 * firstword "second word" "this has ""quotes"" in" sodoes""this""
640 * >this has "quotes" in<
645 /* skip whitespace */
646 while (*p && (*p == ' ' || *p == '\t'))
648 /* mark start of word */
649 q = r = p; /* q sits at start, r writes word */
652 if (!quoting && (*p == ' ' || *p == '\t'))
653 break; /* reached end of word */
654 else if (*p == '"' && p[1] == '"')
655 p += 2, *r++ = '"'; /* a literal quote */
657 p++, quoting = !quoting;
662 p++; /* skip over the whitespace */
664 if (cmd->nwords >= cmd->wordssize) {
665 cmd->wordssize = cmd->nwords + 16;
667 srealloc(cmd->words, cmd->wordssize * sizeof(char *));
669 cmd->words[cmd->nwords++] = q;
673 * Now parse the first word and assign a function.
676 if (cmd->nwords == 0)
677 cmd->obey = sftp_cmd_null;
681 cmd->obey = sftp_cmd_unknown;
684 j = sizeof(sftp_lookup) / sizeof(*sftp_lookup);
687 cmp = strcmp(cmd->words[0], sftp_lookup[k].name);
693 cmd->obey = sftp_lookup[k].obey;
702 void do_sftp(int mode, int modeflags, char *batchfile)
707 * Do protocol initialisation.
711 "Fatal: unable to initialise SFTP: %s\n", fxp_error());
716 * Find out where our home directory is.
718 homedir = fxp_realpath(".");
721 "Warning: failed to resolve home directory: %s\n",
723 homedir = dupstr(".");
725 printf("Remote working directory is %s\n", homedir);
727 pwd = dupstr(homedir);
734 /* ------------------------------------------------------------------
735 * Now we're ready to do Real Stuff.
738 struct sftp_command *cmd;
739 cmd = sftp_getcmd(stdin, 0, 0);
742 if (cmd->obey(cmd) < 0)
746 fp = fopen(batchfile, "r");
748 printf("Fatal: unable to open %s\n", batchfile);
752 struct sftp_command *cmd;
753 cmd = sftp_getcmd(fp, mode, modeflags);
756 if (cmd->obey(cmd) < 0)
758 if (fxp_error() != NULL) {
759 if (!(modeflags & 2))
768 /* ----------------------------------------------------------------------
769 * Dirty bits: integration with PuTTY.
772 static int verbose = 0;
774 void verify_ssh_host_key(char *host, int port, char *keytype,
775 char *keystr, char *fingerprint)
781 static const char absentmsg[] =
782 "The server's host key is not cached in the registry. You\n"
783 "have no guarantee that the server is the computer you\n"
785 "The server's key fingerprint is:\n"
787 "If you trust this host, enter \"y\" to add the key to\n"
788 "PuTTY's cache and carry on connecting.\n"
789 "If you want to carry on connecting just once, without\n"
790 "adding the key to the cache, enter \"n\".\n"
791 "If you do not trust this host, press Return to abandon the\n"
793 "Store key in cache? (y/n) ";
795 static const char wrongmsg[] =
796 "WARNING - POTENTIAL SECURITY BREACH!\n"
797 "The server's host key does not match the one PuTTY has\n"
798 "cached in the registry. This means that either the\n"
799 "server administrator has changed the host key, or you\n"
800 "have actually connected to another computer pretending\n"
801 "to be the server.\n"
802 "The new key fingerprint is:\n"
804 "If you were expecting this change and trust the new key,\n"
805 "enter \"y\" to update PuTTY's cache and continue connecting.\n"
806 "If you want to carry on connecting but without updating\n"
807 "the cache, enter \"n\".\n"
808 "If you want to abandon the connection completely, press\n"
809 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
811 "Update cached key? (y/n, Return cancels connection) ";
813 static const char abandoned[] = "Connection abandoned.\n";
818 * Verify the key against the registry.
820 ret = verify_host_key(host, port, keytype, keystr);
822 if (ret == 0) /* success - key matched OK */
825 if (ret == 2) { /* key was different */
826 fprintf(stderr, wrongmsg, fingerprint);
829 if (ret == 1) { /* key was absent */
830 fprintf(stderr, absentmsg, fingerprint);
834 hin = GetStdHandle(STD_INPUT_HANDLE);
835 GetConsoleMode(hin, &savemode);
836 SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
837 ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
838 ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
839 SetConsoleMode(hin, savemode);
841 if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
842 if (line[0] == 'y' || line[0] == 'Y')
843 store_host_key(host, port, keytype, keystr);
845 fprintf(stderr, abandoned);
851 * Ask whether the selected cipher is acceptable (since it was
852 * below the configured 'warn' threshold).
853 * cs: 0 = both ways, 1 = client->server, 2 = server->client
855 void askcipher(char *ciphername, int cs)
860 static const char msg[] =
861 "The first %scipher supported by the server is\n"
862 "%s, which is below the configured warning threshold.\n"
863 "Continue with connection? (y/n) ";
864 static const char abandoned[] = "Connection abandoned.\n";
870 (cs == 1) ? "client-to-server " :
875 hin = GetStdHandle(STD_INPUT_HANDLE);
876 GetConsoleMode(hin, &savemode);
877 SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
878 ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
879 ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
880 SetConsoleMode(hin, savemode);
882 if (line[0] == 'y' || line[0] == 'Y') {
885 fprintf(stderr, abandoned);
891 * Print an error message and perform a fatal exit.
893 void fatalbox(char *fmt, ...)
895 char str[0x100]; /* Make the size big enough */
898 strcpy(str, "Fatal:");
899 vsprintf(str + strlen(str), fmt, ap);
902 fprintf(stderr, str);
906 void connection_fatal(char *fmt, ...)
908 char str[0x100]; /* Make the size big enough */
911 strcpy(str, "Fatal:");
912 vsprintf(str + strlen(str), fmt, ap);
915 fprintf(stderr, str);
920 void logevent(char *string)
924 void ldisc_send(char *buf, int len)
927 * This is only here because of the calls to ldisc_send(NULL,
928 * 0) in ssh.c. Nothing in PSFTP actually needs to use the
929 * ldisc as an ldisc. So if we get called with any real data, I
930 * want to know about it.
936 * Be told what socket we're supposed to be using.
938 static SOCKET sftp_ssh_socket;
939 char *do_select(SOCKET skt, int startup)
942 sftp_ssh_socket = skt;
944 sftp_ssh_socket = INVALID_SOCKET;
947 extern int select_result(WPARAM, LPARAM);
950 * Receive a block of data from the SSH link. Block until all data
953 * To do this, we repeatedly call the SSH protocol module, with our
954 * own trap in from_backend() to catch the data that comes back. We
955 * do this until we have enough data.
958 static unsigned char *outptr; /* where to put the data */
959 static unsigned outlen; /* how much data required */
960 static unsigned char *pending = NULL; /* any spare data */
961 static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */
962 int from_backend(int is_stderr, char *data, int datalen)
964 unsigned char *p = (unsigned char *) data;
965 unsigned len = (unsigned) datalen;
968 * stderr data is just spouted to local stderr and otherwise
972 fwrite(data, 1, len, stderr);
977 * If this is before the real session begins, just return.
983 unsigned used = outlen;
986 memcpy(outptr, p, used);
994 if (pendsize < pendlen + len) {
995 pendsize = pendlen + len + 4096;
996 pending = (pending ? srealloc(pending, pendsize) :
999 fatalbox("Out of memory");
1001 memcpy(pending + pendlen, p, len);
1007 int sftp_recvdata(char *buf, int len)
1009 outptr = (unsigned char *) buf;
1013 * See if the pending-input block contains some of what we
1017 unsigned pendused = pendlen;
1018 if (pendused > outlen)
1020 memcpy(outptr, pending, pendused);
1021 memmove(pending, pending + pendused, pendlen - pendused);
1024 pendlen -= pendused;
1034 while (outlen > 0) {
1038 FD_SET(sftp_ssh_socket, &readfds);
1039 if (select(1, &readfds, NULL, NULL, NULL) < 0)
1040 return 0; /* doom */
1041 select_result((WPARAM) sftp_ssh_socket, (LPARAM) FD_READ);
1046 int sftp_senddata(char *buf, int len)
1048 back->send((unsigned char *) buf, len);
1053 * Loop through the ssh connection and authentication process.
1055 static void ssh_sftp_init(void)
1057 if (sftp_ssh_socket == INVALID_SOCKET)
1059 while (!back->sendok()) {
1062 FD_SET(sftp_ssh_socket, &readfds);
1063 if (select(1, &readfds, NULL, NULL, NULL) < 0)
1065 select_result((WPARAM) sftp_ssh_socket, (LPARAM) FD_READ);
1069 static char *password = NULL;
1070 static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
1073 DWORD savemode, newmode, i;
1076 static int tried_once = 0;
1081 strncpy(str, password, maxlen);
1082 str[maxlen - 1] = '\0';
1088 hin = GetStdHandle(STD_INPUT_HANDLE);
1089 hout = GetStdHandle(STD_OUTPUT_HANDLE);
1090 if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE) {
1091 fprintf(stderr, "Cannot get standard input/output handles\n");
1095 GetConsoleMode(hin, &savemode);
1096 newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
1098 newmode &= ~ENABLE_ECHO_INPUT;
1100 newmode |= ENABLE_ECHO_INPUT;
1101 SetConsoleMode(hin, newmode);
1103 WriteFile(hout, prompt, strlen(prompt), &i, NULL);
1104 ReadFile(hin, str, maxlen - 1, &i, NULL);
1106 SetConsoleMode(hin, savemode);
1108 if ((int) i > maxlen)
1115 WriteFile(hout, "\r\n", 2, &i, NULL);
1121 * Initialize the Win$ock driver.
1123 static void init_winsock(void)
1128 winsock_ver = MAKEWORD(1, 1);
1129 if (WSAStartup(winsock_ver, &wsadata)) {
1130 fprintf(stderr, "Unable to initialise WinSock");
1133 if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
1134 fprintf(stderr, "WinSock version is incompatible with 1.1");
1140 * Short description of parameters.
1142 static void usage(void)
1144 printf("PuTTY Secure File Transfer (SFTP) client\n");
1145 printf("%s\n", ver);
1146 printf("Usage: psftp [options] user@host\n");
1147 printf("Options:\n");
1148 printf(" -b file use specified batchfile\n");
1149 printf(" -bc output batchfile commands\n");
1150 printf(" -be don't stop batchfile processing if errors\n");
1151 printf(" -v show verbose messages\n");
1152 printf(" -P port connect to specified port\n");
1153 printf(" -pw passw login with specified password\n");
1158 * Main program. Parse arguments etc.
1160 int main(int argc, char *argv[])
1164 char *user, *host, *userhost, *realhost;
1168 char *batchfile = NULL;
1170 flags = FLAG_STDERR;
1171 ssh_get_line = &get_line;
1175 userhost = user = NULL;
1177 for (i = 1; i < argc; i++) {
1178 if (argv[i][0] != '-') {
1182 userhost = dupstr(argv[i]);
1183 } else if (strcmp(argv[i], "-v") == 0) {
1184 verbose = 1, flags |= FLAG_VERBOSE;
1185 } else if (strcmp(argv[i], "-h") == 0 ||
1186 strcmp(argv[i], "-?") == 0) {
1188 } else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) {
1190 } else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc) {
1191 portnumber = atoi(argv[++i]);
1192 } else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc) {
1193 password = argv[++i];
1194 } else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) {
1196 batchfile = argv[++i];
1197 } else if (strcmp(argv[i], "-bc") == 0 && i + 1 < argc) {
1198 modeflags = modeflags | 1;
1199 } else if (strcmp(argv[i], "-be") == 0 && i + 1 < argc) {
1200 modeflags = modeflags | 2;
1201 } else if (strcmp(argv[i], "--") == 0) {
1212 if (argc > 0 || !userhost)
1215 /* Separate host and username */
1217 host = strrchr(host, '@');
1223 printf("psftp: multiple usernames specified; using \"%s\"\n",
1229 /* Try to load settings for this host */
1230 do_defaults(host, &cfg);
1231 if (cfg.host[0] == '\0') {
1232 /* No settings for this host; use defaults */
1233 do_defaults(NULL, &cfg);
1234 strncpy(cfg.host, host, sizeof(cfg.host) - 1);
1235 cfg.host[sizeof(cfg.host) - 1] = '\0';
1240 if (user != NULL && user[0] != '\0') {
1241 strncpy(cfg.username, user, sizeof(cfg.username) - 1);
1242 cfg.username[sizeof(cfg.username) - 1] = '\0';
1244 if (!cfg.username[0]) {
1245 printf("login as: ");
1246 if (!fgets(cfg.username, sizeof(cfg.username), stdin)) {
1247 fprintf(stderr, "psftp: aborting\n");
1250 int len = strlen(cfg.username);
1251 if (cfg.username[len - 1] == '\n')
1252 cfg.username[len - 1] = '\0';
1256 if (cfg.protocol != PROT_SSH)
1260 cfg.port = portnumber;
1262 /* SFTP uses SSH2 by default always */
1265 /* Set up subsystem name. FIXME: fudge for SSH1. */
1266 strcpy(cfg.remote_cmd, "sftp");
1267 cfg.ssh_subsys = TRUE;
1270 back = &ssh_backend;
1272 err = back->init(cfg.host, cfg.port, &realhost);
1274 fprintf(stderr, "ssh_init: %s", err);
1278 if (verbose && realhost != NULL)
1279 printf("Connected to %s\n", realhost);
1281 do_sftp(mode, modeflags, batchfile);
1283 if (back != NULL && back->socket() != NULL) {
1285 back->special(TS_EOF);
1286 sftp_recvdata(&ch, 1);