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

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