GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/sftp/../sftp.c Lines: 0 1199 0.0 %
Date: 2017-11-07 Branches: 0 857 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: sftp.c,v 1.180 2017/06/10 06:33:34 djm Exp $ */
2
/*
3
 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include <sys/types.h>
19
#include <sys/ioctl.h>
20
#include <sys/wait.h>
21
#include <sys/stat.h>
22
#include <sys/socket.h>
23
#include <sys/statvfs.h>
24
25
#include <ctype.h>
26
#include <errno.h>
27
#include <glob.h>
28
#include <histedit.h>
29
#include <paths.h>
30
#include <libgen.h>
31
#include <locale.h>
32
#include <signal.h>
33
#include <stdarg.h>
34
#include <stdlib.h>
35
#include <stdio.h>
36
#include <string.h>
37
#include <unistd.h>
38
#include <limits.h>
39
#include <util.h>
40
#include <stdarg.h>
41
42
#include "xmalloc.h"
43
#include "log.h"
44
#include "pathnames.h"
45
#include "misc.h"
46
#include "utf8.h"
47
48
#include "sftp.h"
49
#include "ssherr.h"
50
#include "sshbuf.h"
51
#include "sftp-common.h"
52
#include "sftp-client.h"
53
54
#define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
55
#define DEFAULT_NUM_REQUESTS	64	/* # concurrent outstanding requests */
56
57
/* File to read commands from */
58
FILE* infile;
59
60
/* Are we in batchfile mode? */
61
int batchmode = 0;
62
63
/* PID of ssh transport process */
64
static pid_t sshpid = -1;
65
66
/* Suppress diagnositic messages */
67
int quiet = 0;
68
69
/* This is set to 0 if the progressmeter is not desired. */
70
int showprogress = 1;
71
72
/* When this option is set, we always recursively download/upload directories */
73
int global_rflag = 0;
74
75
/* When this option is set, we resume download or upload if possible */
76
int global_aflag = 0;
77
78
/* When this option is set, the file transfers will always preserve times */
79
int global_pflag = 0;
80
81
/* When this option is set, transfers will have fsync() called on each file */
82
int global_fflag = 0;
83
84
/* SIGINT received during command processing */
85
volatile sig_atomic_t interrupted = 0;
86
87
/* I wish qsort() took a separate ctx for the comparison function...*/
88
int sort_flag;
89
glob_t *sort_glob;
90
91
/* Context used for commandline completion */
92
struct complete_ctx {
93
	struct sftp_conn *conn;
94
	char **remote_pathp;
95
};
96
97
int remote_glob(struct sftp_conn *, const char *, int,
98
    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
99
100
/* Separators for interactive commands */
101
#define WHITESPACE " \t\r\n"
102
103
/* ls flags */
104
#define LS_LONG_VIEW	0x0001	/* Full view ala ls -l */
105
#define LS_SHORT_VIEW	0x0002	/* Single row view ala ls -1 */
106
#define LS_NUMERIC_VIEW	0x0004	/* Long view with numeric uid/gid */
107
#define LS_NAME_SORT	0x0008	/* Sort by name (default) */
108
#define LS_TIME_SORT	0x0010	/* Sort by mtime */
109
#define LS_SIZE_SORT	0x0020	/* Sort by file size */
110
#define LS_REVERSE_SORT	0x0040	/* Reverse sort order */
111
#define LS_SHOW_ALL	0x0080	/* Don't skip filenames starting with '.' */
112
#define LS_SI_UNITS	0x0100	/* Display sizes as K, M, G, etc. */
113
114
#define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
115
#define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
116
117
/* Commands for interactive mode */
118
enum sftp_command {
119
	I_CHDIR = 1,
120
	I_CHGRP,
121
	I_CHMOD,
122
	I_CHOWN,
123
	I_DF,
124
	I_GET,
125
	I_HELP,
126
	I_LCHDIR,
127
	I_LINK,
128
	I_LLS,
129
	I_LMKDIR,
130
	I_LPWD,
131
	I_LS,
132
	I_LUMASK,
133
	I_MKDIR,
134
	I_PUT,
135
	I_PWD,
136
	I_QUIT,
137
	I_REGET,
138
	I_RENAME,
139
	I_REPUT,
140
	I_RM,
141
	I_RMDIR,
142
	I_SHELL,
143
	I_SYMLINK,
144
	I_VERSION,
145
	I_PROGRESS,
146
};
147
148
struct CMD {
149
	const char *c;
150
	const int n;
151
	const int t;
152
};
153
154
/* Type of completion */
155
#define NOARGS	0
156
#define REMOTE	1
157
#define LOCAL	2
158
159
static const struct CMD cmds[] = {
160
	{ "bye",	I_QUIT,		NOARGS	},
161
	{ "cd",		I_CHDIR,	REMOTE	},
162
	{ "chdir",	I_CHDIR,	REMOTE	},
163
	{ "chgrp",	I_CHGRP,	REMOTE	},
164
	{ "chmod",	I_CHMOD,	REMOTE	},
165
	{ "chown",	I_CHOWN,	REMOTE	},
166
	{ "df",		I_DF,		REMOTE	},
167
	{ "dir",	I_LS,		REMOTE	},
168
	{ "exit",	I_QUIT,		NOARGS	},
169
	{ "get",	I_GET,		REMOTE	},
170
	{ "help",	I_HELP,		NOARGS	},
171
	{ "lcd",	I_LCHDIR,	LOCAL	},
172
	{ "lchdir",	I_LCHDIR,	LOCAL	},
173
	{ "lls",	I_LLS,		LOCAL	},
174
	{ "lmkdir",	I_LMKDIR,	LOCAL	},
175
	{ "ln",		I_LINK,		REMOTE	},
176
	{ "lpwd",	I_LPWD,		LOCAL	},
177
	{ "ls",		I_LS,		REMOTE	},
178
	{ "lumask",	I_LUMASK,	NOARGS	},
179
	{ "mkdir",	I_MKDIR,	REMOTE	},
180
	{ "mget",	I_GET,		REMOTE	},
181
	{ "mput",	I_PUT,		LOCAL	},
182
	{ "progress",	I_PROGRESS,	NOARGS	},
183
	{ "put",	I_PUT,		LOCAL	},
184
	{ "pwd",	I_PWD,		REMOTE	},
185
	{ "quit",	I_QUIT,		NOARGS	},
186
	{ "reget",	I_REGET,	REMOTE	},
187
	{ "rename",	I_RENAME,	REMOTE	},
188
	{ "reput",	I_REPUT,	LOCAL	},
189
	{ "rm",		I_RM,		REMOTE	},
190
	{ "rmdir",	I_RMDIR,	REMOTE	},
191
	{ "symlink",	I_SYMLINK,	REMOTE	},
192
	{ "version",	I_VERSION,	NOARGS	},
193
	{ "!",		I_SHELL,	NOARGS	},
194
	{ "?",		I_HELP,		NOARGS	},
195
	{ NULL,		-1,		-1	}
196
};
197
198
int interactive_loop(struct sftp_conn *, char *file1, char *file2);
199
200
/* ARGSUSED */
201
static void
202
killchild(int signo)
203
{
204
	if (sshpid > 1) {
205
		kill(sshpid, SIGTERM);
206
		waitpid(sshpid, NULL, 0);
207
	}
208
209
	_exit(1);
210
}
211
212
/* ARGSUSED */
213
static void
214
suspchild(int signo)
215
{
216
	if (sshpid > 1) {
217
		kill(sshpid, signo);
218
		while (waitpid(sshpid, NULL, WUNTRACED) == -1 && errno == EINTR)
219
			continue;
220
	}
221
	kill(getpid(), SIGSTOP);
222
}
223
224
/* ARGSUSED */
225
static void
226
cmd_interrupt(int signo)
227
{
228
	const char msg[] = "\rInterrupt  \n";
229
	int olderrno = errno;
230
231
	(void)write(STDERR_FILENO, msg, sizeof(msg) - 1);
232
	interrupted = 1;
233
	errno = olderrno;
234
}
235
236
static void
237
help(void)
238
{
239
	printf("Available commands:\n"
240
	    "bye                                Quit sftp\n"
241
	    "cd path                            Change remote directory to 'path'\n"
242
	    "chgrp grp path                     Change group of file 'path' to 'grp'\n"
243
	    "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
244
	    "chown own path                     Change owner of file 'path' to 'own'\n"
245
	    "df [-hi] [path]                    Display statistics for current directory or\n"
246
	    "                                   filesystem containing 'path'\n"
247
	    "exit                               Quit sftp\n"
248
	    "get [-afPpRr] remote [local]       Download file\n"
249
	    "reget [-fPpRr] remote [local]      Resume download file\n"
250
	    "reput [-fPpRr] [local] remote      Resume upload file\n"
251
	    "help                               Display this help text\n"
252
	    "lcd path                           Change local directory to 'path'\n"
253
	    "lls [ls-options [path]]            Display local directory listing\n"
254
	    "lmkdir path                        Create local directory\n"
255
	    "ln [-s] oldpath newpath            Link remote file (-s for symlink)\n"
256
	    "lpwd                               Print local working directory\n"
257
	    "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
258
	    "lumask umask                       Set local umask to 'umask'\n"
259
	    "mkdir path                         Create remote directory\n"
260
	    "progress                           Toggle display of progress meter\n"
261
	    "put [-afPpRr] local [remote]       Upload file\n"
262
	    "pwd                                Display remote working directory\n"
263
	    "quit                               Quit sftp\n"
264
	    "rename oldpath newpath             Rename remote file\n"
265
	    "rm path                            Delete remote file\n"
266
	    "rmdir path                         Remove remote directory\n"
267
	    "symlink oldpath newpath            Symlink remote file\n"
268
	    "version                            Show SFTP version\n"
269
	    "!command                           Execute 'command' in local shell\n"
270
	    "!                                  Escape to local shell\n"
271
	    "?                                  Synonym for help\n");
272
}
273
274
static void
275
local_do_shell(const char *args)
276
{
277
	int status;
278
	char *shell;
279
	pid_t pid;
280
281
	if (!*args)
282
		args = NULL;
283
284
	if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
285
		shell = _PATH_BSHELL;
286
287
	if ((pid = fork()) == -1)
288
		fatal("Couldn't fork: %s", strerror(errno));
289
290
	if (pid == 0) {
291
		/* XXX: child has pipe fds to ssh subproc open - issue? */
292
		if (args) {
293
			debug3("Executing %s -c \"%s\"", shell, args);
294
			execl(shell, shell, "-c", args, (char *)NULL);
295
		} else {
296
			debug3("Executing %s", shell);
297
			execl(shell, shell, (char *)NULL);
298
		}
299
		fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
300
		    strerror(errno));
301
		_exit(1);
302
	}
303
	while (waitpid(pid, &status, 0) == -1)
304
		if (errno != EINTR)
305
			fatal("Couldn't wait for child: %s", strerror(errno));
306
	if (!WIFEXITED(status))
307
		error("Shell exited abnormally");
308
	else if (WEXITSTATUS(status))
309
		error("Shell exited with status %d", WEXITSTATUS(status));
310
}
311
312
static void
313
local_do_ls(const char *args)
314
{
315
	if (!args || !*args)
316
		local_do_shell(_PATH_LS);
317
	else {
318
		int len = strlen(_PATH_LS " ") + strlen(args) + 1;
319
		char *buf = xmalloc(len);
320
321
		/* XXX: quoting - rip quoting code from ftp? */
322
		snprintf(buf, len, _PATH_LS " %s", args);
323
		local_do_shell(buf);
324
		free(buf);
325
	}
326
}
327
328
/* Strip one path (usually the pwd) from the start of another */
329
static char *
330
path_strip(const char *path, const char *strip)
331
{
332
	size_t len;
333
334
	if (strip == NULL)
335
		return (xstrdup(path));
336
337
	len = strlen(strip);
338
	if (strncmp(path, strip, len) == 0) {
339
		if (strip[len - 1] != '/' && path[len] == '/')
340
			len++;
341
		return (xstrdup(path + len));
342
	}
343
344
	return (xstrdup(path));
345
}
346
347
static char *
348
make_absolute(char *p, const char *pwd)
349
{
350
	char *abs_str;
351
352
	/* Derelativise */
353
	if (p && p[0] != '/') {
354
		abs_str = path_append(pwd, p);
355
		free(p);
356
		return(abs_str);
357
	} else
358
		return(p);
359
}
360
361
static int
362
parse_getput_flags(const char *cmd, char **argv, int argc,
363
    int *aflag, int *fflag, int *pflag, int *rflag)
364
{
365
	extern int opterr, optind, optopt, optreset;
366
	int ch;
367
368
	optind = optreset = 1;
369
	opterr = 0;
370
371
	*aflag = *fflag = *rflag = *pflag = 0;
372
	while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
373
		switch (ch) {
374
		case 'a':
375
			*aflag = 1;
376
			break;
377
		case 'f':
378
			*fflag = 1;
379
			break;
380
		case 'p':
381
		case 'P':
382
			*pflag = 1;
383
			break;
384
		case 'r':
385
		case 'R':
386
			*rflag = 1;
387
			break;
388
		default:
389
			error("%s: Invalid flag -%c", cmd, optopt);
390
			return -1;
391
		}
392
	}
393
394
	return optind;
395
}
396
397
static int
398
parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
399
{
400
	extern int opterr, optind, optopt, optreset;
401
	int ch;
402
403
	optind = optreset = 1;
404
	opterr = 0;
405
406
	*sflag = 0;
407
	while ((ch = getopt(argc, argv, "s")) != -1) {
408
		switch (ch) {
409
		case 's':
410
			*sflag = 1;
411
			break;
412
		default:
413
			error("%s: Invalid flag -%c", cmd, optopt);
414
			return -1;
415
		}
416
	}
417
418
	return optind;
419
}
420
421
static int
422
parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag)
423
{
424
	extern int opterr, optind, optopt, optreset;
425
	int ch;
426
427
	optind = optreset = 1;
428
	opterr = 0;
429
430
	*lflag = 0;
431
	while ((ch = getopt(argc, argv, "l")) != -1) {
432
		switch (ch) {
433
		case 'l':
434
			*lflag = 1;
435
			break;
436
		default:
437
			error("%s: Invalid flag -%c", cmd, optopt);
438
			return -1;
439
		}
440
	}
441
442
	return optind;
443
}
444
445
static int
446
parse_ls_flags(char **argv, int argc, int *lflag)
447
{
448
	extern int opterr, optind, optopt, optreset;
449
	int ch;
450
451
	optind = optreset = 1;
452
	opterr = 0;
453
454
	*lflag = LS_NAME_SORT;
455
	while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
456
		switch (ch) {
457
		case '1':
458
			*lflag &= ~VIEW_FLAGS;
459
			*lflag |= LS_SHORT_VIEW;
460
			break;
461
		case 'S':
462
			*lflag &= ~SORT_FLAGS;
463
			*lflag |= LS_SIZE_SORT;
464
			break;
465
		case 'a':
466
			*lflag |= LS_SHOW_ALL;
467
			break;
468
		case 'f':
469
			*lflag &= ~SORT_FLAGS;
470
			break;
471
		case 'h':
472
			*lflag |= LS_SI_UNITS;
473
			break;
474
		case 'l':
475
			*lflag &= ~LS_SHORT_VIEW;
476
			*lflag |= LS_LONG_VIEW;
477
			break;
478
		case 'n':
479
			*lflag &= ~LS_SHORT_VIEW;
480
			*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
481
			break;
482
		case 'r':
483
			*lflag |= LS_REVERSE_SORT;
484
			break;
485
		case 't':
486
			*lflag &= ~SORT_FLAGS;
487
			*lflag |= LS_TIME_SORT;
488
			break;
489
		default:
490
			error("ls: Invalid flag -%c", optopt);
491
			return -1;
492
		}
493
	}
494
495
	return optind;
496
}
497
498
static int
499
parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
500
{
501
	extern int opterr, optind, optopt, optreset;
502
	int ch;
503
504
	optind = optreset = 1;
505
	opterr = 0;
506
507
	*hflag = *iflag = 0;
508
	while ((ch = getopt(argc, argv, "hi")) != -1) {
509
		switch (ch) {
510
		case 'h':
511
			*hflag = 1;
512
			break;
513
		case 'i':
514
			*iflag = 1;
515
			break;
516
		default:
517
			error("%s: Invalid flag -%c", cmd, optopt);
518
			return -1;
519
		}
520
	}
521
522
	return optind;
523
}
524
525
static int
526
parse_no_flags(const char *cmd, char **argv, int argc)
527
{
528
	extern int opterr, optind, optopt, optreset;
529
	int ch;
530
531
	optind = optreset = 1;
532
	opterr = 0;
533
534
	while ((ch = getopt(argc, argv, "")) != -1) {
535
		switch (ch) {
536
		default:
537
			error("%s: Invalid flag -%c", cmd, optopt);
538
			return -1;
539
		}
540
	}
541
542
	return optind;
543
}
544
545
static int
546
is_dir(const char *path)
547
{
548
	struct stat sb;
549
550
	/* XXX: report errors? */
551
	if (stat(path, &sb) == -1)
552
		return(0);
553
554
	return(S_ISDIR(sb.st_mode));
555
}
556
557
static int
558
remote_is_dir(struct sftp_conn *conn, const char *path)
559
{
560
	Attrib *a;
561
562
	/* XXX: report errors? */
563
	if ((a = do_stat(conn, path, 1)) == NULL)
564
		return(0);
565
	if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
566
		return(0);
567
	return(S_ISDIR(a->perm));
568
}
569
570
/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
571
static int
572
pathname_is_dir(const char *pathname)
573
{
574
	size_t l = strlen(pathname);
575
576
	return l > 0 && pathname[l - 1] == '/';
577
}
578
579
static int
580
process_get(struct sftp_conn *conn, const char *src, const char *dst,
581
    const char *pwd, int pflag, int rflag, int resume, int fflag)
582
{
583
	char *abs_src = NULL;
584
	char *abs_dst = NULL;
585
	glob_t g;
586
	char *filename, *tmp=NULL;
587
	int i, r, err = 0;
588
589
	abs_src = xstrdup(src);
590
	abs_src = make_absolute(abs_src, pwd);
591
	memset(&g, 0, sizeof(g));
592
593
	debug3("Looking up %s", abs_src);
594
	if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
595
		if (r == GLOB_NOSPACE) {
596
			error("Too many matches for \"%s\".", abs_src);
597
		} else {
598
			error("File \"%s\" not found.", abs_src);
599
		}
600
		err = -1;
601
		goto out;
602
	}
603
604
	/*
605
	 * If multiple matches then dst must be a directory or
606
	 * unspecified.
607
	 */
608
	if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) {
609
		error("Multiple source paths, but destination "
610
		    "\"%s\" is not a directory", dst);
611
		err = -1;
612
		goto out;
613
	}
614
615
	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
616
		tmp = xstrdup(g.gl_pathv[i]);
617
		if ((filename = basename(tmp)) == NULL) {
618
			error("basename %s: %s", tmp, strerror(errno));
619
			free(tmp);
620
			err = -1;
621
			goto out;
622
		}
623
624
		if (g.gl_matchc == 1 && dst) {
625
			if (is_dir(dst)) {
626
				abs_dst = path_append(dst, filename);
627
			} else {
628
				abs_dst = xstrdup(dst);
629
			}
630
		} else if (dst) {
631
			abs_dst = path_append(dst, filename);
632
		} else {
633
			abs_dst = xstrdup(filename);
634
		}
635
		free(tmp);
636
637
		resume |= global_aflag;
638
		if (!quiet && resume)
639
			mprintf("Resuming %s to %s\n",
640
			    g.gl_pathv[i], abs_dst);
641
		else if (!quiet && !resume)
642
			mprintf("Fetching %s to %s\n",
643
			    g.gl_pathv[i], abs_dst);
644
		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
645
			if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
646
			    pflag || global_pflag, 1, resume,
647
			    fflag || global_fflag) == -1)
648
				err = -1;
649
		} else {
650
			if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
651
			    pflag || global_pflag, resume,
652
			    fflag || global_fflag) == -1)
653
				err = -1;
654
		}
655
		free(abs_dst);
656
		abs_dst = NULL;
657
	}
658
659
out:
660
	free(abs_src);
661
	globfree(&g);
662
	return(err);
663
}
664
665
static int
666
process_put(struct sftp_conn *conn, const char *src, const char *dst,
667
    const char *pwd, int pflag, int rflag, int resume, int fflag)
668
{
669
	char *tmp_dst = NULL;
670
	char *abs_dst = NULL;
671
	char *tmp = NULL, *filename = NULL;
672
	glob_t g;
673
	int err = 0;
674
	int i, dst_is_dir = 1;
675
	struct stat sb;
676
677
	if (dst) {
678
		tmp_dst = xstrdup(dst);
679
		tmp_dst = make_absolute(tmp_dst, pwd);
680
	}
681
682
	memset(&g, 0, sizeof(g));
683
	debug3("Looking up %s", src);
684
	if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
685
		error("File \"%s\" not found.", src);
686
		err = -1;
687
		goto out;
688
	}
689
690
	/* If we aren't fetching to pwd then stash this status for later */
691
	if (tmp_dst != NULL)
692
		dst_is_dir = remote_is_dir(conn, tmp_dst);
693
694
	/* If multiple matches, dst may be directory or unspecified */
695
	if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
696
		error("Multiple paths match, but destination "
697
		    "\"%s\" is not a directory", tmp_dst);
698
		err = -1;
699
		goto out;
700
	}
701
702
	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
703
		if (stat(g.gl_pathv[i], &sb) == -1) {
704
			err = -1;
705
			error("stat %s: %s", g.gl_pathv[i], strerror(errno));
706
			continue;
707
		}
708
709
		tmp = xstrdup(g.gl_pathv[i]);
710
		if ((filename = basename(tmp)) == NULL) {
711
			error("basename %s: %s", tmp, strerror(errno));
712
			free(tmp);
713
			err = -1;
714
			goto out;
715
		}
716
717
		if (g.gl_matchc == 1 && tmp_dst) {
718
			/* If directory specified, append filename */
719
			if (dst_is_dir)
720
				abs_dst = path_append(tmp_dst, filename);
721
			else
722
				abs_dst = xstrdup(tmp_dst);
723
		} else if (tmp_dst) {
724
			abs_dst = path_append(tmp_dst, filename);
725
		} else {
726
			abs_dst = make_absolute(xstrdup(filename), pwd);
727
		}
728
		free(tmp);
729
730
                resume |= global_aflag;
731
		if (!quiet && resume)
732
			mprintf("Resuming upload of %s to %s\n",
733
			    g.gl_pathv[i], abs_dst);
734
		else if (!quiet && !resume)
735
			mprintf("Uploading %s to %s\n",
736
			    g.gl_pathv[i], abs_dst);
737
		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
738
			if (upload_dir(conn, g.gl_pathv[i], abs_dst,
739
			    pflag || global_pflag, 1, resume,
740
			    fflag || global_fflag) == -1)
741
				err = -1;
742
		} else {
743
			if (do_upload(conn, g.gl_pathv[i], abs_dst,
744
			    pflag || global_pflag, resume,
745
			    fflag || global_fflag) == -1)
746
				err = -1;
747
		}
748
	}
749
750
out:
751
	free(abs_dst);
752
	free(tmp_dst);
753
	globfree(&g);
754
	return(err);
755
}
756
757
static int
758
sdirent_comp(const void *aa, const void *bb)
759
{
760
	SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
761
	SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
762
	int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
763
764
#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
765
	if (sort_flag & LS_NAME_SORT)
766
		return (rmul * strcmp(a->filename, b->filename));
767
	else if (sort_flag & LS_TIME_SORT)
768
		return (rmul * NCMP(a->a.mtime, b->a.mtime));
769
	else if (sort_flag & LS_SIZE_SORT)
770
		return (rmul * NCMP(a->a.size, b->a.size));
771
772
	fatal("Unknown ls sort type");
773
}
774
775
/* sftp ls.1 replacement for directories */
776
static int
777
do_ls_dir(struct sftp_conn *conn, const char *path,
778
    const char *strip_path, int lflag)
779
{
780
	int n;
781
	u_int c = 1, colspace = 0, columns = 1;
782
	SFTP_DIRENT **d;
783
784
	if ((n = do_readdir(conn, path, &d)) != 0)
785
		return (n);
786
787
	if (!(lflag & LS_SHORT_VIEW)) {
788
		u_int m = 0, width = 80;
789
		struct winsize ws;
790
		char *tmp;
791
792
		/* Count entries for sort and find longest filename */
793
		for (n = 0; d[n] != NULL; n++) {
794
			if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
795
				m = MAXIMUM(m, strlen(d[n]->filename));
796
		}
797
798
		/* Add any subpath that also needs to be counted */
799
		tmp = path_strip(path, strip_path);
800
		m += strlen(tmp);
801
		free(tmp);
802
803
		if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
804
			width = ws.ws_col;
805
806
		columns = width / (m + 2);
807
		columns = MAXIMUM(columns, 1);
808
		colspace = width / columns;
809
		colspace = MINIMUM(colspace, width);
810
	}
811
812
	if (lflag & SORT_FLAGS) {
813
		for (n = 0; d[n] != NULL; n++)
814
			;	/* count entries */
815
		sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
816
		qsort(d, n, sizeof(*d), sdirent_comp);
817
	}
818
819
	for (n = 0; d[n] != NULL && !interrupted; n++) {
820
		char *tmp, *fname;
821
822
		if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
823
			continue;
824
825
		tmp = path_append(path, d[n]->filename);
826
		fname = path_strip(tmp, strip_path);
827
		free(tmp);
828
829
		if (lflag & LS_LONG_VIEW) {
830
			if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
831
				char *lname;
832
				struct stat sb;
833
834
				memset(&sb, 0, sizeof(sb));
835
				attrib_to_stat(&d[n]->a, &sb);
836
				lname = ls_file(fname, &sb, 1,
837
				    (lflag & LS_SI_UNITS));
838
				mprintf("%s\n", lname);
839
				free(lname);
840
			} else
841
				mprintf("%s\n", d[n]->longname);
842
		} else {
843
			mprintf("%-*s", colspace, fname);
844
			if (c >= columns) {
845
				printf("\n");
846
				c = 1;
847
			} else
848
				c++;
849
		}
850
851
		free(fname);
852
	}
853
854
	if (!(lflag & LS_LONG_VIEW) && (c != 1))
855
		printf("\n");
856
857
	free_sftp_dirents(d);
858
	return (0);
859
}
860
861
static int
862
sglob_comp(const void *aa, const void *bb)
863
{
864
	u_int a = *(const u_int *)aa;
865
	u_int b = *(const u_int *)bb;
866
	const char *ap = sort_glob->gl_pathv[a];
867
	const char *bp = sort_glob->gl_pathv[b];
868
	const struct stat *as = sort_glob->gl_statv[a];
869
	const struct stat *bs = sort_glob->gl_statv[b];
870
	int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
871
872
#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
873
	if (sort_flag & LS_NAME_SORT)
874
		return (rmul * strcmp(ap, bp));
875
	else if (sort_flag & LS_TIME_SORT)
876
		return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <));
877
	else if (sort_flag & LS_SIZE_SORT)
878
		return (rmul * NCMP(as->st_size, bs->st_size));
879
880
	fatal("Unknown ls sort type");
881
}
882
883
/* sftp ls.1 replacement which handles path globs */
884
static int
885
do_globbed_ls(struct sftp_conn *conn, const char *path,
886
    const char *strip_path, int lflag)
887
{
888
	char *fname, *lname;
889
	glob_t g;
890
	int err, r;
891
	struct winsize ws;
892
	u_int i, j, nentries, *indices = NULL, c = 1;
893
	u_int colspace = 0, columns = 1, m = 0, width = 80;
894
895
	memset(&g, 0, sizeof(g));
896
897
	if ((r = remote_glob(conn, path,
898
	    GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
899
	    NULL, &g)) != 0 ||
900
	    (g.gl_pathc && !g.gl_matchc)) {
901
		if (g.gl_pathc)
902
			globfree(&g);
903
		if (r == GLOB_NOSPACE) {
904
			error("Can't ls: Too many matches for \"%s\"", path);
905
		} else {
906
			error("Can't ls: \"%s\" not found", path);
907
		}
908
		return -1;
909
	}
910
911
	if (interrupted)
912
		goto out;
913
914
	/*
915
	 * If the glob returns a single match and it is a directory,
916
	 * then just list its contents.
917
	 */
918
	if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
919
	    S_ISDIR(g.gl_statv[0]->st_mode)) {
920
		err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
921
		globfree(&g);
922
		return err;
923
	}
924
925
	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
926
		width = ws.ws_col;
927
928
	if (!(lflag & LS_SHORT_VIEW)) {
929
		/* Count entries for sort and find longest filename */
930
		for (i = 0; g.gl_pathv[i]; i++)
931
			m = MAXIMUM(m, strlen(g.gl_pathv[i]));
932
933
		columns = width / (m + 2);
934
		columns = MAXIMUM(columns, 1);
935
		colspace = width / columns;
936
	}
937
938
	/*
939
	 * Sorting: rather than mess with the contents of glob_t, prepare
940
	 * an array of indices into it and sort that. For the usual
941
	 * unsorted case, the indices are just the identity 1=1, 2=2, etc.
942
	 */
943
	for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++)
944
		;	/* count entries */
945
	indices = calloc(nentries, sizeof(*indices));
946
	for (i = 0; i < nentries; i++)
947
		indices[i] = i;
948
949
	if (lflag & SORT_FLAGS) {
950
		sort_glob = &g;
951
		sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
952
		qsort(indices, nentries, sizeof(*indices), sglob_comp);
953
		sort_glob = NULL;
954
	}
955
956
	for (j = 0; j < nentries && !interrupted; j++) {
957
		i = indices[j];
958
		fname = path_strip(g.gl_pathv[i], strip_path);
959
		if (lflag & LS_LONG_VIEW) {
960
			if (g.gl_statv[i] == NULL) {
961
				error("no stat information for %s", fname);
962
				continue;
963
			}
964
			lname = ls_file(fname, g.gl_statv[i], 1,
965
			    (lflag & LS_SI_UNITS));
966
			mprintf("%s\n", lname);
967
			free(lname);
968
		} else {
969
			mprintf("%-*s", colspace, fname);
970
			if (c >= columns) {
971
				printf("\n");
972
				c = 1;
973
			} else
974
				c++;
975
		}
976
		free(fname);
977
	}
978
979
	if (!(lflag & LS_LONG_VIEW) && (c != 1))
980
		printf("\n");
981
982
 out:
983
	if (g.gl_pathc)
984
		globfree(&g);
985
	free(indices);
986
987
	return 0;
988
}
989
990
static int
991
do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
992
{
993
	struct sftp_statvfs st;
994
	char s_used[FMT_SCALED_STRSIZE], s_avail[FMT_SCALED_STRSIZE];
995
	char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE];
996
	char s_icapacity[16], s_dcapacity[16];
997
998
	if (do_statvfs(conn, path, &st, 1) == -1)
999
		return -1;
1000
	if (st.f_files == 0)
1001
		strlcpy(s_icapacity, "ERR", sizeof(s_icapacity));
1002
	else {
1003
		snprintf(s_icapacity, sizeof(s_icapacity), "%3llu%%",
1004
		    (unsigned long long)(100 * (st.f_files - st.f_ffree) /
1005
		    st.f_files));
1006
	}
1007
	if (st.f_blocks == 0)
1008
		strlcpy(s_dcapacity, "ERR", sizeof(s_dcapacity));
1009
	else {
1010
		snprintf(s_dcapacity, sizeof(s_dcapacity), "%3llu%%",
1011
		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
1012
		    st.f_blocks));
1013
	}
1014
	if (iflag) {
1015
		printf("     Inodes        Used       Avail      "
1016
		    "(root)    %%Capacity\n");
1017
		printf("%11llu %11llu %11llu %11llu         %s\n",
1018
		    (unsigned long long)st.f_files,
1019
		    (unsigned long long)(st.f_files - st.f_ffree),
1020
		    (unsigned long long)st.f_favail,
1021
		    (unsigned long long)st.f_ffree, s_icapacity);
1022
	} else if (hflag) {
1023
		strlcpy(s_used, "error", sizeof(s_used));
1024
		strlcpy(s_avail, "error", sizeof(s_avail));
1025
		strlcpy(s_root, "error", sizeof(s_root));
1026
		strlcpy(s_total, "error", sizeof(s_total));
1027
		fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
1028
		fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
1029
		fmt_scaled(st.f_bfree * st.f_frsize, s_root);
1030
		fmt_scaled(st.f_blocks * st.f_frsize, s_total);
1031
		printf("    Size     Used    Avail   (root)    %%Capacity\n");
1032
		printf("%7sB %7sB %7sB %7sB         %s\n",
1033
		    s_total, s_used, s_avail, s_root, s_dcapacity);
1034
	} else {
1035
		printf("        Size         Used        Avail       "
1036
		    "(root)    %%Capacity\n");
1037
		printf("%12llu %12llu %12llu %12llu         %s\n",
1038
		    (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
1039
		    (unsigned long long)(st.f_frsize *
1040
		    (st.f_blocks - st.f_bfree) / 1024),
1041
		    (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
1042
		    (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
1043
		    s_dcapacity);
1044
	}
1045
	return 0;
1046
}
1047
1048
/*
1049
 * Undo escaping of glob sequences in place. Used to undo extra escaping
1050
 * applied in makeargv() when the string is destined for a function that
1051
 * does not glob it.
1052
 */
1053
static void
1054
undo_glob_escape(char *s)
1055
{
1056
	size_t i, j;
1057
1058
	for (i = j = 0;;) {
1059
		if (s[i] == '\0') {
1060
			s[j] = '\0';
1061
			return;
1062
		}
1063
		if (s[i] != '\\') {
1064
			s[j++] = s[i++];
1065
			continue;
1066
		}
1067
		/* s[i] == '\\' */
1068
		++i;
1069
		switch (s[i]) {
1070
		case '?':
1071
		case '[':
1072
		case '*':
1073
		case '\\':
1074
			s[j++] = s[i++];
1075
			break;
1076
		case '\0':
1077
			s[j++] = '\\';
1078
			s[j] = '\0';
1079
			return;
1080
		default:
1081
			s[j++] = '\\';
1082
			s[j++] = s[i++];
1083
			break;
1084
		}
1085
	}
1086
}
1087
1088
/*
1089
 * Split a string into an argument vector using sh(1)-style quoting,
1090
 * comment and escaping rules, but with some tweaks to handle glob(3)
1091
 * wildcards.
1092
 * The "sloppy" flag allows for recovery from missing terminating quote, for
1093
 * use in parsing incomplete commandlines during tab autocompletion.
1094
 *
1095
 * Returns NULL on error or a NULL-terminated array of arguments.
1096
 *
1097
 * If "lastquote" is not NULL, the quoting character used for the last
1098
 * argument is placed in *lastquote ("\0", "'" or "\"").
1099
 *
1100
 * If "terminated" is not NULL, *terminated will be set to 1 when the
1101
 * last argument's quote has been properly terminated or 0 otherwise.
1102
 * This parameter is only of use if "sloppy" is set.
1103
 */
1104
#define MAXARGS 	128
1105
#define MAXARGLEN	8192
1106
static char **
1107
makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1108
    u_int *terminated)
1109
{
1110
	int argc, quot;
1111
	size_t i, j;
1112
	static char argvs[MAXARGLEN];
1113
	static char *argv[MAXARGS + 1];
1114
	enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
1115
1116
	*argcp = argc = 0;
1117
	if (strlen(arg) > sizeof(argvs) - 1) {
1118
 args_too_longs:
1119
		error("string too long");
1120
		return NULL;
1121
	}
1122
	if (terminated != NULL)
1123
		*terminated = 1;
1124
	if (lastquote != NULL)
1125
		*lastquote = '\0';
1126
	state = MA_START;
1127
	i = j = 0;
1128
	for (;;) {
1129
		if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){
1130
			error("Too many arguments.");
1131
			return NULL;
1132
		}
1133
		if (isspace((unsigned char)arg[i])) {
1134
			if (state == MA_UNQUOTED) {
1135
				/* Terminate current argument */
1136
				argvs[j++] = '\0';
1137
				argc++;
1138
				state = MA_START;
1139
			} else if (state != MA_START)
1140
				argvs[j++] = arg[i];
1141
		} else if (arg[i] == '"' || arg[i] == '\'') {
1142
			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
1143
			if (state == MA_START) {
1144
				argv[argc] = argvs + j;
1145
				state = q;
1146
				if (lastquote != NULL)
1147
					*lastquote = arg[i];
1148
			} else if (state == MA_UNQUOTED)
1149
				state = q;
1150
			else if (state == q)
1151
				state = MA_UNQUOTED;
1152
			else
1153
				argvs[j++] = arg[i];
1154
		} else if (arg[i] == '\\') {
1155
			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1156
				quot = state == MA_SQUOTE ? '\'' : '"';
1157
				/* Unescape quote we are in */
1158
				/* XXX support \n and friends? */
1159
				if (arg[i + 1] == quot) {
1160
					i++;
1161
					argvs[j++] = arg[i];
1162
				} else if (arg[i + 1] == '?' ||
1163
				    arg[i + 1] == '[' || arg[i + 1] == '*') {
1164
					/*
1165
					 * Special case for sftp: append
1166
					 * double-escaped glob sequence -
1167
					 * glob will undo one level of
1168
					 * escaping. NB. string can grow here.
1169
					 */
1170
					if (j >= sizeof(argvs) - 5)
1171
						goto args_too_longs;
1172
					argvs[j++] = '\\';
1173
					argvs[j++] = arg[i++];
1174
					argvs[j++] = '\\';
1175
					argvs[j++] = arg[i];
1176
				} else {
1177
					argvs[j++] = arg[i++];
1178
					argvs[j++] = arg[i];
1179
				}
1180
			} else {
1181
				if (state == MA_START) {
1182
					argv[argc] = argvs + j;
1183
					state = MA_UNQUOTED;
1184
					if (lastquote != NULL)
1185
						*lastquote = '\0';
1186
				}
1187
				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1188
				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
1189
					/*
1190
					 * Special case for sftp: append
1191
					 * escaped glob sequence -
1192
					 * glob will undo one level of
1193
					 * escaping.
1194
					 */
1195
					argvs[j++] = arg[i++];
1196
					argvs[j++] = arg[i];
1197
				} else {
1198
					/* Unescape everything */
1199
					/* XXX support \n and friends? */
1200
					i++;
1201
					argvs[j++] = arg[i];
1202
				}
1203
			}
1204
		} else if (arg[i] == '#') {
1205
			if (state == MA_SQUOTE || state == MA_DQUOTE)
1206
				argvs[j++] = arg[i];
1207
			else
1208
				goto string_done;
1209
		} else if (arg[i] == '\0') {
1210
			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1211
				if (sloppy) {
1212
					state = MA_UNQUOTED;
1213
					if (terminated != NULL)
1214
						*terminated = 0;
1215
					goto string_done;
1216
				}
1217
				error("Unterminated quoted argument");
1218
				return NULL;
1219
			}
1220
 string_done:
1221
			if (state == MA_UNQUOTED) {
1222
				argvs[j++] = '\0';
1223
				argc++;
1224
			}
1225
			break;
1226
		} else {
1227
			if (state == MA_START) {
1228
				argv[argc] = argvs + j;
1229
				state = MA_UNQUOTED;
1230
				if (lastquote != NULL)
1231
					*lastquote = '\0';
1232
			}
1233
			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1234
			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1235
				/*
1236
				 * Special case for sftp: escape quoted
1237
				 * glob(3) wildcards. NB. string can grow
1238
				 * here.
1239
				 */
1240
				if (j >= sizeof(argvs) - 3)
1241
					goto args_too_longs;
1242
				argvs[j++] = '\\';
1243
				argvs[j++] = arg[i];
1244
			} else
1245
				argvs[j++] = arg[i];
1246
		}
1247
		i++;
1248
	}
1249
	*argcp = argc;
1250
	return argv;
1251
}
1252
1253
static int
1254
parse_args(const char **cpp, int *ignore_errors, int *aflag,
1255
	  int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1256
	  int *rflag, int *sflag,
1257
    unsigned long *n_arg, char **path1, char **path2)
1258
{
1259
	const char *cmd, *cp = *cpp;
1260
	char *cp2, **argv;
1261
	int base = 0;
1262
	long l;
1263
	int i, cmdnum, optidx, argc;
1264
1265
	/* Skip leading whitespace */
1266
	cp = cp + strspn(cp, WHITESPACE);
1267
1268
	/* Check for leading '-' (disable error processing) */
1269
	*ignore_errors = 0;
1270
	if (*cp == '-') {
1271
		*ignore_errors = 1;
1272
		cp++;
1273
		cp = cp + strspn(cp, WHITESPACE);
1274
	}
1275
1276
	/* Ignore blank lines and lines which begin with comment '#' char */
1277
	if (*cp == '\0' || *cp == '#')
1278
		return (0);
1279
1280
	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1281
		return -1;
1282
1283
	/* Figure out which command we have */
1284
	for (i = 0; cmds[i].c != NULL; i++) {
1285
		if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0)
1286
			break;
1287
	}
1288
	cmdnum = cmds[i].n;
1289
	cmd = cmds[i].c;
1290
1291
	/* Special case */
1292
	if (*cp == '!') {
1293
		cp++;
1294
		cmdnum = I_SHELL;
1295
	} else if (cmdnum == -1) {
1296
		error("Invalid command.");
1297
		return -1;
1298
	}
1299
1300
	/* Get arguments and parse flags */
1301
	*aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
1302
	*rflag = *sflag = 0;
1303
	*path1 = *path2 = NULL;
1304
	optidx = 1;
1305
	switch (cmdnum) {
1306
	case I_GET:
1307
	case I_REGET:
1308
	case I_REPUT:
1309
	case I_PUT:
1310
		if ((optidx = parse_getput_flags(cmd, argv, argc,
1311
		    aflag, fflag, pflag, rflag)) == -1)
1312
			return -1;
1313
		/* Get first pathname (mandatory) */
1314
		if (argc - optidx < 1) {
1315
			error("You must specify at least one path after a "
1316
			    "%s command.", cmd);
1317
			return -1;
1318
		}
1319
		*path1 = xstrdup(argv[optidx]);
1320
		/* Get second pathname (optional) */
1321
		if (argc - optidx > 1) {
1322
			*path2 = xstrdup(argv[optidx + 1]);
1323
			/* Destination is not globbed */
1324
			undo_glob_escape(*path2);
1325
		}
1326
		break;
1327
	case I_LINK:
1328
		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1329
			return -1;
1330
		goto parse_two_paths;
1331
	case I_RENAME:
1332
		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1333
			return -1;
1334
		goto parse_two_paths;
1335
	case I_SYMLINK:
1336
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1337
			return -1;
1338
 parse_two_paths:
1339
		if (argc - optidx < 2) {
1340
			error("You must specify two paths after a %s "
1341
			    "command.", cmd);
1342
			return -1;
1343
		}
1344
		*path1 = xstrdup(argv[optidx]);
1345
		*path2 = xstrdup(argv[optidx + 1]);
1346
		/* Paths are not globbed */
1347
		undo_glob_escape(*path1);
1348
		undo_glob_escape(*path2);
1349
		break;
1350
	case I_RM:
1351
	case I_MKDIR:
1352
	case I_RMDIR:
1353
	case I_CHDIR:
1354
	case I_LCHDIR:
1355
	case I_LMKDIR:
1356
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1357
			return -1;
1358
		/* Get pathname (mandatory) */
1359
		if (argc - optidx < 1) {
1360
			error("You must specify a path after a %s command.",
1361
			    cmd);
1362
			return -1;
1363
		}
1364
		*path1 = xstrdup(argv[optidx]);
1365
		/* Only "rm" globs */
1366
		if (cmdnum != I_RM)
1367
			undo_glob_escape(*path1);
1368
		break;
1369
	case I_DF:
1370
		if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
1371
		    iflag)) == -1)
1372
			return -1;
1373
		/* Default to current directory if no path specified */
1374
		if (argc - optidx < 1)
1375
			*path1 = NULL;
1376
		else {
1377
			*path1 = xstrdup(argv[optidx]);
1378
			undo_glob_escape(*path1);
1379
		}
1380
		break;
1381
	case I_LS:
1382
		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
1383
			return(-1);
1384
		/* Path is optional */
1385
		if (argc - optidx > 0)
1386
			*path1 = xstrdup(argv[optidx]);
1387
		break;
1388
	case I_LLS:
1389
		/* Skip ls command and following whitespace */
1390
		cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
1391
	case I_SHELL:
1392
		/* Uses the rest of the line */
1393
		break;
1394
	case I_LUMASK:
1395
	case I_CHMOD:
1396
		base = 8;
1397
	case I_CHOWN:
1398
	case I_CHGRP:
1399
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1400
			return -1;
1401
		/* Get numeric arg (mandatory) */
1402
		if (argc - optidx < 1)
1403
			goto need_num_arg;
1404
		errno = 0;
1405
		l = strtol(argv[optidx], &cp2, base);
1406
		if (cp2 == argv[optidx] || *cp2 != '\0' ||
1407
		    ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
1408
		    l < 0) {
1409
 need_num_arg:
1410
			error("You must supply a numeric argument "
1411
			    "to the %s command.", cmd);
1412
			return -1;
1413
		}
1414
		*n_arg = l;
1415
		if (cmdnum == I_LUMASK)
1416
			break;
1417
		/* Get pathname (mandatory) */
1418
		if (argc - optidx < 2) {
1419
			error("You must specify a path after a %s command.",
1420
			    cmd);
1421
			return -1;
1422
		}
1423
		*path1 = xstrdup(argv[optidx + 1]);
1424
		break;
1425
	case I_QUIT:
1426
	case I_PWD:
1427
	case I_LPWD:
1428
	case I_HELP:
1429
	case I_VERSION:
1430
	case I_PROGRESS:
1431
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1432
			return -1;
1433
		break;
1434
	default:
1435
		fatal("Command not implemented");
1436
	}
1437
1438
	*cpp = cp;
1439
	return(cmdnum);
1440
}
1441
1442
static int
1443
parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1444
    int err_abort)
1445
{
1446
	char *path1, *path2, *tmp;
1447
	int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0,
1448
	iflag = 0;
1449
	int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1450
	int cmdnum, i;
1451
	unsigned long n_arg = 0;
1452
	Attrib a, *aa;
1453
	char path_buf[PATH_MAX];
1454
	int err = 0;
1455
	glob_t g;
1456
1457
	path1 = path2 = NULL;
1458
	cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag,
1459
	    &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2);
1460
	if (ignore_errors != 0)
1461
		err_abort = 0;
1462
1463
	memset(&g, 0, sizeof(g));
1464
1465
	/* Perform command */
1466
	switch (cmdnum) {
1467
	case 0:
1468
		/* Blank line */
1469
		break;
1470
	case -1:
1471
		/* Unrecognized command */
1472
		err = -1;
1473
		break;
1474
	case I_REGET:
1475
		aflag = 1;
1476
		/* FALLTHROUGH */
1477
	case I_GET:
1478
		err = process_get(conn, path1, path2, *pwd, pflag,
1479
		    rflag, aflag, fflag);
1480
		break;
1481
	case I_REPUT:
1482
		aflag = 1;
1483
		/* FALLTHROUGH */
1484
	case I_PUT:
1485
		err = process_put(conn, path1, path2, *pwd, pflag,
1486
		    rflag, aflag, fflag);
1487
		break;
1488
	case I_RENAME:
1489
		path1 = make_absolute(path1, *pwd);
1490
		path2 = make_absolute(path2, *pwd);
1491
		err = do_rename(conn, path1, path2, lflag);
1492
		break;
1493
	case I_SYMLINK:
1494
		sflag = 1;
1495
	case I_LINK:
1496
		if (!sflag)
1497
			path1 = make_absolute(path1, *pwd);
1498
		path2 = make_absolute(path2, *pwd);
1499
		err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1500
		break;
1501
	case I_RM:
1502
		path1 = make_absolute(path1, *pwd);
1503
		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1504
		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1505
			if (!quiet)
1506
				mprintf("Removing %s\n", g.gl_pathv[i]);
1507
			err = do_rm(conn, g.gl_pathv[i]);
1508
			if (err != 0 && err_abort)
1509
				break;
1510
		}
1511
		break;
1512
	case I_MKDIR:
1513
		path1 = make_absolute(path1, *pwd);
1514
		attrib_clear(&a);
1515
		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1516
		a.perm = 0777;
1517
		err = do_mkdir(conn, path1, &a, 1);
1518
		break;
1519
	case I_RMDIR:
1520
		path1 = make_absolute(path1, *pwd);
1521
		err = do_rmdir(conn, path1);
1522
		break;
1523
	case I_CHDIR:
1524
		path1 = make_absolute(path1, *pwd);
1525
		if ((tmp = do_realpath(conn, path1)) == NULL) {
1526
			err = 1;
1527
			break;
1528
		}
1529
		if ((aa = do_stat(conn, tmp, 0)) == NULL) {
1530
			free(tmp);
1531
			err = 1;
1532
			break;
1533
		}
1534
		if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
1535
			error("Can't change directory: Can't check target");
1536
			free(tmp);
1537
			err = 1;
1538
			break;
1539
		}
1540
		if (!S_ISDIR(aa->perm)) {
1541
			error("Can't change directory: \"%s\" is not "
1542
			    "a directory", tmp);
1543
			free(tmp);
1544
			err = 1;
1545
			break;
1546
		}
1547
		free(*pwd);
1548
		*pwd = tmp;
1549
		break;
1550
	case I_LS:
1551
		if (!path1) {
1552
			do_ls_dir(conn, *pwd, *pwd, lflag);
1553
			break;
1554
		}
1555
1556
		/* Strip pwd off beginning of non-absolute paths */
1557
		tmp = NULL;
1558
		if (*path1 != '/')
1559
			tmp = *pwd;
1560
1561
		path1 = make_absolute(path1, *pwd);
1562
		err = do_globbed_ls(conn, path1, tmp, lflag);
1563
		break;
1564
	case I_DF:
1565
		/* Default to current directory if no path specified */
1566
		if (path1 == NULL)
1567
			path1 = xstrdup(*pwd);
1568
		path1 = make_absolute(path1, *pwd);
1569
		err = do_df(conn, path1, hflag, iflag);
1570
		break;
1571
	case I_LCHDIR:
1572
		tmp = tilde_expand_filename(path1, getuid());
1573
		free(path1);
1574
		path1 = tmp;
1575
		if (chdir(path1) == -1) {
1576
			error("Couldn't change local directory to "
1577
			    "\"%s\": %s", path1, strerror(errno));
1578
			err = 1;
1579
		}
1580
		break;
1581
	case I_LMKDIR:
1582
		if (mkdir(path1, 0777) == -1) {
1583
			error("Couldn't create local directory "
1584
			    "\"%s\": %s", path1, strerror(errno));
1585
			err = 1;
1586
		}
1587
		break;
1588
	case I_LLS:
1589
		local_do_ls(cmd);
1590
		break;
1591
	case I_SHELL:
1592
		local_do_shell(cmd);
1593
		break;
1594
	case I_LUMASK:
1595
		umask(n_arg);
1596
		printf("Local umask: %03lo\n", n_arg);
1597
		break;
1598
	case I_CHMOD:
1599
		path1 = make_absolute(path1, *pwd);
1600
		attrib_clear(&a);
1601
		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1602
		a.perm = n_arg;
1603
		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1604
		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1605
			if (!quiet)
1606
				mprintf("Changing mode on %s\n",
1607
				    g.gl_pathv[i]);
1608
			err = do_setstat(conn, g.gl_pathv[i], &a);
1609
			if (err != 0 && err_abort)
1610
				break;
1611
		}
1612
		break;
1613
	case I_CHOWN:
1614
	case I_CHGRP:
1615
		path1 = make_absolute(path1, *pwd);
1616
		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1617
		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1618
			if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1619
				if (err_abort) {
1620
					err = -1;
1621
					break;
1622
				} else
1623
					continue;
1624
			}
1625
			if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
1626
				error("Can't get current ownership of "
1627
				    "remote file \"%s\"", g.gl_pathv[i]);
1628
				if (err_abort) {
1629
					err = -1;
1630
					break;
1631
				} else
1632
					continue;
1633
			}
1634
			aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
1635
			if (cmdnum == I_CHOWN) {
1636
				if (!quiet)
1637
					mprintf("Changing owner on %s\n",
1638
					    g.gl_pathv[i]);
1639
				aa->uid = n_arg;
1640
			} else {
1641
				if (!quiet)
1642
					mprintf("Changing group on %s\n",
1643
					    g.gl_pathv[i]);
1644
				aa->gid = n_arg;
1645
			}
1646
			err = do_setstat(conn, g.gl_pathv[i], aa);
1647
			if (err != 0 && err_abort)
1648
				break;
1649
		}
1650
		break;
1651
	case I_PWD:
1652
		mprintf("Remote working directory: %s\n", *pwd);
1653
		break;
1654
	case I_LPWD:
1655
		if (!getcwd(path_buf, sizeof(path_buf))) {
1656
			error("Couldn't get local cwd: %s", strerror(errno));
1657
			err = -1;
1658
			break;
1659
		}
1660
		mprintf("Local working directory: %s\n", path_buf);
1661
		break;
1662
	case I_QUIT:
1663
		/* Processed below */
1664
		break;
1665
	case I_HELP:
1666
		help();
1667
		break;
1668
	case I_VERSION:
1669
		printf("SFTP protocol version %u\n", sftp_proto_version(conn));
1670
		break;
1671
	case I_PROGRESS:
1672
		showprogress = !showprogress;
1673
		if (showprogress)
1674
			printf("Progress meter enabled\n");
1675
		else
1676
			printf("Progress meter disabled\n");
1677
		break;
1678
	default:
1679
		fatal("%d is not implemented", cmdnum);
1680
	}
1681
1682
	if (g.gl_pathc)
1683
		globfree(&g);
1684
	free(path1);
1685
	free(path2);
1686
1687
	/* If an unignored error occurs in batch mode we should abort. */
1688
	if (err_abort && err != 0)
1689
		return (-1);
1690
	else if (cmdnum == I_QUIT)
1691
		return (1);
1692
1693
	return (0);
1694
}
1695
1696
static char *
1697
prompt(EditLine *el)
1698
{
1699
	return ("sftp> ");
1700
}
1701
1702
/* Display entries in 'list' after skipping the first 'len' chars */
1703
static void
1704
complete_display(char **list, u_int len)
1705
{
1706
	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1707
	struct winsize ws;
1708
	char *tmp;
1709
1710
	/* Count entries for sort and find longest */
1711
	for (y = 0; list[y]; y++)
1712
		m = MAXIMUM(m, strlen(list[y]));
1713
1714
	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1715
		width = ws.ws_col;
1716
1717
	m = m > len ? m - len : 0;
1718
	columns = width / (m + 2);
1719
	columns = MAXIMUM(columns, 1);
1720
	colspace = width / columns;
1721
	colspace = MINIMUM(colspace, width);
1722
1723
	printf("\n");
1724
	m = 1;
1725
	for (y = 0; list[y]; y++) {
1726
		llen = strlen(list[y]);
1727
		tmp = llen > len ? list[y] + len : "";
1728
		mprintf("%-*s", colspace, tmp);
1729
		if (m >= columns) {
1730
			printf("\n");
1731
			m = 1;
1732
		} else
1733
			m++;
1734
	}
1735
	printf("\n");
1736
}
1737
1738
/*
1739
 * Given a "list" of words that begin with a common prefix of "word",
1740
 * attempt to find an autocompletion to extends "word" by the next
1741
 * characters common to all entries in "list".
1742
 */
1743
static char *
1744
complete_ambiguous(const char *word, char **list, size_t count)
1745
{
1746
	if (word == NULL)
1747
		return NULL;
1748
1749
	if (count > 0) {
1750
		u_int y, matchlen = strlen(list[0]);
1751
1752
		/* Find length of common stem */
1753
		for (y = 1; list[y]; y++) {
1754
			u_int x;
1755
1756
			for (x = 0; x < matchlen; x++)
1757
				if (list[0][x] != list[y][x])
1758
					break;
1759
1760
			matchlen = x;
1761
		}
1762
1763
		if (matchlen > strlen(word)) {
1764
			char *tmp = xstrdup(list[0]);
1765
1766
			tmp[matchlen] = '\0';
1767
			return tmp;
1768
		}
1769
	}
1770
1771
	return xstrdup(word);
1772
}
1773
1774
/* Autocomplete a sftp command */
1775
static int
1776
complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1777
    int terminated)
1778
{
1779
	u_int y, count = 0, cmdlen, tmplen;
1780
	char *tmp, **list, argterm[3];
1781
	const LineInfo *lf;
1782
1783
	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1784
1785
	/* No command specified: display all available commands */
1786
	if (cmd == NULL) {
1787
		for (y = 0; cmds[y].c; y++)
1788
			list[count++] = xstrdup(cmds[y].c);
1789
1790
		list[count] = NULL;
1791
		complete_display(list, 0);
1792
1793
		for (y = 0; list[y] != NULL; y++)
1794
			free(list[y]);
1795
		free(list);
1796
		return count;
1797
	}
1798
1799
	/* Prepare subset of commands that start with "cmd" */
1800
	cmdlen = strlen(cmd);
1801
	for (y = 0; cmds[y].c; y++)  {
1802
		if (!strncasecmp(cmd, cmds[y].c, cmdlen))
1803
			list[count++] = xstrdup(cmds[y].c);
1804
	}
1805
	list[count] = NULL;
1806
1807
	if (count == 0) {
1808
		free(list);
1809
		return 0;
1810
	}
1811
1812
	/* Complete ambigious command */
1813
	tmp = complete_ambiguous(cmd, list, count);
1814
	if (count > 1)
1815
		complete_display(list, 0);
1816
1817
	for (y = 0; list[y]; y++)
1818
		free(list[y]);
1819
	free(list);
1820
1821
	if (tmp != NULL) {
1822
		tmplen = strlen(tmp);
1823
		cmdlen = strlen(cmd);
1824
		/* If cmd may be extended then do so */
1825
		if (tmplen > cmdlen)
1826
			if (el_insertstr(el, tmp + cmdlen) == -1)
1827
				fatal("el_insertstr failed.");
1828
		lf = el_line(el);
1829
		/* Terminate argument cleanly */
1830
		if (count == 1) {
1831
			y = 0;
1832
			if (!terminated)
1833
				argterm[y++] = quote;
1834
			if (lastarg || *(lf->cursor) != ' ')
1835
				argterm[y++] = ' ';
1836
			argterm[y] = '\0';
1837
			if (y > 0 && el_insertstr(el, argterm) == -1)
1838
				fatal("el_insertstr failed.");
1839
		}
1840
		free(tmp);
1841
	}
1842
1843
	return count;
1844
}
1845
1846
/*
1847
 * Determine whether a particular sftp command's arguments (if any)
1848
 * represent local or remote files.
1849
 */
1850
static int
1851
complete_is_remote(char *cmd) {
1852
	int i;
1853
1854
	if (cmd == NULL)
1855
		return -1;
1856
1857
	for (i = 0; cmds[i].c; i++) {
1858
		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
1859
			return cmds[i].t;
1860
	}
1861
1862
	return -1;
1863
}
1864
1865
/* Autocomplete a filename "file" */
1866
static int
1867
complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1868
    char *file, int remote, int lastarg, char quote, int terminated)
1869
{
1870
	glob_t g;
1871
	char *tmp, *tmp2, ins[8];
1872
	u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs;
1873
	int clen;
1874
	const LineInfo *lf;
1875
1876
	/* Glob from "file" location */
1877
	if (file == NULL)
1878
		tmp = xstrdup("*");
1879
	else
1880
		xasprintf(&tmp, "%s*", file);
1881
1882
	/* Check if the path is absolute. */
1883
	isabs = tmp[0] == '/';
1884
1885
	memset(&g, 0, sizeof(g));
1886
	if (remote != LOCAL) {
1887
		tmp = make_absolute(tmp, remote_path);
1888
		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1889
	} else
1890
		glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1891
1892
	/* Determine length of pwd so we can trim completion display */
1893
	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1894
		/* Terminate counting on first unescaped glob metacharacter */
1895
		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1896
			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1897
				hadglob = 1;
1898
			break;
1899
		}
1900
		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1901
			tmplen++;
1902
		if (tmp[tmplen] == '/')
1903
			pwdlen = tmplen + 1;	/* track last seen '/' */
1904
	}
1905
	free(tmp);
1906
	tmp = NULL;
1907
1908
	if (g.gl_matchc == 0)
1909
		goto out;
1910
1911
	if (g.gl_matchc > 1)
1912
		complete_display(g.gl_pathv, pwdlen);
1913
1914
	/* Don't try to extend globs */
1915
	if (file == NULL || hadglob)
1916
		goto out;
1917
1918
	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1919
	tmp = path_strip(tmp2, isabs ? NULL : remote_path);
1920
	free(tmp2);
1921
1922
	if (tmp == NULL)
1923
		goto out;
1924
1925
	tmplen = strlen(tmp);
1926
	filelen = strlen(file);
1927
1928
	/* Count the number of escaped characters in the input string. */
1929
	cesc = isesc = 0;
1930
	for (i = 0; i < filelen; i++) {
1931
		if (!isesc && file[i] == '\\' && i + 1 < filelen){
1932
			isesc = 1;
1933
			cesc++;
1934
		} else
1935
			isesc = 0;
1936
	}
1937
1938
	if (tmplen > (filelen - cesc)) {
1939
		tmp2 = tmp + filelen - cesc;
1940
		len = strlen(tmp2);
1941
		/* quote argument on way out */
1942
		for (i = 0; i < len; i += clen) {
1943
			if ((clen = mblen(tmp2 + i, len - i)) < 0 ||
1944
			    (size_t)clen > sizeof(ins) - 2)
1945
				fatal("invalid multibyte character");
1946
			ins[0] = '\\';
1947
			memcpy(ins + 1, tmp2 + i, clen);
1948
			ins[clen + 1] = '\0';
1949
			switch (tmp2[i]) {
1950
			case '\'':
1951
			case '"':
1952
			case '\\':
1953
			case '\t':
1954
			case '[':
1955
			case ' ':
1956
			case '#':
1957
			case '*':
1958
				if (quote == '\0' || tmp2[i] == quote) {
1959
					if (el_insertstr(el, ins) == -1)
1960
						fatal("el_insertstr "
1961
						    "failed.");
1962
					break;
1963
				}
1964
				/* FALLTHROUGH */
1965
			default:
1966
				if (el_insertstr(el, ins + 1) == -1)
1967
					fatal("el_insertstr failed.");
1968
				break;
1969
			}
1970
		}
1971
	}
1972
1973
	lf = el_line(el);
1974
	if (g.gl_matchc == 1) {
1975
		i = 0;
1976
		if (!terminated && quote != '\0')
1977
			ins[i++] = quote;
1978
		if (*(lf->cursor - 1) != '/' &&
1979
		    (lastarg || *(lf->cursor) != ' '))
1980
			ins[i++] = ' ';
1981
		ins[i] = '\0';
1982
		if (i > 0 && el_insertstr(el, ins) == -1)
1983
			fatal("el_insertstr failed.");
1984
	}
1985
	free(tmp);
1986
1987
 out:
1988
	globfree(&g);
1989
	return g.gl_matchc;
1990
}
1991
1992
/* tab-completion hook function, called via libedit */
1993
static unsigned char
1994
complete(EditLine *el, int ch)
1995
{
1996
	char **argv, *line, quote;
1997
	int argc, carg;
1998
	u_int cursor, len, terminated, ret = CC_ERROR;
1999
	const LineInfo *lf;
2000
	struct complete_ctx *complete_ctx;
2001
2002
	lf = el_line(el);
2003
	if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
2004
		fatal("%s: el_get failed", __func__);
2005
2006
	/* Figure out which argument the cursor points to */
2007
	cursor = lf->cursor - lf->buffer;
2008
	line = xmalloc(cursor + 1);
2009
	memcpy(line, lf->buffer, cursor);
2010
	line[cursor] = '\0';
2011
	argv = makeargv(line, &carg, 1, &quote, &terminated);
2012
	free(line);
2013
2014
	/* Get all the arguments on the line */
2015
	len = lf->lastchar - lf->buffer;
2016
	line = xmalloc(len + 1);
2017
	memcpy(line, lf->buffer, len);
2018
	line[len] = '\0';
2019
	argv = makeargv(line, &argc, 1, NULL, NULL);
2020
2021
	/* Ensure cursor is at EOL or a argument boundary */
2022
	if (line[cursor] != ' ' && line[cursor] != '\0' &&
2023
	    line[cursor] != '\n') {
2024
		free(line);
2025
		return ret;
2026
	}
2027
2028
	if (carg == 0) {
2029
		/* Show all available commands */
2030
		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
2031
		ret = CC_REDISPLAY;
2032
	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
2033
		/* Handle the command parsing */
2034
		if (complete_cmd_parse(el, argv[0], argc == carg,
2035
		    quote, terminated) != 0)
2036
			ret = CC_REDISPLAY;
2037
	} else if (carg >= 1) {
2038
		/* Handle file parsing */
2039
		int remote = complete_is_remote(argv[0]);
2040
		char *filematch = NULL;
2041
2042
		if (carg > 1 && line[cursor-1] != ' ')
2043
			filematch = argv[carg - 1];
2044
2045
		if (remote != 0 &&
2046
		    complete_match(el, complete_ctx->conn,
2047
		    *complete_ctx->remote_pathp, filematch,
2048
		    remote, carg == argc, quote, terminated) != 0)
2049
			ret = CC_REDISPLAY;
2050
	}
2051
2052
	free(line);
2053
	return ret;
2054
}
2055
2056
int
2057
interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2058
{
2059
	char *remote_path;
2060
	char *dir = NULL;
2061
	char cmd[2048];
2062
	int err, interactive;
2063
	EditLine *el = NULL;
2064
	History *hl = NULL;
2065
	HistEvent hev;
2066
	extern char *__progname;
2067
	struct complete_ctx complete_ctx;
2068
2069
	if (!batchmode && isatty(STDIN_FILENO)) {
2070
		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
2071
			fatal("Couldn't initialise editline");
2072
		if ((hl = history_init()) == NULL)
2073
			fatal("Couldn't initialise editline history");
2074
		history(hl, &hev, H_SETSIZE, 100);
2075
		el_set(el, EL_HIST, history, hl);
2076
2077
		el_set(el, EL_PROMPT, prompt);
2078
		el_set(el, EL_EDITOR, "emacs");
2079
		el_set(el, EL_TERMINAL, NULL);
2080
		el_set(el, EL_SIGNAL, 1);
2081
		el_source(el, NULL);
2082
2083
		/* Tab Completion */
2084
		el_set(el, EL_ADDFN, "ftp-complete",
2085
		    "Context sensitive argument completion", complete);
2086
		complete_ctx.conn = conn;
2087
		complete_ctx.remote_pathp = &remote_path;
2088
		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
2089
		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
2090
		/* enable ctrl-left-arrow and ctrl-right-arrow */
2091
		el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
2092
		el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL);
2093
		el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
2094
		el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
2095
		/* make ^w match ksh behaviour */
2096
		el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL);
2097
	}
2098
2099
	remote_path = do_realpath(conn, ".");
2100
	if (remote_path == NULL)
2101
		fatal("Need cwd");
2102
2103
	if (file1 != NULL) {
2104
		dir = xstrdup(file1);
2105
		dir = make_absolute(dir, remote_path);
2106
2107
		if (remote_is_dir(conn, dir) && file2 == NULL) {
2108
			if (!quiet)
2109
				mprintf("Changing to: %s\n", dir);
2110
			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
2111
			if (parse_dispatch_command(conn, cmd,
2112
			    &remote_path, 1) != 0) {
2113
				free(dir);
2114
				free(remote_path);
2115
				free(conn);
2116
				return (-1);
2117
			}
2118
		} else {
2119
			/* XXX this is wrong wrt quoting */
2120
			snprintf(cmd, sizeof cmd, "get%s %s%s%s",
2121
			    global_aflag ? " -a" : "", dir,
2122
			    file2 == NULL ? "" : " ",
2123
			    file2 == NULL ? "" : file2);
2124
			err = parse_dispatch_command(conn, cmd,
2125
			    &remote_path, 1);
2126
			free(dir);
2127
			free(remote_path);
2128
			free(conn);
2129
			return (err);
2130
		}
2131
		free(dir);
2132
	}
2133
2134
	setvbuf(stdout, NULL, _IOLBF, 0);
2135
	setvbuf(infile, NULL, _IOLBF, 0);
2136
2137
	interactive = !batchmode && isatty(STDIN_FILENO);
2138
	err = 0;
2139
	for (;;) {
2140
		char *cp;
2141
		const char *line;
2142
		int count = 0;
2143
2144
		signal(SIGINT, SIG_IGN);
2145
2146
		if (el == NULL) {
2147
			if (interactive)
2148
				printf("sftp> ");
2149
			if (fgets(cmd, sizeof(cmd), infile) == NULL) {
2150
				if (interactive)
2151
					printf("\n");
2152
				break;
2153
			}
2154
			if (!interactive) { /* Echo command */
2155
				mprintf("sftp> %s", cmd);
2156
				if (strlen(cmd) > 0 &&
2157
				    cmd[strlen(cmd) - 1] != '\n')
2158
					printf("\n");
2159
			}
2160
		} else {
2161
			if ((line = el_gets(el, &count)) == NULL ||
2162
			    count <= 0) {
2163
				printf("\n");
2164
				break;
2165
			}
2166
			history(hl, &hev, H_ENTER, line);
2167
			if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
2168
				fprintf(stderr, "Error: input line too long\n");
2169
				continue;
2170
			}
2171
		}
2172
2173
		cp = strrchr(cmd, '\n');
2174
		if (cp)
2175
			*cp = '\0';
2176
2177
		/* Handle user interrupts gracefully during commands */
2178
		interrupted = 0;
2179
		signal(SIGINT, cmd_interrupt);
2180
2181
		err = parse_dispatch_command(conn, cmd, &remote_path,
2182
		    batchmode);
2183
		if (err != 0)
2184
			break;
2185
	}
2186
	free(remote_path);
2187
	free(conn);
2188
2189
	if (el != NULL)
2190
		el_end(el);
2191
2192
	/* err == 1 signifies normal "quit" exit */
2193
	return (err >= 0 ? 0 : -1);
2194
}
2195
2196
static void
2197
connect_to_server(char *path, char **args, int *in, int *out)
2198
{
2199
	int c_in, c_out;
2200
2201
	int inout[2];
2202
2203
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2204
		fatal("socketpair: %s", strerror(errno));
2205
	*in = *out = inout[0];
2206
	c_in = c_out = inout[1];
2207
2208
	if ((sshpid = fork()) == -1)
2209
		fatal("fork: %s", strerror(errno));
2210
	else if (sshpid == 0) {
2211
		if ((dup2(c_in, STDIN_FILENO) == -1) ||
2212
		    (dup2(c_out, STDOUT_FILENO) == -1)) {
2213
			fprintf(stderr, "dup2: %s\n", strerror(errno));
2214
			_exit(1);
2215
		}
2216
		close(*in);
2217
		close(*out);
2218
		close(c_in);
2219
		close(c_out);
2220
2221
		/*
2222
		 * The underlying ssh is in the same process group, so we must
2223
		 * ignore SIGINT if we want to gracefully abort commands,
2224
		 * otherwise the signal will make it to the ssh process and
2225
		 * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2226
		 * underlying ssh, it must *not* ignore that signal.
2227
		 */
2228
		signal(SIGINT, SIG_IGN);
2229
		signal(SIGTERM, SIG_DFL);
2230
		execvp(path, args);
2231
		fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2232
		_exit(1);
2233
	}
2234
2235
	signal(SIGTERM, killchild);
2236
	signal(SIGINT, killchild);
2237
	signal(SIGHUP, killchild);
2238
	signal(SIGTSTP, suspchild);
2239
	signal(SIGTTIN, suspchild);
2240
	signal(SIGTTOU, suspchild);
2241
	close(c_in);
2242
	close(c_out);
2243
}
2244
2245
static void
2246
usage(void)
2247
{
2248
	extern char *__progname;
2249
2250
	fprintf(stderr,
2251
	    "usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2252
	    "          [-D sftp_server_path] [-F ssh_config] "
2253
	    "[-i identity_file] [-l limit]\n"
2254
	    "          [-o ssh_option] [-P port] [-R num_requests] "
2255
	    "[-S program]\n"
2256
	    "          [-s subsystem | sftp_server] host\n"
2257
	    "       %s [user@]host[:file ...]\n"
2258
	    "       %s [user@]host[:dir[/]]\n"
2259
	    "       %s -b batchfile [user@]host\n",
2260
	    __progname, __progname, __progname, __progname);
2261
	exit(1);
2262
}
2263
2264
int
2265
main(int argc, char **argv)
2266
{
2267
	int in, out, ch, err;
2268
	char *host = NULL, *userhost, *cp, *file2 = NULL;
2269
	int debug_level = 0, sshver = 2;
2270
	char *file1 = NULL, *sftp_server = NULL;
2271
	char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2272
	const char *errstr;
2273
	LogLevel ll = SYSLOG_LEVEL_INFO;
2274
	arglist args;
2275
	extern int optind;
2276
	extern char *optarg;
2277
	struct sftp_conn *conn;
2278
	size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2279
	size_t num_requests = DEFAULT_NUM_REQUESTS;
2280
	long long limit_kbps = 0;
2281
2282
	ssh_malloc_init();	/* must be called before any mallocs */
2283
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2284
	sanitise_stdfd();
2285
	setlocale(LC_CTYPE, "");
2286
2287
	memset(&args, '\0', sizeof(args));
2288
	args.list = NULL;
2289
	addargs(&args, "%s", ssh_program);
2290
	addargs(&args, "-oForwardX11 no");
2291
	addargs(&args, "-oForwardAgent no");
2292
	addargs(&args, "-oPermitLocalCommand no");
2293
	addargs(&args, "-oClearAllForwardings yes");
2294
2295
	ll = SYSLOG_LEVEL_INFO;
2296
	infile = stdin;
2297
2298
	while ((ch = getopt(argc, argv,
2299
	    "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2300
		switch (ch) {
2301
		/* Passed through to ssh(1) */
2302
		case '4':
2303
		case '6':
2304
		case 'C':
2305
			addargs(&args, "-%c", ch);
2306
			break;
2307
		/* Passed through to ssh(1) with argument */
2308
		case 'F':
2309
		case 'c':
2310
		case 'i':
2311
		case 'o':
2312
			addargs(&args, "-%c", ch);
2313
			addargs(&args, "%s", optarg);
2314
			break;
2315
		case 'q':
2316
			ll = SYSLOG_LEVEL_ERROR;
2317
			quiet = 1;
2318
			showprogress = 0;
2319
			addargs(&args, "-%c", ch);
2320
			break;
2321
		case 'P':
2322
			addargs(&args, "-oPort %s", optarg);
2323
			break;
2324
		case 'v':
2325
			if (debug_level < 3) {
2326
				addargs(&args, "-v");
2327
				ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2328
			}
2329
			debug_level++;
2330
			break;
2331
		case '1':
2332
			sshver = 1;
2333
			if (sftp_server == NULL)
2334
				sftp_server = _PATH_SFTP_SERVER;
2335
			break;
2336
		case '2':
2337
			sshver = 2;
2338
			break;
2339
		case 'a':
2340
			global_aflag = 1;
2341
			break;
2342
		case 'B':
2343
			copy_buffer_len = strtol(optarg, &cp, 10);
2344
			if (copy_buffer_len == 0 || *cp != '\0')
2345
				fatal("Invalid buffer size \"%s\"", optarg);
2346
			break;
2347
		case 'b':
2348
			if (batchmode)
2349
				fatal("Batch file already specified.");
2350
2351
			/* Allow "-" as stdin */
2352
			if (strcmp(optarg, "-") != 0 &&
2353
			    (infile = fopen(optarg, "r")) == NULL)
2354
				fatal("%s (%s).", strerror(errno), optarg);
2355
			showprogress = 0;
2356
			quiet = batchmode = 1;
2357
			addargs(&args, "-obatchmode yes");
2358
			break;
2359
		case 'f':
2360
			global_fflag = 1;
2361
			break;
2362
		case 'p':
2363
			global_pflag = 1;
2364
			break;
2365
		case 'D':
2366
			sftp_direct = optarg;
2367
			break;
2368
		case 'l':
2369
			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2370
			    &errstr);
2371
			if (errstr != NULL)
2372
				usage();
2373
			limit_kbps *= 1024; /* kbps */
2374
			break;
2375
		case 'r':
2376
			global_rflag = 1;
2377
			break;
2378
		case 'R':
2379
			num_requests = strtol(optarg, &cp, 10);
2380
			if (num_requests == 0 || *cp != '\0')
2381
				fatal("Invalid number of requests \"%s\"",
2382
				    optarg);
2383
			break;
2384
		case 's':
2385
			sftp_server = optarg;
2386
			break;
2387
		case 'S':
2388
			ssh_program = optarg;
2389
			replacearg(&args, 0, "%s", ssh_program);
2390
			break;
2391
		case 'h':
2392
		default:
2393
			usage();
2394
		}
2395
	}
2396
2397
	if (!isatty(STDERR_FILENO))
2398
		showprogress = 0;
2399
2400
	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2401
2402
	if (sftp_direct == NULL) {
2403
		if (optind == argc || argc > (optind + 2))
2404
			usage();
2405
2406
		userhost = xstrdup(argv[optind]);
2407
		file2 = argv[optind+1];
2408
2409
		if ((host = strrchr(userhost, '@')) == NULL)
2410
			host = userhost;
2411
		else {
2412
			*host++ = '\0';
2413
			if (!userhost[0]) {
2414
				fprintf(stderr, "Missing username\n");
2415
				usage();
2416
			}
2417
			addargs(&args, "-l");
2418
			addargs(&args, "%s", userhost);
2419
		}
2420
2421
		if ((cp = colon(host)) != NULL) {
2422
			*cp++ = '\0';
2423
			file1 = cp;
2424
		}
2425
2426
		host = cleanhostname(host);
2427
		if (!*host) {
2428
			fprintf(stderr, "Missing hostname\n");
2429
			usage();
2430
		}
2431
2432
		addargs(&args, "-oProtocol %d", sshver);
2433
2434
		/* no subsystem if the server-spec contains a '/' */
2435
		if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2436
			addargs(&args, "-s");
2437
2438
		addargs(&args, "--");
2439
		addargs(&args, "%s", host);
2440
		addargs(&args, "%s", (sftp_server != NULL ?
2441
		    sftp_server : "sftp"));
2442
2443
		connect_to_server(ssh_program, args.list, &in, &out);
2444
	} else {
2445
		args.list = NULL;
2446
		addargs(&args, "sftp-server");
2447
2448
		connect_to_server(sftp_direct, args.list, &in, &out);
2449
	}
2450
	freeargs(&args);
2451
2452
	conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2453
	if (conn == NULL)
2454
		fatal("Couldn't initialise connection to server");
2455
2456
	if (!quiet) {
2457
		if (sftp_direct == NULL)
2458
			fprintf(stderr, "Connected to %s.\n", host);
2459
		else
2460
			fprintf(stderr, "Attached to %s.\n", sftp_direct);
2461
	}
2462
2463
	err = interactive_loop(conn, file1, file2);
2464
2465
	close(in);
2466
	close(out);
2467
	if (batchmode)
2468
		fclose(infile);
2469
2470
	while (waitpid(sshpid, NULL, 0) == -1)
2471
		if (errno != EINTR)
2472
			fatal("Couldn't wait for ssh process: %s",
2473
			    strerror(errno));
2474
2475
	exit(err == 0 ? 0 : 1);
2476
}