2 * psftp.c: front end for PSFTP.
12 #define PUTTY_DO_GLOBALS
19 /* ----------------------------------------------------------------------
20 * String handling routines.
26 char *p
= smalloc(len
+ 1);
31 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */
32 char *dupcat(char *s1
, ...)
41 sn
= va_arg(ap
, char *);
54 sn
= va_arg(ap
, char *);
65 /* ----------------------------------------------------------------------
71 /* ----------------------------------------------------------------------
72 * Higher-level helper functions used in commands.
76 * Attempt to canonify a pathname starting from the pwd. If
77 * canonification fails, at least fall back to returning a _valid_
78 * pathname (though it may be ugly, eg /home/simon/../foobar).
80 char *canonify(char *name
)
82 char *fullname
, *canonname
;
85 fullname
= dupstr(name
);
88 if (pwd
[strlen(pwd
) - 1] == '/')
92 fullname
= dupcat(pwd
, slash
, name
, NULL
);
95 canonname
= fxp_realpath(fullname
);
102 * Attempt number 2. Some FXP_REALPATH implementations
103 * (glibc-based ones, in particular) require the _whole_
104 * path to point to something that exists, whereas others
105 * (BSD-based) only require all but the last component to
106 * exist. So if the first call failed, we should strip off
107 * everything from the last slash onwards and try again,
108 * then put the final component back on.
112 * - if the last component is "/." or "/..", then we don't
113 * bother trying this because there's no way it can work.
115 * - if the thing actually ends with a "/", we remove it
116 * before we start. Except if the string is "/" itself
117 * (although I can't see why we'd have got here if so,
118 * because surely "/" would have worked the first
119 * time?), in which case we don't bother.
121 * - if there's no slash in the string at all, give up in
122 * confusion (we expect at least one because of the way
123 * we constructed the string).
129 i
= strlen(fullname
);
130 if (i
> 2 && fullname
[i
- 1] == '/')
131 fullname
[--i
] = '\0'; /* strip trailing / unless at pos 0 */
132 while (i
> 0 && fullname
[--i
] != '/');
135 * Give up on special cases.
137 if (fullname
[i
] != '/' || /* no slash at all */
138 !strcmp(fullname
+ i
, "/.") || /* ends in /. */
139 !strcmp(fullname
+ i
, "/..") || /* ends in /.. */
140 !strcmp(fullname
, "/")) {
145 * Now i points at the slash. Deal with the final special
146 * case i==0 (ie the whole path was "/nonexistentfile").
148 fullname
[i
] = '\0'; /* separate the string */
150 canonname
= fxp_realpath("/");
152 canonname
= fxp_realpath(fullname
);
156 return fullname
; /* even that failed; give up */
159 * We have a canonical name for all but the last path
160 * component. Concatenate the last component and return.
162 returnname
= dupcat(canonname
,
163 canonname
[strlen(canonname
) - 1] ==
164 '/' ?
"" : "/", fullname
+ i
+ 1, NULL
);
171 /* ----------------------------------------------------------------------
172 * Actual sftp commands.
174 struct sftp_command
{
176 int nwords
, wordssize
;
177 int (*obey
) (struct sftp_command
*); /* returns <0 to quit */
180 int sftp_cmd_null(struct sftp_command
*cmd
)
185 int sftp_cmd_unknown(struct sftp_command
*cmd
)
187 printf("psftp: unknown command \"%s\"\n", cmd
->words
[0]);
191 int sftp_cmd_quit(struct sftp_command
*cmd
)
197 * List a directory. If no arguments are given, list pwd; otherwise
198 * list the directory given in words[1].
200 static int sftp_ls_compare(const void *av
, const void *bv
)
202 const struct fxp_name
*a
= (const struct fxp_name
*) av
;
203 const struct fxp_name
*b
= (const struct fxp_name
*) bv
;
204 return strcmp(a
->filename
, b
->filename
);
206 int sftp_cmd_ls(struct sftp_command
*cmd
)
208 struct fxp_handle
*dirh
;
209 struct fxp_names
*names
;
210 struct fxp_name
*ournames
;
211 int nnames
, namesize
;
220 cdir
= canonify(dir
);
222 printf("%s: %s\n", dir
, fxp_error());
226 printf("Listing directory %s\n", cdir
);
228 dirh
= fxp_opendir(cdir
);
230 printf("Unable to open %s: %s\n", dir
, fxp_error());
232 nnames
= namesize
= 0;
237 names
= fxp_readdir(dirh
);
239 if (fxp_error_type() == SSH_FX_EOF
)
241 printf("Reading directory %s: %s\n", dir
, fxp_error());
244 if (names
->nnames
== 0) {
245 fxp_free_names(names
);
249 if (nnames
+ names
->nnames
>= namesize
) {
250 namesize
+= names
->nnames
+ 128;
252 srealloc(ournames
, namesize
* sizeof(*ournames
));
255 for (i
= 0; i
< names
->nnames
; i
++)
256 ournames
[nnames
++] = names
->names
[i
];
258 names
->nnames
= 0; /* prevent free_names */
259 fxp_free_names(names
);
264 * Now we have our filenames. Sort them by actual file
265 * name, and then output the longname parts.
267 qsort(ournames
, nnames
, sizeof(*ournames
), sftp_ls_compare
);
272 for (i
= 0; i
< nnames
; i
++)
273 printf("%s\n", ournames
[i
].longname
);
282 * Change directories. We do this by canonifying the new name, then
283 * trying to OPENDIR it. Only if that succeeds do we set the new pwd.
285 int sftp_cmd_cd(struct sftp_command
*cmd
)
287 struct fxp_handle
*dirh
;
291 dir
= dupstr(homedir
);
293 dir
= canonify(cmd
->words
[1]);
296 printf("%s: %s\n", dir
, fxp_error());
300 dirh
= fxp_opendir(dir
);
302 printf("Directory %s: %s\n", dir
, fxp_error());
311 printf("Remote directory is now %s\n", pwd
);
317 * Get a file and save it at the local end.
319 int sftp_cmd_get(struct sftp_command
*cmd
)
321 struct fxp_handle
*fh
;
322 char *fname
, *outfname
;
326 if (cmd
->nwords
< 2) {
327 printf("get: expects a filename\n");
331 fname
= canonify(cmd
->words
[1]);
333 printf("%s: %s\n", cmd
->words
[1], fxp_error());
336 outfname
= (cmd
->nwords
== 2 ? cmd
->words
[1] : cmd
->words
[2]);
338 fh
= fxp_open(fname
, SSH_FXF_READ
);
340 printf("%s: %s\n", fname
, fxp_error());
344 fp
= fopen(outfname
, "wb");
346 printf("local: unable to open %s\n", outfname
);
352 printf("remote:%s => local:%s\n", fname
, outfname
);
354 offset
= uint64_make(0, 0);
357 * FIXME: we can use FXP_FSTAT here to get the file size, and
358 * thus put up a progress bar.
365 len
= fxp_read(fh
, buffer
, offset
, sizeof(buffer
));
366 if ((len
== -1 && fxp_error_type() == SSH_FX_EOF
) || len
== 0)
369 printf("error while reading: %s\n", fxp_error());
375 wlen
= fwrite(buffer
, 1, len
- wpos
, fp
);
377 printf("error while writing local file\n");
382 if (wpos
< len
) /* we had an error */
384 offset
= uint64_add32(offset
, len
);
395 * Send a file and store it at the remote end.
397 int sftp_cmd_put(struct sftp_command
*cmd
)
399 struct fxp_handle
*fh
;
400 char *fname
, *origoutfname
, *outfname
;
404 if (cmd
->nwords
< 2) {
405 printf("put: expects a filename\n");
409 fname
= cmd
->words
[1];
410 origoutfname
= (cmd
->nwords
== 2 ? cmd
->words
[1] : cmd
->words
[2]);
411 outfname
= canonify(origoutfname
);
413 printf("%s: %s\n", origoutfname
, fxp_error());
417 fp
= fopen(fname
, "rb");
419 printf("local: unable to open %s\n", fname
);
423 fh
= fxp_open(outfname
, SSH_FXF_WRITE
| SSH_FXF_CREAT
| SSH_FXF_TRUNC
);
425 printf("%s: %s\n", outfname
, fxp_error());
430 printf("local:%s => remote:%s\n", fname
, outfname
);
432 offset
= uint64_make(0, 0);
435 * FIXME: we can use FXP_FSTAT here to get the file size, and
436 * thus put up a progress bar.
442 len
= fread(buffer
, 1, sizeof(buffer
), fp
);
444 printf("error while reading local file\n");
446 } else if (len
== 0) {
449 if (!fxp_write(fh
, buffer
, offset
, len
)) {
450 printf("error while writing: %s\n", fxp_error());
453 offset
= uint64_add32(offset
, len
);
463 int sftp_cmd_mkdir(struct sftp_command
*cmd
)
469 if (cmd
->nwords
< 2) {
470 printf("mkdir: expects a directory\n");
474 dir
= canonify(cmd
->words
[1]);
476 printf("%s: %s\n", dir
, fxp_error());
480 result
= fxp_mkdir(dir
);
482 printf("mkdir %s: %s\n", dir
, fxp_error());
492 int sftp_cmd_rmdir(struct sftp_command
*cmd
)
498 if (cmd
->nwords
< 2) {
499 printf("rmdir: expects a directory\n");
503 dir
= canonify(cmd
->words
[1]);
505 printf("%s: %s\n", dir
, fxp_error());
509 result
= fxp_rmdir(dir
);
511 printf("rmdir %s: %s\n", dir
, fxp_error());
521 int sftp_cmd_rm(struct sftp_command
*cmd
)
527 if (cmd
->nwords
< 2) {
528 printf("rm: expects a filename\n");
532 fname
= canonify(cmd
->words
[1]);
534 printf("%s: %s\n", fname
, fxp_error());
538 result
= fxp_rm(fname
);
540 printf("rm %s: %s\n", fname
, fxp_error());
551 static struct sftp_cmd_lookup
{
553 int (*obey
) (struct sftp_command
*);
556 * List of sftp commands. This is binary-searched so it MUST be
560 "bye", sftp_cmd_quit
}, {
561 "cd", sftp_cmd_cd
}, {
562 "dir", sftp_cmd_ls
}, {
563 "exit", sftp_cmd_quit
}, {
564 "get", sftp_cmd_get
}, {
565 "ls", sftp_cmd_ls
}, {
566 "mkdir", sftp_cmd_mkdir
}, {
567 "put", sftp_cmd_put
}, {
568 "quit", sftp_cmd_quit
}, {
569 "rm", sftp_cmd_rm
}, {
570 "rmdir", sftp_cmd_rmdir
},};
572 /* ----------------------------------------------------------------------
573 * Command line reading and parsing.
575 struct sftp_command
*sftp_getcmd(FILE *fp
, int mode
, int modeflags
)
578 int linelen
, linesize
;
579 struct sftp_command
*cmd
;
583 if ((mode
== 0) || (modeflags
& 1)) {
588 cmd
= smalloc(sizeof(struct sftp_command
));
594 linesize
= linelen
= 0;
600 line
= srealloc(line
, linesize
);
601 ret
= fgets(line
+ linelen
, linesize
- linelen
, fp
);
606 if (!ret
|| (linelen
== 0 && line
[0] == '\0')) {
607 cmd
->obey
= sftp_cmd_quit
;
609 return cmd
; /* eof */
611 len
= linelen
+ strlen(line
+ linelen
);
613 if (line
[linelen
- 1] == '\n') {
615 line
[linelen
] = '\0';
621 * Parse the command line into words. The syntax is:
622 * - double quotes are removed, but cause spaces within to be
623 * treated as non-separating.
624 * - a double-doublequote pair is a literal double quote, inside
625 * _or_ outside quotes. Like this:
627 * firstword "second word" "this has ""quotes"" in" sodoes""this""
633 * >this has "quotes" in<
638 /* skip whitespace */
639 while (*p
&& (*p
== ' ' || *p
== '\t'))
641 /* mark start of word */
642 q
= r
= p
; /* q sits at start, r writes word */
645 if (!quoting
&& (*p
== ' ' || *p
== '\t'))
646 break; /* reached end of word */
647 else if (*p
== '"' && p
[1] == '"')
648 p
+= 2, *r
++ = '"'; /* a literal quote */
650 p
++, quoting
= !quoting
;
655 p
++; /* skip over the whitespace */
657 if (cmd
->nwords
>= cmd
->wordssize
) {
658 cmd
->wordssize
= cmd
->nwords
+ 16;
660 srealloc(cmd
->words
, cmd
->wordssize
* sizeof(char *));
662 cmd
->words
[cmd
->nwords
++] = q
;
666 * Now parse the first word and assign a function.
669 if (cmd
->nwords
== 0)
670 cmd
->obey
= sftp_cmd_null
;
674 cmd
->obey
= sftp_cmd_unknown
;
677 j
= sizeof(sftp_lookup
) / sizeof(*sftp_lookup
);
680 cmp
= strcmp(cmd
->words
[0], sftp_lookup
[k
].name
);
686 cmd
->obey
= sftp_lookup
[k
].obey
;
695 void do_sftp(int mode
, int modeflags
, char *batchfile
)
700 * Do protocol initialisation.
704 "Fatal: unable to initialise SFTP: %s\n", fxp_error());
709 * Find out where our home directory is.
711 homedir
= fxp_realpath(".");
714 "Warning: failed to resolve home directory: %s\n",
716 homedir
= dupstr(".");
718 printf("Remote working directory is %s\n", homedir
);
720 pwd
= dupstr(homedir
);
727 /* ------------------------------------------------------------------
728 * Now we're ready to do Real Stuff.
731 struct sftp_command
*cmd
;
732 cmd
= sftp_getcmd(stdin
, 0, 0);
735 if (cmd
->obey(cmd
) < 0)
739 fp
= fopen(batchfile
, "r");
741 printf("Fatal: unable to open %s\n", batchfile
);
745 struct sftp_command
*cmd
;
746 cmd
= sftp_getcmd(fp
, mode
, modeflags
);
749 if (cmd
->obey(cmd
) < 0)
751 if (fxp_error() != NULL
) {
752 if (!(modeflags
& 2))
761 /* ----------------------------------------------------------------------
762 * Dirty bits: integration with PuTTY.
765 static int verbose
= 0;
767 void verify_ssh_host_key(char *host
, int port
, char *keytype
,
768 char *keystr
, char *fingerprint
)
774 static const char absentmsg
[] =
775 "The server's host key is not cached in the registry. You\n"
776 "have no guarantee that the server is the computer you\n"
778 "The server's key fingerprint is:\n"
780 "If you trust this host, enter \"y\" to add the key to\n"
781 "PuTTY's cache and carry on connecting.\n"
782 "If you want to carry on connecting just once, without\n"
783 "adding the key to the cache, enter \"n\".\n"
784 "If you do not trust this host, press Return to abandon the\n"
786 "Store key in cache? (y/n) ";
788 static const char wrongmsg
[] =
789 "WARNING - POTENTIAL SECURITY BREACH!\n"
790 "The server's host key does not match the one PuTTY has\n"
791 "cached in the registry. This means that either the\n"
792 "server administrator has changed the host key, or you\n"
793 "have actually connected to another computer pretending\n"
794 "to be the server.\n"
795 "The new key fingerprint is:\n"
797 "If you were expecting this change and trust the new key,\n"
798 "enter \"y\" to update PuTTY's cache and continue connecting.\n"
799 "If you want to carry on connecting but without updating\n"
800 "the cache, enter \"n\".\n"
801 "If you want to abandon the connection completely, press\n"
802 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
804 "Update cached key? (y/n, Return cancels connection) ";
806 static const char abandoned
[] = "Connection abandoned.\n";
811 * Verify the key against the registry.
813 ret
= verify_host_key(host
, port
, keytype
, keystr
);
815 if (ret
== 0) /* success - key matched OK */
818 if (ret
== 2) { /* key was different */
819 fprintf(stderr
, wrongmsg
, fingerprint
);
822 if (ret
== 1) { /* key was absent */
823 fprintf(stderr
, absentmsg
, fingerprint
);
827 hin
= GetStdHandle(STD_INPUT_HANDLE
);
828 GetConsoleMode(hin
, &savemode
);
829 SetConsoleMode(hin
, (savemode
| ENABLE_ECHO_INPUT
|
830 ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
));
831 ReadFile(hin
, line
, sizeof(line
) - 1, &i
, NULL
);
832 SetConsoleMode(hin
, savemode
);
834 if (line
[0] != '\0' && line
[0] != '\r' && line
[0] != '\n') {
835 if (line
[0] == 'y' || line
[0] == 'Y')
836 store_host_key(host
, port
, keytype
, keystr
);
838 fprintf(stderr
, abandoned
);
844 * Print an error message and perform a fatal exit.
846 void fatalbox(char *fmt
, ...)
848 char str
[0x100]; /* Make the size big enough */
851 strcpy(str
, "Fatal:");
852 vsprintf(str
+ strlen(str
), fmt
, ap
);
855 fprintf(stderr
, str
);
859 void connection_fatal(char *fmt
, ...)
861 char str
[0x100]; /* Make the size big enough */
864 strcpy(str
, "Fatal:");
865 vsprintf(str
+ strlen(str
), fmt
, ap
);
868 fprintf(stderr
, str
);
873 void logevent(char *string
)
877 void ldisc_send(char *buf
, int len
)
880 * This is only here because of the calls to ldisc_send(NULL,
881 * 0) in ssh.c. Nothing in PSFTP actually needs to use the
882 * ldisc as an ldisc. So if we get called with any real data, I
883 * want to know about it.
889 * Be told what socket we're supposed to be using.
891 static SOCKET sftp_ssh_socket
;
892 char *do_select(SOCKET skt
, int startup
)
895 sftp_ssh_socket
= skt
;
897 sftp_ssh_socket
= INVALID_SOCKET
;
900 extern int select_result(WPARAM
, LPARAM
);
903 * Receive a block of data from the SSH link. Block until all data
906 * To do this, we repeatedly call the SSH protocol module, with our
907 * own trap in from_backend() to catch the data that comes back. We
908 * do this until we have enough data.
911 static unsigned char *outptr
; /* where to put the data */
912 static unsigned outlen
; /* how much data required */
913 static unsigned char *pending
= NULL
; /* any spare data */
914 static unsigned pendlen
= 0, pendsize
= 0; /* length and phys. size of buffer */
915 void from_backend(int is_stderr
, char *data
, int datalen
)
917 unsigned char *p
= (unsigned char *) data
;
918 unsigned len
= (unsigned) datalen
;
921 * stderr data is just spouted to local stderr and otherwise
925 fwrite(data
, 1, len
, stderr
);
930 * If this is before the real session begins, just return.
936 unsigned used
= outlen
;
939 memcpy(outptr
, p
, used
);
947 if (pendsize
< pendlen
+ len
) {
948 pendsize
= pendlen
+ len
+ 4096;
949 pending
= (pending ?
srealloc(pending
, pendsize
) :
952 fatalbox("Out of memory");
954 memcpy(pending
+ pendlen
, p
, len
);
958 int sftp_recvdata(char *buf
, int len
)
960 outptr
= (unsigned char *) buf
;
964 * See if the pending-input block contains some of what we
968 unsigned pendused
= pendlen
;
969 if (pendused
> outlen
)
971 memcpy(outptr
, pending
, pendused
);
972 memmove(pending
, pending
+ pendused
, pendlen
- pendused
);
989 FD_SET(sftp_ssh_socket
, &readfds
);
990 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
992 select_result((WPARAM
) sftp_ssh_socket
, (LPARAM
) FD_READ
);
997 int sftp_senddata(char *buf
, int len
)
999 back
->send((unsigned char *) buf
, len
);
1004 * Loop through the ssh connection and authentication process.
1006 static void ssh_sftp_init(void)
1008 if (sftp_ssh_socket
== INVALID_SOCKET
)
1010 while (!back
->sendok()) {
1013 FD_SET(sftp_ssh_socket
, &readfds
);
1014 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
1016 select_result((WPARAM
) sftp_ssh_socket
, (LPARAM
) FD_READ
);
1020 static char *password
= NULL
;
1021 static int get_line(const char *prompt
, char *str
, int maxlen
, int is_pw
)
1024 DWORD savemode
, newmode
, i
;
1027 static int tried_once
= 0;
1032 strncpy(str
, password
, maxlen
);
1033 str
[maxlen
- 1] = '\0';
1039 hin
= GetStdHandle(STD_INPUT_HANDLE
);
1040 hout
= GetStdHandle(STD_OUTPUT_HANDLE
);
1041 if (hin
== INVALID_HANDLE_VALUE
|| hout
== INVALID_HANDLE_VALUE
) {
1042 fprintf(stderr
, "Cannot get standard input/output handles\n");
1046 GetConsoleMode(hin
, &savemode
);
1047 newmode
= savemode
| ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
;
1049 newmode
&= ~ENABLE_ECHO_INPUT
;
1051 newmode
|= ENABLE_ECHO_INPUT
;
1052 SetConsoleMode(hin
, newmode
);
1054 WriteFile(hout
, prompt
, strlen(prompt
), &i
, NULL
);
1055 ReadFile(hin
, str
, maxlen
- 1, &i
, NULL
);
1057 SetConsoleMode(hin
, savemode
);
1059 if ((int) i
> maxlen
)
1066 WriteFile(hout
, "\r\n", 2, &i
, NULL
);
1072 * Initialize the Win$ock driver.
1074 static void init_winsock(void)
1079 winsock_ver
= MAKEWORD(1, 1);
1080 if (WSAStartup(winsock_ver
, &wsadata
)) {
1081 fprintf(stderr
, "Unable to initialise WinSock");
1084 if (LOBYTE(wsadata
.wVersion
) != 1 || HIBYTE(wsadata
.wVersion
) != 1) {
1085 fprintf(stderr
, "WinSock version is incompatible with 1.1");
1091 * Short description of parameters.
1093 static void usage(void)
1095 printf("PuTTY Secure File Transfer (SFTP) client\n");
1096 printf("%s\n", ver
);
1097 printf("Usage: psftp [options] user@host\n");
1098 printf("Options:\n");
1099 printf(" -b file use specified batchfile\n");
1100 printf(" -bc output batchfile commands\n");
1101 printf(" -be don't stop batchfile processing if errors\n");
1102 printf(" -v show verbose messages\n");
1103 printf(" -P port connect to specified port\n");
1104 printf(" -pw passw login with specified password\n");
1109 * Main program. Parse arguments etc.
1111 int main(int argc
, char *argv
[])
1115 char *user
, *host
, *userhost
, *realhost
;
1119 char *batchfile
= NULL
;
1121 flags
= FLAG_STDERR
;
1122 ssh_get_line
= &get_line
;
1126 userhost
= user
= NULL
;
1128 for (i
= 1; i
< argc
; i
++) {
1129 if (argv
[i
][0] != '-') {
1133 userhost
= dupstr(argv
[i
]);
1134 } else if (strcmp(argv
[i
], "-v") == 0) {
1135 verbose
= 1, flags
|= FLAG_VERBOSE
;
1136 } else if (strcmp(argv
[i
], "-h") == 0 ||
1137 strcmp(argv
[i
], "-?") == 0) {
1139 } else if (strcmp(argv
[i
], "-l") == 0 && i
+ 1 < argc
) {
1141 } else if (strcmp(argv
[i
], "-P") == 0 && i
+ 1 < argc
) {
1142 portnumber
= atoi(argv
[++i
]);
1143 } else if (strcmp(argv
[i
], "-pw") == 0 && i
+ 1 < argc
) {
1144 password
= argv
[++i
];
1145 } else if (strcmp(argv
[i
], "-b") == 0 && i
+ 1 < argc
) {
1147 batchfile
= argv
[++i
];
1148 } else if (strcmp(argv
[i
], "-bc") == 0 && i
+ 1 < argc
) {
1149 modeflags
= modeflags
| 1;
1150 } else if (strcmp(argv
[i
], "-be") == 0 && i
+ 1 < argc
) {
1151 modeflags
= modeflags
| 2;
1152 } else if (strcmp(argv
[i
], "--") == 0) {
1163 if (argc
> 0 || !userhost
)
1166 /* Separate host and username */
1168 host
= strrchr(host
, '@');
1174 printf("psftp: multiple usernames specified; using \"%s\"\n",
1180 /* Try to load settings for this host */
1181 do_defaults(host
, &cfg
);
1182 if (cfg
.host
[0] == '\0') {
1183 /* No settings for this host; use defaults */
1184 do_defaults(NULL
, &cfg
);
1185 strncpy(cfg
.host
, host
, sizeof(cfg
.host
) - 1);
1186 cfg
.host
[sizeof(cfg
.host
) - 1] = '\0';
1191 if (user
!= NULL
&& user
[0] != '\0') {
1192 strncpy(cfg
.username
, user
, sizeof(cfg
.username
) - 1);
1193 cfg
.username
[sizeof(cfg
.username
) - 1] = '\0';
1195 if (!cfg
.username
[0]) {
1196 printf("login as: ");
1197 if (!fgets(cfg
.username
, sizeof(cfg
.username
), stdin
)) {
1198 fprintf(stderr
, "psftp: aborting\n");
1201 int len
= strlen(cfg
.username
);
1202 if (cfg
.username
[len
- 1] == '\n')
1203 cfg
.username
[len
- 1] = '\0';
1207 if (cfg
.protocol
!= PROT_SSH
)
1211 cfg
.port
= portnumber
;
1213 /* SFTP uses SSH2 by default always */
1216 /* Set up subsystem name. FIXME: fudge for SSH1. */
1217 strcpy(cfg
.remote_cmd
, "sftp");
1218 cfg
.ssh_subsys
= TRUE
;
1221 back
= &ssh_backend
;
1223 err
= back
->init(cfg
.host
, cfg
.port
, &realhost
);
1225 fprintf(stderr
, "ssh_init: %s", err
);
1229 if (verbose
&& realhost
!= NULL
)
1230 printf("Connected to %s\n", realhost
);
1232 do_sftp(mode
, modeflags
, batchfile
);
1234 if (back
!= NULL
&& back
->socket() != NULL
) {
1236 back
->special(TS_EOF
);
1237 sftp_recvdata(&ch
, 1);