X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/4f2b387f9cba569d49559f88e785639d56ea2d66..fa3db7671d4557362fa059bd440e51197696b07a:/psftp.c diff --git a/psftp.c b/psftp.c index 37f39ff3..b57ce05c 100644 --- a/psftp.c +++ b/psftp.c @@ -24,6 +24,9 @@ * send buffer. */ +static int psftp_connect(char *userhost, char *user, int portnumber); +static void do_sftp_init(void); + /* ---------------------------------------------------------------------- * sftp client state. */ @@ -130,6 +133,30 @@ char *canonify(char *name) } } +/* + * Return a pointer to the portion of str that comes after the last + * slash (or backslash or colon, if `local' is TRUE). + */ +static char *stripslashes(char *str, int local) +{ + char *p; + + if (local) { + p = strchr(str, ':'); + if (p) str = p+1; + } + + p = strrchr(str, '/'); + if (p) str = p+1; + + if (local) { + p = strrchr(str, '\\'); + if (p) str = p+1; + } + + return str; +} + /* ---------------------------------------------------------------------- * Actual sftp commands. */ @@ -174,6 +201,11 @@ int sftp_cmd_ls(struct sftp_command *cmd) char *dir, *cdir; int i; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 2) dir = "."; else @@ -249,6 +281,11 @@ int sftp_cmd_cd(struct sftp_command *cmd) struct fxp_handle *dirh; char *dir; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 2) dir = dupstr(homedir); else @@ -280,6 +317,11 @@ int sftp_cmd_cd(struct sftp_command *cmd) */ int sftp_cmd_pwd(struct sftp_command *cmd) { + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + printf("Remote directory is %s\n", pwd); return 0; } @@ -297,6 +339,11 @@ int sftp_general_get(struct sftp_command *cmd, int restart) uint64 offset; FILE *fp; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 2) { printf("get: expects a filename\n"); return 0; @@ -307,7 +354,8 @@ int sftp_general_get(struct sftp_command *cmd, int restart) printf("%s: %s\n", cmd->words[1], fxp_error()); return 0; } - outfname = (cmd->nwords == 2 ? cmd->words[1] : cmd->words[2]); + outfname = (cmd->nwords == 2 ? + stripslashes(cmd->words[1], 0) : cmd->words[2]); fh = fxp_open(fname, SSH_FXF_READ); if (!fh) { @@ -400,13 +448,19 @@ int sftp_general_put(struct sftp_command *cmd, int restart) uint64 offset; FILE *fp; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 2) { printf("put: expects a filename\n"); return 0; } fname = cmd->words[1]; - origoutfname = (cmd->nwords == 2 ? cmd->words[1] : cmd->words[2]); + origoutfname = (cmd->nwords == 2 ? + stripslashes(cmd->words[1], 1) : cmd->words[2]); outfname = canonify(origoutfname); if (!outfname) { printf("%s: %s\n", origoutfname, fxp_error()); @@ -503,6 +557,10 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) char *dir; int result; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } if (cmd->nwords < 2) { printf("mkdir: expects a directory\n"); @@ -531,6 +589,10 @@ int sftp_cmd_rmdir(struct sftp_command *cmd) char *dir; int result; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } if (cmd->nwords < 2) { printf("rmdir: expects a directory\n"); @@ -559,6 +621,11 @@ int sftp_cmd_rm(struct sftp_command *cmd) char *fname; int result; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 2) { printf("rm: expects a filename\n"); return 0; @@ -587,6 +654,11 @@ int sftp_cmd_mv(struct sftp_command *cmd) char *srcfname, *dstfname; int result; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 3) { printf("mv: expects two filenames\n"); return 0; @@ -654,6 +726,11 @@ int sftp_cmd_chmod(struct sftp_command *cmd) struct fxp_attrs attrs; unsigned attrs_clr, attrs_xor, oldperms, newperms; + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + if (cmd->nwords < 3) { printf("chmod: expects a mode specifier and a filename\n"); return 0; @@ -798,6 +875,25 @@ int sftp_cmd_chmod(struct sftp_command *cmd) return 0; } +static int sftp_cmd_open(struct sftp_command *cmd) +{ + if (back != NULL) { + printf("psftp: already connected\n"); + return 0; + } + + if (cmd->nwords < 2) { + printf("open: expects a host name\n"); + return 0; + } + + if (psftp_connect(cmd->words[1], NULL, 0)) { + back = NULL; /* connection is already closed */ + return -1; /* this is fatal */ + } + do_sftp_init(); +} + static int sftp_cmd_help(struct sftp_command *cmd); static struct sftp_cmd_lookup { @@ -928,6 +1024,14 @@ static struct sftp_cmd_lookup { sftp_cmd_put }, { + "open", "connect to a host", + " [@]\n" + " Establishes an SFTP connection to a given host. Only usable\n" + " when you did not already specify a host name on the command\n" + " line.\n", + sftp_cmd_open + }, + { "pwd", "print your remote working directory", "\n" " Print the current remote working directory for your SFTP session.\n", @@ -1147,10 +1251,8 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) return cmd; } -void do_sftp(int mode, int modeflags, char *batchfile) +static void do_sftp_init(void) { - FILE *fp; - /* * Do protocol initialisation. */ @@ -1173,6 +1275,11 @@ void do_sftp(int mode, int modeflags, char *batchfile) printf("Remote working directory is %s\n", homedir); } pwd = dupstr(homedir); +} + +void do_sftp(int mode, int modeflags, char *batchfile) +{ + FILE *fp; /* * Batch mode? @@ -1336,6 +1443,25 @@ void askcipher(char *ciphername, int cs) } /* + * Warn about the obsolescent key file format. + */ +void old_keyfile_warning(void) +{ + static const char message[] = + "You are loading an SSH 2 private key which has an\n" + "old version of the file format. This means your key\n" + "file is not fully tamperproof. Future versions of\n" + "PuTTY may stop supporting this private key format,\n" + "so we recommend you convert your key to the new\n" + "format.\n" + "\n" + "Once the key is loaded into PuTTYgen, you can perform\n" + "this conversion simply by saving it again.\n"; + + fputs(message, stderr); +} + +/* * Print an error message and perform a fatal exit. */ void fatalbox(char *fmt, ...) @@ -1347,7 +1473,7 @@ void fatalbox(char *fmt, ...) vsprintf(str + strlen(str), fmt, ap); va_end(ap); strcat(str, "\n"); - fprintf(stderr, str); + fputs(stderr, str); exit(1); } @@ -1360,7 +1486,7 @@ void connection_fatal(char *fmt, ...) vsprintf(str + strlen(str), fmt, ap); va_end(ap); strcat(str, "\n"); - fprintf(stderr, str); + fputs(stderr, str); exit(1); } @@ -1369,7 +1495,7 @@ void logevent(char *string) { } -void ldisc_send(char *buf, int len) +void ldisc_send(char *buf, int len, int interactive) { /* * This is only here because of the calls to ldisc_send(NULL, @@ -1603,62 +1729,12 @@ static void usage(void) } /* - * Main program. Parse arguments etc. + * Connect to a host. */ -int main(int argc, char *argv[]) +static int psftp_connect(char *userhost, char *user, int portnumber) { - int i; - int portnumber = 0; - char *user, *host, *userhost, *realhost; + char *host, *realhost; char *err; - int mode = 0; - int modeflags = 0; - char *batchfile = NULL; - - flags = FLAG_STDERR | FLAG_INTERACTIVE; - ssh_get_line = &get_line; - init_winsock(); - sk_init(); - - userhost = user = NULL; - - for (i = 1; i < argc; i++) { - if (argv[i][0] != '-') { - if (userhost) - usage(); - else - userhost = dupstr(argv[i]); - } else if (strcmp(argv[i], "-v") == 0) { - verbose = 1, flags |= FLAG_VERBOSE; - } else if (strcmp(argv[i], "-h") == 0 || - strcmp(argv[i], "-?") == 0) { - usage(); - } else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { - user = argv[++i]; - } else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc) { - portnumber = atoi(argv[++i]); - } else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc) { - password = argv[++i]; - } else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) { - mode = 1; - batchfile = argv[++i]; - } else if (strcmp(argv[i], "-bc") == 0 && i + 1 < argc) { - modeflags = modeflags | 1; - } else if (strcmp(argv[i], "-be") == 0 && i + 1 < argc) { - modeflags = modeflags | 2; - } else if (strcmp(argv[i], "--") == 0) { - i++; - break; - } else { - usage(); - } - } - argc -= i; - argv += i; - back = NULL; - - if (argc > 0 || !userhost) - usage(); /* Separate host and username */ host = userhost; @@ -1684,6 +1760,32 @@ int main(int argc, char *argv[]) cfg.port = 22; } + /* + * Trim leading whitespace off the hostname if it's there. + */ + { + int space = strspn(cfg.host, " \t"); + memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); + } + + /* See if host is of the form user@host */ + if (cfg.host[0] != '\0') { + char *atsign = strchr(cfg.host, '@'); + /* Make sure we're not overflowing the user field */ + if (atsign) { + if (atsign - cfg.host < sizeof cfg.username) { + strncpy(cfg.username, cfg.host, atsign - cfg.host); + cfg.username[atsign - cfg.host] = '\0'; + } + memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); + } + } + + /* + * Trim a colon suffix off the hostname if it's there. + */ + cfg.host[strcspn(cfg.host, ":")] = '\0'; + /* Set username */ if (user != NULL && user[0] != '\0') { strncpy(cfg.username, user, sizeof(cfg.username) - 1); @@ -1710,6 +1812,15 @@ int main(int argc, char *argv[]) /* SFTP uses SSH2 by default always */ cfg.sshprot = 2; + /* + * Disable scary things which shouldn't be enabled for simple + * things like SCP and SFTP: agent forwarding, port forwarding, + * X forwarding. + */ + cfg.x11_forward = 0; + cfg.agentfwd = 0; + cfg.portfwd[0] = cfg.portfwd[1] = '\0'; + /* Set up subsystem name. */ strcpy(cfg.remote_cmd, "sftp"); cfg.ssh_subsys = TRUE; @@ -1740,14 +1851,83 @@ int main(int argc, char *argv[]) back = &ssh_backend; - err = back->init(cfg.host, cfg.port, &realhost); + err = back->init(cfg.host, cfg.port, &realhost, 0); if (err != NULL) { - fprintf(stderr, "ssh_init: %s", err); + fprintf(stderr, "ssh_init: %s\n", err); return 1; } ssh_sftp_init(); if (verbose && realhost != NULL) printf("Connected to %s\n", realhost); + return 0; +} + +/* + * Main program. Parse arguments etc. + */ +int main(int argc, char *argv[]) +{ + int i; + int portnumber = 0; + char *userhost, *user; + int mode = 0; + int modeflags = 0; + char *batchfile = NULL; + + flags = FLAG_STDERR | FLAG_INTERACTIVE; + ssh_get_line = &get_line; + init_winsock(); + sk_init(); + + userhost = user = NULL; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (userhost) + usage(); + else + userhost = dupstr(argv[i]); + } else if (strcmp(argv[i], "-v") == 0) { + verbose = 1, flags |= FLAG_VERBOSE; + } else if (strcmp(argv[i], "-h") == 0 || + strcmp(argv[i], "-?") == 0) { + usage(); + } else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { + user = argv[++i]; + } else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc) { + portnumber = atoi(argv[++i]); + } else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc) { + password = argv[++i]; + } else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) { + mode = 1; + batchfile = argv[++i]; + } else if (strcmp(argv[i], "-bc") == 0 && i + 1 < argc) { + modeflags = modeflags | 1; + } else if (strcmp(argv[i], "-be") == 0 && i + 1 < argc) { + modeflags = modeflags | 2; + } else if (strcmp(argv[i], "--") == 0) { + i++; + break; + } else { + usage(); + } + } + argc -= i; + argv += i; + back = NULL; + + /* + * If a user@host string has already been provided, connect to + * it now. + */ + if (userhost) { + if (psftp_connect(userhost, user, portnumber)) + return 1; + do_sftp_init(); + } else { + printf("psftp: no hostname specified; use \"open host.name\"" + " to connect\n"); + } do_sftp(mode, modeflags, batchfile);