GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ftp/small.c Lines: 0 320 0.0 %
Date: 2016-12-06 Branches: 0 313 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: small.c,v 1.6 2016/05/25 15:36:01 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
freegetit:
293
	if (oldargv2 != globargv2)	/* free up after globulize() */
294
		free(globargv2);
295
	return (rval);
296
}
297
298
/* XXX - Signal race. */
299
/* ARGSUSED */
300
void
301
mabort(int signo)
302
{
303
	int save_errno = errno;
304
305
	alarmtimer(0);
306
	(void) write(fileno(ttyout), "\n\r", 2);
307
#ifndef SMALL
308
	if (mflag && fromatty) {
309
		/* XXX signal race, crazy unbelievable stdio misuse */
310
		if (confirm(mname, NULL)) {
311
			errno = save_errno;
312
			longjmp(jabort, 1);
313
		}
314
	}
315
#endif /* !SMALL */
316
	mflag = 0;
317
	errno = save_errno;
318
	longjmp(jabort, 1);
319
}
320
321
/*
322
 * Get multiple files.
323
 */
324
void
325
mget(int argc, char *argv[])
326
{
327
	extern int optind, optreset;
328
	sig_t oldintr;
329
	int ch, xargc = 2;
330
	char *cp, localcwd[PATH_MAX], *xargv[] = { argv[0], NULL, NULL };
331
	static int restartit = 0;
332
#ifndef SMALL
333
	extern char *optarg;
334
	const char *errstr;
335
	int i = 1;
336
	char type = 0, *dummyargv[] = { argv[0], ".", NULL };
337
	FILE *ftemp = NULL;
338
	static int depth = 0, max_depth = 0;
339
340
	optind = optreset = 1;
341
342
	if (depth)
343
		depth++;
344
345
	while ((ch = getopt(argc, argv, "cd:nr")) != -1) {
346
		switch(ch) {
347
		case 'c':
348
			restartit = 1;
349
			break;
350
		case 'd':
351
			max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
352
			if (errstr != NULL) {
353
				fprintf(ttyout, "bad depth value, %s: %s\n",
354
				    errstr, optarg);
355
				code = -1;
356
				return;
357
			}
358
			break;
359
		case 'n':
360
			restartit = -1;
361
			break;
362
		case 'r':
363
			depth = 1;
364
			break;
365
		default:
366
			goto usage;
367
		}
368
	}
369
370
	if (argc - optind < 1 && !another(&argc, &argv, "remote-files")) {
371
usage:
372
		fprintf(ttyout, "usage: %s [-cnr] [-d depth] remote-files\n",
373
		    argv[0]);
374
		code = -1;
375
		return;
376
	}
377
378
	argv[optind - 1] = argv[0];
379
	argc -= optind - 1;
380
	argv += optind - 1;
381
#endif /* !SMALL */
382
383
	mname = argv[0];
384
	mflag = 1;
385
	if (getcwd(localcwd, sizeof(localcwd)) == NULL)
386
		err(1, "can't get cwd");
387
388
	oldintr = signal(SIGINT, mabort);
389
	(void)setjmp(jabort);
390
	while ((cp =
391
#ifdef SMALL
392
	    remglob(argv, proxy, NULL)) != NULL
393
	    ) {
394
#else /* SMALL */
395
	    depth ? remglob2(dummyargv, proxy, NULL, &ftemp, &type) :
396
	    remglob(argv, proxy, NULL)) != NULL
397
	    || (mflag && depth && ++i < argc)
398
	    ) {
399
		if (cp == NULL)
400
			continue;
401
#endif /* SMALL */
402
		if (*cp == '\0') {
403
			mflag = 0;
404
			continue;
405
		}
406
		if (!mflag)
407
			continue;
408
#ifndef SMALL
409
		if (depth && fnmatch(argv[i], cp, FNM_PATHNAME) != 0)
410
			continue;
411
#endif /* !SMALL */
412
		if (!fileindir(cp, localcwd)) {
413
			fprintf(ttyout, "Skipping non-relative filename `%s'\n",
414
			    cp);
415
			continue;
416
		}
417
#ifndef SMALL
418
		if (type == 'd' && depth == max_depth)
419
			continue;
420
		if (!confirm(argv[0], cp))
421
			continue;
422
		if (type == 'd') {
423
			mkdir(cp, 0755);
424
			if (chdir(cp) != 0) {
425
				warn("local: %s", cp);
426
				continue;
427
			}
428
429
			xargv[1] = cp;
430
			cd(xargc, xargv);
431
			if (dirchange != 1)
432
				goto out;
433
434
			xargv[1] = "*";
435
			mget(xargc, xargv);
436
437
			xargv[1] = "..";
438
			cd(xargc, xargv);
439
			if (dirchange != 1) {
440
				mflag = 0;
441
				goto out;
442
			}
443
444
out:
445
			if (chdir("..") != 0) {
446
				warn("local: %s", cp);
447
				mflag = 0;
448
			}
449
			continue;
450
		}
451
		if (type == 's')
452
			/* Currently ignored. */
453
			continue;
454
#endif /* !SMALL */
455
		xargv[1] = cp;
456
		(void)getit(xargc, xargv, restartit,
457
		    (restartit == 1 || restart_point) ? "a+w" : "w");
458
#ifndef SMALL
459
		if (!mflag && fromatty) {
460
			if (confirm(argv[0], NULL))
461
				mflag = 1;
462
		}
463
#endif /* !SMALL */
464
	}
465
	(void)signal(SIGINT, oldintr);
466
#ifndef SMALL
467
	if (depth)
468
		depth--;
469
	if (depth == 0 || mflag == 0)
470
		depth = max_depth = mflag = restartit = 0;
471
#else /* !SMALL */
472
	mflag = 0;
473
#endif /* !SMALL */
474
}
475
476
/*
477
 * Set current working directory on remote machine.
478
 */
479
void
480
cd(int argc, char *argv[])
481
{
482
	int r;
483
484
#ifndef SMALL
485
	if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
486
	    argc > 2) {
487
		fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
488
		code = -1;
489
		return;
490
	}
491
#endif /* !SMALL */
492
	r = command("CWD %s", argv[1]);
493
	if (r == ERROR && code == 500) {
494
		if (verbose)
495
			fputs("CWD command not recognized, trying XCWD.\n", ttyout);
496
		r = command("XCWD %s", argv[1]);
497
	}
498
	if (r == ERROR && code == 550) {
499
		dirchange = 0;
500
		return;
501
	}
502
	if (r == COMPLETE)
503
		dirchange = 1;
504
}
505
506
/*
507
 * Terminate session, but don't exit.
508
 */
509
/* ARGSUSED */
510
void
511
disconnect(int argc, char *argv[])
512
{
513
514
	if (!connected)
515
		return;
516
	(void)command("QUIT");
517
	if (cout) {
518
		(void)fclose(cout);
519
	}
520
	cout = NULL;
521
	connected = 0;
522
	data = -1;
523
#ifndef SMALL
524
	if (!proxy) {
525
		macnum = 0;
526
	}
527
#endif /* !SMALL */
528
}
529
530
char *
531
dotrans(char *name)
532
{
533
	static char new[PATH_MAX];
534
	char *cp1, *cp2 = new;
535
	int i, ostop, found;
536
537
	for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
538
		continue;
539
	for (cp1 = name; *cp1; cp1++) {
540
		found = 0;
541
		for (i = 0; *(ntin + i) && i < 16; i++) {
542
			if (*cp1 == *(ntin + i)) {
543
				found++;
544
				if (i < ostop) {
545
					*cp2++ = *(ntout + i);
546
				}
547
				break;
548
			}
549
		}
550
		if (!found) {
551
			*cp2++ = *cp1;
552
		}
553
	}
554
	*cp2 = '\0';
555
	return (new);
556
}
557
558
char *
559
domap(char *name)
560
{
561
	static char new[PATH_MAX];
562
	char *cp1 = name, *cp2 = mapin;
563
	char *tp[9], *te[9];
564
	int i, toks[9], toknum = 0, match = 1;
565
566
	for (i=0; i < 9; ++i) {
567
		toks[i] = 0;
568
	}
569
	while (match && *cp1 && *cp2) {
570
		switch (*cp2) {
571
			case '\\':
572
				if (*++cp2 != *cp1) {
573
					match = 0;
574
				}
575
				break;
576
			case '$':
577
				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
578
					if (*cp1 != *(++cp2+1)) {
579
						toks[toknum = *cp2 - '1']++;
580
						tp[toknum] = cp1;
581
						while (*++cp1 && *(cp2+1)
582
							!= *cp1);
583
						te[toknum] = cp1;
584
					}
585
					cp2++;
586
					break;
587
				}
588
				/* FALLTHROUGH */
589
			default:
590
				if (*cp2 != *cp1) {
591
					match = 0;
592
				}
593
				break;
594
		}
595
		if (match && *cp1) {
596
			cp1++;
597
		}
598
		if (match && *cp2) {
599
			cp2++;
600
		}
601
	}
602
	if (!match && *cp1) /* last token mismatch */
603
	{
604
		toks[toknum] = 0;
605
	}
606
	cp1 = new;
607
	*cp1 = '\0';
608
	cp2 = mapout;
609
	while (*cp2) {
610
		match = 0;
611
		switch (*cp2) {
612
			case '\\':
613
				if (*(cp2 + 1)) {
614
					*cp1++ = *++cp2;
615
				}
616
				break;
617
			case '[':
618
LOOP:
619
				if (*++cp2 == '$' && isdigit((unsigned char)*(cp2 + 1))) {
620
					if (*++cp2 == '0') {
621
						char *cp3 = name;
622
623
						while (*cp3) {
624
							*cp1++ = *cp3++;
625
						}
626
						match = 1;
627
					}
628
					else if (toks[toknum = *cp2 - '1']) {
629
						char *cp3 = tp[toknum];
630
631
						while (cp3 != te[toknum]) {
632
							*cp1++ = *cp3++;
633
						}
634
						match = 1;
635
					}
636
				}
637
				else {
638
					while (*cp2 && *cp2 != ',' &&
639
					    *cp2 != ']') {
640
						if (*cp2 == '\\') {
641
							cp2++;
642
						}
643
						else if (*cp2 == '$' &&
644
   						        isdigit((unsigned char)*(cp2 + 1))) {
645
							if (*++cp2 == '0') {
646
							   char *cp3 = name;
647
648
							   while (*cp3) {
649
								*cp1++ = *cp3++;
650
							   }
651
							}
652
							else if (toks[toknum =
653
							    *cp2 - '1']) {
654
							   char *cp3=tp[toknum];
655
656
							   while (cp3 !=
657
								  te[toknum]) {
658
								*cp1++ = *cp3++;
659
							   }
660
							}
661
						}
662
						else if (*cp2) {
663
							*cp1++ = *cp2++;
664
						}
665
					}
666
					if (!*cp2) {
667
						fputs(
668
"nmap: unbalanced brackets.\n", ttyout);
669
						return (name);
670
					}
671
					match = 1;
672
					cp2--;
673
				}
674
				if (match) {
675
					while (*++cp2 && *cp2 != ']') {
676
					      if (*cp2 == '\\' && *(cp2 + 1)) {
677
							cp2++;
678
					      }
679
					}
680
					if (!*cp2) {
681
						fputs(
682
"nmap: unbalanced brackets.\n", ttyout);
683
						return (name);
684
					}
685
					break;
686
				}
687
				switch (*++cp2) {
688
					case ',':
689
						goto LOOP;
690
					case ']':
691
						break;
692
					default:
693
						cp2--;
694
						goto LOOP;
695
				}
696
				break;
697
			case '$':
698
				if (isdigit((unsigned char)*(cp2 + 1))) {
699
					if (*++cp2 == '0') {
700
						char *cp3 = name;
701
702
						while (*cp3) {
703
							*cp1++ = *cp3++;
704
						}
705
					}
706
					else if (toks[toknum = *cp2 - '1']) {
707
						char *cp3 = tp[toknum];
708
709
						while (cp3 != te[toknum]) {
710
							*cp1++ = *cp3++;
711
						}
712
					}
713
					break;
714
				}
715
				/* FALLTHROUGH */
716
			default:
717
				*cp1++ = *cp2;
718
				break;
719
		}
720
		cp2++;
721
	}
722
	*cp1 = '\0';
723
	if (!*new) {
724
		return (name);
725
	}
726
	return (new);
727
}
728