GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ftp/small.c Lines: 0 302 0.0 %
Date: 2017-11-07 Branches: 0 292 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: small.c,v 1.9 2017/01/21 08:33:07 krw Exp $	*/
2
/*	$NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $	*/
3
4
/*
5
 * Copyright (C) 1997 and 1998 WIDE Project.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the project nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * Copyright (c) 1985, 1989, 1993, 1994
35
 *	The Regents of the University of California.  All rights reserved.
36
 *
37
 * Redistribution and use in source and binary forms, with or without
38
 * modification, are permitted provided that the following conditions
39
 * are met:
40
 * 1. Redistributions of source code must retain the above copyright
41
 *    notice, this list of conditions and the following disclaimer.
42
 * 2. Redistributions in binary form must reproduce the above copyright
43
 *    notice, this list of conditions and the following disclaimer in the
44
 *    documentation and/or other materials provided with the distribution.
45
 * 3. Neither the name of the University nor the names of its contributors
46
 *    may be used to endorse or promote products derived from this software
47
 *    without specific prior written permission.
48
 *
49
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59
 * SUCH DAMAGE.
60
 */
61
62
/*
63
 * FTP User Program -- Command Routines.
64
 */
65
#include <sys/types.h>
66
#include <sys/socket.h>
67
#include <sys/stat.h>
68
#include <sys/wait.h>
69
#include <arpa/ftp.h>
70
71
#include <ctype.h>
72
#include <err.h>
73
#include <fnmatch.h>
74
#include <glob.h>
75
#include <netdb.h>
76
#include <stdio.h>
77
#include <stdlib.h>
78
#include <string.h>
79
#include <unistd.h>
80
#include <errno.h>
81
82
#include "ftp_var.h"
83
#include "pathnames.h"
84
#include "small.h"
85
86
jmp_buf	jabort;
87
char   *mname;
88
char   *home = "/";
89
90
struct	types {
91
	char	*t_name;
92
	char	*t_mode;
93
	int	t_type;
94
} types[] = {
95
	{ "ascii",	"A",	TYPE_A },
96
	{ "binary",	"I",	TYPE_I },
97
	{ "image",	"I",	TYPE_I },
98
	{ NULL }
99
};
100
101
/*
102
 * Set transfer type.
103
 */
104
void
105
settype(int argc, char *argv[])
106
{
107
	struct types *p;
108
	int comret;
109
110
	if (argc > 2) {
111
		char *sep;
112
113
		fprintf(ttyout, "usage: %s [", argv[0]);
114
		sep = "";
115
		for (p = types; p->t_name; p++) {
116
			fprintf(ttyout, "%s%s", sep, p->t_name);
117
			sep = " | ";
118
		}
119
		fputs("]\n", ttyout);
120
		code = -1;
121
		return;
122
	}
123
	if (argc < 2) {
124
		fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
125
		code = 0;
126
		return;
127
	}
128
	for (p = types; p->t_name; p++)
129
		if (strcmp(argv[1], p->t_name) == 0)
130
			break;
131
	if (p->t_name == 0) {
132
		fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
133
		code = -1;
134
		return;
135
	}
136
	comret = command("TYPE %s", p->t_mode);
137
	if (comret == COMPLETE) {
138
		(void)strlcpy(typename, p->t_name, sizeof typename);
139
		curtype = type = p->t_type;
140
	}
141
}
142
143
/*
144
 * Internal form of settype; changes current type in use with server
145
 * without changing our notion of the type for data transfers.
146
 * Used to change to and from ascii for listings.
147
 */
148
void
149
changetype(int newtype, int show)
150
{
151
	struct types *p;
152
	int comret, oldverbose = verbose;
153
154
	if (newtype == 0)
155
		newtype = TYPE_I;
156
	if (newtype == curtype)
157
		return;
158
	if (
159
#ifndef SMALL
160
	    !debug &&
161
#endif /* !SMALL */
162
	    show == 0)
163
		verbose = 0;
164
	for (p = types; p->t_name; p++)
165
		if (newtype == p->t_type)
166
			break;
167
	if (p->t_name == 0) {
168
		warnx("internal error: unknown type %d.", newtype);
169
		return;
170
	}
171
	if (newtype == TYPE_L && bytename[0] != '\0')
172
		comret = command("TYPE %s %s", p->t_mode, bytename);
173
	else
174
		comret = command("TYPE %s", p->t_mode);
175
	if (comret == COMPLETE)
176
		curtype = newtype;
177
	verbose = oldverbose;
178
}
179
180
char *stype[] = {
181
	"type",
182
	"",
183
	0
184
};
185
186
/*
187
 * Set binary transfer type.
188
 */
189
/*ARGSUSED*/
190
void
191
setbinary(int argc, char *argv[])
192
{
193
194
	stype[1] = "binary";
195
	settype(2, stype);
196
}
197
198
void
199
get(int argc, char *argv[])
200
{
201
202
	(void)getit(argc, argv, 0, restart_point ? "a+w" : "w" );
203
}
204
205
/*
206
 * Receive one file.
207
 */
208
int
209
getit(int argc, char *argv[], int restartit, const char *mode)
210
{
211
	int loc = 0;
212
	int rval = 0;
213
	char *oldargv1, *oldargv2, *globargv2;
214
215
	if (argc == 2) {
216
		argc++;
217
		argv[2] = argv[1];
218
		loc++;
219
	}
220
#ifndef SMALL
221
	if (argc < 2 && !another(&argc, &argv, "remote-file"))
222
		goto usage;
223
	if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
224
usage:
225
		fprintf(ttyout, "usage: %s remote-file [local-file]\n",
226
		    argv[0]);
227
		code = -1;
228
		return (0);
229
	}
230
#endif /* !SMALL */
231
	oldargv1 = argv[1];
232
	oldargv2 = argv[2];
233
	if (!globulize(&argv[2])) {
234
		code = -1;
235
		return (0);
236
	}
237
	globargv2 = argv[2];
238
	if (loc && mcase) {
239
		char *tp = argv[1], *tp2, tmpbuf[PATH_MAX];
240
241
		while (*tp && !islower((unsigned char)*tp)) {
242
			tp++;
243
		}
244
		if (!*tp) {
245
			tp = argv[2];
246
			tp2 = tmpbuf;
247
			while ((*tp2 = *tp) != '\0') {
248
				if (isupper((unsigned char)*tp2)) {
249
					*tp2 = tolower((unsigned char)*tp2);
250
				}
251
				tp++;
252
				tp2++;
253
			}
254
			argv[2] = tmpbuf;
255
		}
256
	}
257
	if (loc && ntflag)
258
		argv[2] = dotrans(argv[2]);
259
	if (loc && mapflag)
260
		argv[2] = domap(argv[2]);
261
#ifndef SMALL
262
	if (restartit) {
263
		struct stat stbuf;
264
		int ret;
265
266
		ret = stat(argv[2], &stbuf);
267
		if (restartit == 1) {
268
			restart_point = (ret < 0) ? 0 : stbuf.st_size;
269
		} else {
270
			if (ret == 0) {
271
				time_t mtime;
272
273
				mtime = remotemodtime(argv[1], 0);
274
				if (mtime == -1)
275
					goto freegetit;
276
				if (stbuf.st_mtime >= mtime) {
277
					rval = 1;
278
					fprintf(ttyout,
279
						"Local file \"%s\" is newer "\
280
						"than remote file \"%s\".\n",
281
						argv[2], argv[1]);
282
					goto freegetit;
283
				}
284
			}
285
		}
286
	}
287
#endif /* !SMALL */
288
289
	recvrequest("RETR", argv[2], argv[1], mode,
290
	    argv[1] != oldargv1 || argv[2] != oldargv2 || !interactive, loc);
291
	restart_point = 0;
292
#ifndef SMALL
293
freegetit:
294
#endif
295
	if (oldargv2 != globargv2)	/* free up after globulize() */
296
		free(globargv2);
297
	return (rval);
298
}
299
300
/* XXX - Signal race. */
301
/* ARGSUSED */
302
void
303
mabort(int signo)
304
{
305
	int save_errno = errno;
306
307
	alarmtimer(0);
308
	(void) write(fileno(ttyout), "\n\r", 2);
309
#ifndef SMALL
310
	if (mflag && fromatty) {
311
		/* XXX signal race, crazy unbelievable stdio misuse */
312
		if (confirm(mname, NULL)) {
313
			errno = save_errno;
314
			longjmp(jabort, 1);
315
		}
316
	}
317
#endif /* !SMALL */
318
	mflag = 0;
319
	errno = save_errno;
320
	longjmp(jabort, 1);
321
}
322
323
/*
324
 * Get multiple files.
325
 */
326
void
327
mget(int argc, char *argv[])
328
{
329
	extern int optind, optreset;
330
	sig_t oldintr;
331
	int xargc = 2;
332
	char *cp, localcwd[PATH_MAX], *xargv[] = { argv[0], NULL, NULL };
333
	static int restartit = 0;
334
#ifndef SMALL
335
	extern char *optarg;
336
	const char *errstr;
337
	int ch, i = 1;
338
	char type = 0, *dummyargv[] = { argv[0], ".", NULL };
339
	FILE *ftemp = NULL;
340
	static int depth = 0, max_depth = 0;
341
342
	optind = optreset = 1;
343
344
	if (depth)
345
		depth++;
346
347
	while ((ch = getopt(argc, argv, "cd:nr")) != -1) {
348
		switch(ch) {
349
		case 'c':
350
			restartit = 1;
351
			break;
352
		case 'd':
353
			max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
354
			if (errstr != NULL) {
355
				fprintf(ttyout, "bad depth value, %s: %s\n",
356
				    errstr, optarg);
357
				code = -1;
358
				return;
359
			}
360
			break;
361
		case 'n':
362
			restartit = -1;
363
			break;
364
		case 'r':
365
			depth = 1;
366
			break;
367
		default:
368
			goto usage;
369
		}
370
	}
371
372
	if (argc - optind < 1 && !another(&argc, &argv, "remote-files")) {
373
usage:
374
		fprintf(ttyout, "usage: %s [-cnr] [-d depth] remote-files\n",
375
		    argv[0]);
376
		code = -1;
377
		return;
378
	}
379
380
	argv[optind - 1] = argv[0];
381
	argc -= optind - 1;
382
	argv += optind - 1;
383
#endif /* !SMALL */
384
385
	mname = argv[0];
386
	mflag = 1;
387
	if (getcwd(localcwd, sizeof(localcwd)) == NULL)
388
		err(1, "can't get cwd");
389
390
	oldintr = signal(SIGINT, mabort);
391
	(void)setjmp(jabort);
392
	while ((cp =
393
#ifdef SMALL
394
	    remglob(argv, proxy, NULL)) != NULL
395
	    ) {
396
#else /* SMALL */
397
	    depth ? remglob2(dummyargv, proxy, NULL, &ftemp, &type) :
398
	    remglob(argv, proxy, NULL)) != NULL
399
	    || (mflag && depth && ++i < argc)
400
	    ) {
401
		if (cp == NULL)
402
			continue;
403
#endif /* SMALL */
404
		if (*cp == '\0') {
405
			mflag = 0;
406
			continue;
407
		}
408
		if (!mflag)
409
			continue;
410
#ifndef SMALL
411
		if (depth && fnmatch(argv[i], cp, FNM_PATHNAME) != 0)
412
			continue;
413
#endif /* !SMALL */
414
		if (!fileindir(cp, localcwd)) {
415
			fprintf(ttyout, "Skipping non-relative filename `%s'\n",
416
			    cp);
417
			continue;
418
		}
419
#ifndef SMALL
420
		if (type == 'd' && depth == max_depth)
421
			continue;
422
		if (!confirm(argv[0], cp))
423
			continue;
424
		if (type == 'd') {
425
			mkdir(cp, 0755);
426
			if (chdir(cp) != 0) {
427
				warn("local: %s", cp);
428
				continue;
429
			}
430
431
			xargv[1] = cp;
432
			cd(xargc, xargv);
433
			if (dirchange != 1)
434
				goto out;
435
436
			xargv[1] = "*";
437
			mget(xargc, xargv);
438
439
			xargv[1] = "..";
440
			cd(xargc, xargv);
441
			if (dirchange != 1) {
442
				mflag = 0;
443
				goto out;
444
			}
445
446
out:
447
			if (chdir("..") != 0) {
448
				warn("local: %s", cp);
449
				mflag = 0;
450
			}
451
			continue;
452
		}
453
		if (type == 's')
454
			/* Currently ignored. */
455
			continue;
456
#endif /* !SMALL */
457
		xargv[1] = cp;
458
		(void)getit(xargc, xargv, restartit,
459
		    (restartit == 1 || restart_point) ? "a+w" : "w");
460
#ifndef SMALL
461
		if (!mflag && fromatty) {
462
			if (confirm(argv[0], NULL))
463
				mflag = 1;
464
		}
465
#endif /* !SMALL */
466
	}
467
	(void)signal(SIGINT, oldintr);
468
#ifndef SMALL
469
	if (depth)
470
		depth--;
471
	if (depth == 0 || mflag == 0)
472
		depth = max_depth = mflag = restartit = 0;
473
#else /* !SMALL */
474
	mflag = 0;
475
#endif /* !SMALL */
476
}
477
478
/*
479
 * Set current working directory on remote machine.
480
 */
481
void
482
cd(int argc, char *argv[])
483
{
484
	int r;
485
486
#ifndef SMALL
487
	if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
488
	    argc > 2) {
489
		fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
490
		code = -1;
491
		return;
492
	}
493
#endif /* !SMALL */
494
	r = command("CWD %s", argv[1]);
495
	if (r == ERROR && code == 500) {
496
		if (verbose)
497
			fputs("CWD command not recognized, trying XCWD.\n", ttyout);
498
		r = command("XCWD %s", argv[1]);
499
	}
500
	if (r == ERROR && code == 550) {
501
		dirchange = 0;
502
		return;
503
	}
504
	if (r == COMPLETE)
505
		dirchange = 1;
506
}
507
508
/*
509
 * Terminate session, but don't exit.
510
 */
511
/* ARGSUSED */
512
void
513
disconnect(int argc, char *argv[])
514
{
515
516
	if (!connected)
517
		return;
518
	(void)command("QUIT");
519
	if (cout) {
520
		(void)fclose(cout);
521
	}
522
	cout = NULL;
523
	connected = 0;
524
	data = -1;
525
#ifndef SMALL
526
	if (!proxy) {
527
		macnum = 0;
528
	}
529
#endif /* !SMALL */
530
}
531
532
char *
533
dotrans(char *name)
534
{
535
	static char new[PATH_MAX];
536
	char *cp1, *cp2 = new;
537
	int i, ostop, found;
538
539
	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
540
		continue;
541
	for (cp1 = name; *cp1; cp1++) {
542
		found = 0;
543
		for (i = 0; *(ntin + i) && i < 16; i++) {
544
			if (*cp1 == *(ntin + i)) {
545
				found++;
546
				if (i < ostop) {
547
					*cp2++ = *(ntout + i);
548
				}
549
				break;
550
			}
551
		}
552
		if (!found) {
553
			*cp2++ = *cp1;
554
		}
555
	}
556
	*cp2 = '\0';
557
	return (new);
558
}
559
560
char *
561
domap(char *name)
562
{
563
	static char new[PATH_MAX];
564
	char *cp1 = name, *cp2 = mapin;
565
	char *tp[9], *te[9];
566
	int i, toks[9], toknum = 0, match = 1;
567
568
	for (i=0; i < 9; ++i) {
569
		toks[i] = 0;
570
	}
571
	while (match && *cp1 && *cp2) {
572
		switch (*cp2) {
573
			case '\\':
574
				if (*++cp2 != *cp1) {
575
					match = 0;
576
				}
577
				break;
578
			case '$':
579
				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
580
					if (*cp1 != *(++cp2+1)) {
581
						toks[toknum = *cp2 - '1']++;
582
						tp[toknum] = cp1;
583
						while (*++cp1 && *(cp2+1)
584
							!= *cp1);
585
						te[toknum] = cp1;
586
					}
587
					cp2++;
588
					break;
589
				}
590
				/* FALLTHROUGH */
591
			default:
592
				if (*cp2 != *cp1) {
593
					match = 0;
594
				}
595
				break;
596
		}
597
		if (match && *cp1) {
598
			cp1++;
599
		}
600
		if (match && *cp2) {
601
			cp2++;
602
		}
603
	}
604
	if (!match && *cp1) /* last token mismatch */
605
	{
606
		toks[toknum] = 0;
607
	}
608
	cp1 = new;
609
	*cp1 = '\0';
610
	cp2 = mapout;
611
	while (*cp2) {
612
		match = 0;
613
		switch (*cp2) {
614
			case '\\':
615
				if (*(cp2 + 1)) {
616
					*cp1++ = *++cp2;
617
				}
618
				break;
619
			case '[':
620
LOOP:
621
				if (*++cp2 == '$' && isdigit((unsigned char)*(cp2 + 1))) {
622
					if (*++cp2 == '0') {
623
						char *cp3 = name;
624
625
						while (*cp3) {
626
							*cp1++ = *cp3++;
627
						}
628
						match = 1;
629
					}
630
					else if (toks[toknum = *cp2 - '1']) {
631
						char *cp3 = tp[toknum];
632
633
						while (cp3 != te[toknum]) {
634
							*cp1++ = *cp3++;
635
						}
636
						match = 1;
637
					}
638
				}
639
				else {
640
					while (*cp2 && *cp2 != ',' &&
641
					    *cp2 != ']') {
642
						if (*cp2 == '\\') {
643
							cp2++;
644
						}
645
						else if (*cp2 == '$' &&
646
						        isdigit((unsigned char)*(cp2 + 1))) {
647
							if (*++cp2 == '0') {
648
							   char *cp3 = name;
649
650
							   while (*cp3) {
651
								*cp1++ = *cp3++;
652
							   }
653
							}
654
							else if (toks[toknum =
655
							    *cp2 - '1']) {
656
							   char *cp3=tp[toknum];
657
658
							   while (cp3 !=
659
								  te[toknum]) {
660
								*cp1++ = *cp3++;
661
							   }
662
							}
663
						}
664
						else if (*cp2) {
665
							*cp1++ = *cp2++;
666
						}
667
					}
668
					if (!*cp2) {
669
						fputs(
670
"nmap: unbalanced brackets.\n", ttyout);
671
						return (name);
672
					}
673
					match = 1;
674
					cp2--;
675
				}
676
				if (match) {
677
					while (*++cp2 && *cp2 != ']') {
678
					      if (*cp2 == '\\' && *(cp2 + 1)) {
679
							cp2++;
680
					      }
681
					}
682
					if (!*cp2) {
683
						fputs(
684
"nmap: unbalanced brackets.\n", ttyout);
685
						return (name);
686
					}
687
					break;
688
				}
689
				switch (*++cp2) {
690
					case ',':
691
						goto LOOP;
692
					case ']':
693
						break;
694
					default:
695
						cp2--;
696
						goto LOOP;
697
				}
698
				break;
699
			case '$':
700
				if (isdigit((unsigned char)*(cp2 + 1))) {
701
					if (*++cp2 == '0') {
702
						char *cp3 = name;
703
704
						while (*cp3) {
705
							*cp1++ = *cp3++;
706
						}
707
					}
708
					else if (toks[toknum = *cp2 - '1']) {
709
						char *cp3 = tp[toknum];
710
711
						while (cp3 != te[toknum]) {
712
							*cp1++ = *cp3++;
713
						}
714
					}
715
					break;
716
				}
717
				/* FALLTHROUGH */
718
			default:
719
				*cp1++ = *cp2;
720
				break;
721
		}
722
		cp2++;
723
	}
724
	*cp1 = '\0';
725
	if (!*new) {
726
		return (name);
727
	}
728
	return (new);
729
}
730