GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/scp/../scp.c Lines: 96 730 13.2 %
Date: 2017-11-13 Branches: 45 500 9.0 %

Line Branch Exec Source
1
/* $OpenBSD: scp.c,v 1.193 2017/10/21 23:06:24 millert Exp $ */
2
/*
3
 * scp - secure remote copy.  This is basically patched BSD rcp which
4
 * uses ssh to do the data transfer (instead of using rcmd).
5
 *
6
 * NOTE: This version should NOT be suid root.  (This uses ssh to
7
 * do the transfer and ssh has the necessary privileges.)
8
 *
9
 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
10
 *
11
 * As far as I am concerned, the code I have written for this software
12
 * can be used freely for any purpose.  Any derived versions of this
13
 * software must be clearly marked as such, and if the derived work is
14
 * incompatible with the protocol description in the RFC file, it must be
15
 * called by a name other than "ssh" or "Secure Shell".
16
 */
17
/*
18
 * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
19
 * Copyright (c) 1999 Aaron Campbell.  All rights reserved.
20
 *
21
 * Redistribution and use in source and binary forms, with or without
22
 * modification, are permitted provided that the following conditions
23
 * are met:
24
 * 1. Redistributions of source code must retain the above copyright
25
 *    notice, this list of conditions and the following disclaimer.
26
 * 2. Redistributions in binary form must reproduce the above copyright
27
 *    notice, this list of conditions and the following disclaimer in the
28
 *    documentation and/or other materials provided with the distribution.
29
 *
30
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
31
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
33
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
34
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
 */
41
42
/*
43
 * Parts from:
44
 *
45
 * Copyright (c) 1983, 1990, 1992, 1993, 1995
46
 *	The Regents of the University of California.  All rights reserved.
47
 *
48
 * Redistribution and use in source and binary forms, with or without
49
 * modification, are permitted provided that the following conditions
50
 * are met:
51
 * 1. Redistributions of source code must retain the above copyright
52
 *    notice, this list of conditions and the following disclaimer.
53
 * 2. Redistributions in binary form must reproduce the above copyright
54
 *    notice, this list of conditions and the following disclaimer in the
55
 *    documentation and/or other materials provided with the distribution.
56
 * 3. Neither the name of the University nor the names of its contributors
57
 *    may be used to endorse or promote products derived from this software
58
 *    without specific prior written permission.
59
 *
60
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70
 * SUCH DAMAGE.
71
 *
72
 */
73
74
#include <sys/types.h>
75
#include <sys/poll.h>
76
#include <sys/wait.h>
77
#include <sys/stat.h>
78
#include <sys/time.h>
79
#include <sys/uio.h>
80
81
#include <ctype.h>
82
#include <dirent.h>
83
#include <errno.h>
84
#include <fcntl.h>
85
#include <locale.h>
86
#include <pwd.h>
87
#include <signal.h>
88
#include <stdarg.h>
89
#include <stdint.h>
90
#include <stdio.h>
91
#include <stdlib.h>
92
#include <string.h>
93
#include <time.h>
94
#include <unistd.h>
95
#include <limits.h>
96
#include <vis.h>
97
98
#include "xmalloc.h"
99
#include "ssh.h"
100
#include "atomicio.h"
101
#include "pathnames.h"
102
#include "log.h"
103
#include "misc.h"
104
#include "progressmeter.h"
105
#include "utf8.h"
106
107
#define COPY_BUFLEN	16384
108
109
int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout);
110
int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout);
111
112
/* Struct for addargs */
113
arglist args;
114
arglist remote_remote_args;
115
116
/* Bandwidth limit */
117
long long limit_kbps = 0;
118
struct bwlimit bwlimit;
119
120
/* Name of current file being transferred. */
121
char *curfile;
122
123
/* This is set to non-zero to enable verbose mode. */
124
int verbose_mode = 0;
125
126
/* This is set to zero if the progressmeter is not desired. */
127
int showprogress = 1;
128
129
/*
130
 * This is set to non-zero if remote-remote copy should be piped
131
 * through this process.
132
 */
133
int throughlocal = 0;
134
135
/* Non-standard port to use for the ssh connection or -1. */
136
int sshport = -1;
137
138
/* This is the program to execute for the secured connection. ("ssh" or -S) */
139
char *ssh_program = _PATH_SSH_PROGRAM;
140
141
/* This is used to store the pid of ssh_program */
142
pid_t do_cmd_pid = -1;
143
144
static void
145
killchild(int signo)
146
{
147
	if (do_cmd_pid > 1) {
148
		kill(do_cmd_pid, signo ? signo : SIGTERM);
149
		waitpid(do_cmd_pid, NULL, 0);
150
	}
151
152
	if (signo)
153
		_exit(1);
154
	exit(1);
155
}
156
157
static void
158
suspchild(int signo)
159
{
160
	int status;
161
162
	if (do_cmd_pid > 1) {
163
		kill(do_cmd_pid, signo);
164
		while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 &&
165
		    errno == EINTR)
166
			;
167
		kill(getpid(), SIGSTOP);
168
	}
169
}
170
171
static int
172
do_local_cmd(arglist *a)
173
{
174
	u_int i;
175
	int status;
176
	pid_t pid;
177
178
	if (a->num == 0)
179
		fatal("do_local_cmd: no arguments");
180
181
	if (verbose_mode) {
182
		fprintf(stderr, "Executing:");
183
		for (i = 0; i < a->num; i++)
184
			fmprintf(stderr, " %s", a->list[i]);
185
		fprintf(stderr, "\n");
186
	}
187
	if ((pid = fork()) == -1)
188
		fatal("do_local_cmd: fork: %s", strerror(errno));
189
190
	if (pid == 0) {
191
		execvp(a->list[0], a->list);
192
		perror(a->list[0]);
193
		exit(1);
194
	}
195
196
	do_cmd_pid = pid;
197
	signal(SIGTERM, killchild);
198
	signal(SIGINT, killchild);
199
	signal(SIGHUP, killchild);
200
201
	while (waitpid(pid, &status, 0) == -1)
202
		if (errno != EINTR)
203
			fatal("do_local_cmd: waitpid: %s", strerror(errno));
204
205
	do_cmd_pid = -1;
206
207
	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
208
		return (-1);
209
210
	return (0);
211
}
212
213
/*
214
 * This function executes the given command as the specified user on the
215
 * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
216
 * assigns the input and output file descriptors on success.
217
 */
218
219
int
220
do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
221
{
222
	int pin[2], pout[2], reserved[2];
223
224
	if (verbose_mode)
225
		fmprintf(stderr,
226
		    "Executing: program %s host %s, user %s, command %s\n",
227
		    ssh_program, host,
228
		    remuser ? remuser : "(unspecified)", cmd);
229
230
	if (port == -1)
231
		port = sshport;
232
233
	/*
234
	 * Reserve two descriptors so that the real pipes won't get
235
	 * descriptors 0 and 1 because that will screw up dup2 below.
236
	 */
237
	if (pipe(reserved) < 0)
238
		fatal("pipe: %s", strerror(errno));
239
240
	/* Create a socket pair for communicating with ssh. */
241
	if (pipe(pin) < 0)
242
		fatal("pipe: %s", strerror(errno));
243
	if (pipe(pout) < 0)
244
		fatal("pipe: %s", strerror(errno));
245
246
	/* Free the reserved descriptors. */
247
	close(reserved[0]);
248
	close(reserved[1]);
249
250
	signal(SIGTSTP, suspchild);
251
	signal(SIGTTIN, suspchild);
252
	signal(SIGTTOU, suspchild);
253
254
	/* Fork a child to execute the command on the remote host using ssh. */
255
	do_cmd_pid = fork();
256
	if (do_cmd_pid == 0) {
257
		/* Child. */
258
		close(pin[1]);
259
		close(pout[0]);
260
		dup2(pin[0], 0);
261
		dup2(pout[1], 1);
262
		close(pin[0]);
263
		close(pout[1]);
264
265
		replacearg(&args, 0, "%s", ssh_program);
266
		if (port != -1) {
267
			addargs(&args, "-p");
268
			addargs(&args, "%d", port);
269
		}
270
		if (remuser != NULL) {
271
			addargs(&args, "-l");
272
			addargs(&args, "%s", remuser);
273
		}
274
		addargs(&args, "--");
275
		addargs(&args, "%s", host);
276
		addargs(&args, "%s", cmd);
277
278
		execvp(ssh_program, args.list);
279
		perror(ssh_program);
280
		exit(1);
281
	} else if (do_cmd_pid == -1) {
282
		fatal("fork: %s", strerror(errno));
283
	}
284
	/* Parent.  Close the other side, and return the local side. */
285
	close(pin[0]);
286
	*fdout = pin[1];
287
	close(pout[1]);
288
	*fdin = pout[0];
289
	signal(SIGTERM, killchild);
290
	signal(SIGINT, killchild);
291
	signal(SIGHUP, killchild);
292
	return 0;
293
}
294
295
/*
296
 * This functions executes a command simlar to do_cmd(), but expects the
297
 * input and output descriptors to be setup by a previous call to do_cmd().
298
 * This way the input and output of two commands can be connected.
299
 */
300
int
301
do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
302
{
303
	pid_t pid;
304
	int status;
305
306
	if (verbose_mode)
307
		fmprintf(stderr,
308
		    "Executing: 2nd program %s host %s, user %s, command %s\n",
309
		    ssh_program, host,
310
		    remuser ? remuser : "(unspecified)", cmd);
311
312
	if (port == -1)
313
		port = sshport;
314
315
	/* Fork a child to execute the command on the remote host using ssh. */
316
	pid = fork();
317
	if (pid == 0) {
318
		dup2(fdin, 0);
319
		dup2(fdout, 1);
320
321
		replacearg(&args, 0, "%s", ssh_program);
322
		if (port != -1) {
323
			addargs(&args, "-p");
324
			addargs(&args, "%d", port);
325
		}
326
		if (remuser != NULL) {
327
			addargs(&args, "-l");
328
			addargs(&args, "%s", remuser);
329
		}
330
		addargs(&args, "--");
331
		addargs(&args, "%s", host);
332
		addargs(&args, "%s", cmd);
333
334
		execvp(ssh_program, args.list);
335
		perror(ssh_program);
336
		exit(1);
337
	} else if (pid == -1) {
338
		fatal("fork: %s", strerror(errno));
339
	}
340
	while (waitpid(pid, &status, 0) == -1)
341
		if (errno != EINTR)
342
			fatal("do_cmd2: waitpid: %s", strerror(errno));
343
	return 0;
344
}
345
346
typedef struct {
347
	size_t cnt;
348
	char *buf;
349
} BUF;
350
351
BUF *allocbuf(BUF *, int, int);
352
void lostconn(int);
353
int okname(char *);
354
void run_err(const char *,...);
355
void verifydir(char *);
356
357
struct passwd *pwd;
358
uid_t userid;
359
int errs, remin, remout;
360
int pflag, iamremote, iamrecursive, targetshouldbedirectory;
361
362
#define	CMDNEEDS	64
363
char cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
364
365
int response(void);
366
void rsource(char *, struct stat *);
367
void sink(int, char *[]);
368
void source(int, char *[]);
369
void tolocal(int, char *[]);
370
void toremote(int, char *[]);
371
void usage(void);
372
373
int
374
main(int argc, char **argv)
375
{
376
10
	int ch, fflag, tflag, status, n;
377
	char **newargv;
378
5
	const char *errstr;
379
	extern char *optarg;
380
	extern int optind;
381
382
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
383
5
	sanitise_stdfd();
384
385
5
	setlocale(LC_CTYPE, "");
386
387
	/* Copy argv, because we modify it */
388
5
	newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
389
28774
	for (n = 0; n < argc; n++)
390
14382
		newargv[n] = xstrdup(argv[n]);
391
	argv = newargv;
392
393
5
	memset(&args, '\0', sizeof(args));
394
5
	memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
395
5
	args.list = remote_remote_args.list = NULL;
396
5
	addargs(&args, "%s", ssh_program);
397
5
	addargs(&args, "-x");
398
5
	addargs(&args, "-oForwardAgent=no");
399
5
	addargs(&args, "-oPermitLocalCommand=no");
400
5
	addargs(&args, "-oClearAllForwardings=yes");
401
402
	fflag = tflag = 0;
403
20
	while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
404





10
		switch (ch) {
405
		/* User-visible flags. */
406
		case '1':
407
			fatal("SSH protocol v.1 is no longer supported");
408
			break;
409
		case '2':
410
			/* Ignored */
411
			break;
412
		case '4':
413
		case '6':
414
		case 'C':
415
			addargs(&args, "-%c", ch);
416
			addargs(&remote_remote_args, "-%c", ch);
417
			break;
418
		case '3':
419
			throughlocal = 1;
420
			break;
421
		case 'o':
422
		case 'c':
423
		case 'i':
424
		case 'F':
425
			addargs(&remote_remote_args, "-%c", ch);
426
			addargs(&remote_remote_args, "%s", optarg);
427
			addargs(&args, "-%c", ch);
428
			addargs(&args, "%s", optarg);
429
			break;
430
		case 'P':
431
			sshport = a2port(optarg);
432
			if (sshport <= 0)
433
				fatal("bad port \"%s\"\n", optarg);
434
			break;
435
		case 'B':
436
			addargs(&remote_remote_args, "-oBatchmode=yes");
437
			addargs(&args, "-oBatchmode=yes");
438
			break;
439
		case 'l':
440
			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
441
			    &errstr);
442
			if (errstr != NULL)
443
				usage();
444
			limit_kbps *= 1024; /* kbps */
445
			bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
446
			break;
447
		case 'p':
448
			pflag = 1;
449
			break;
450
		case 'r':
451
			iamrecursive = 1;
452
			break;
453
		case 'S':
454
			ssh_program = xstrdup(optarg);
455
			break;
456
		case 'v':
457
			addargs(&args, "-v");
458
			addargs(&remote_remote_args, "-v");
459
			verbose_mode = 1;
460
			break;
461
		case 'q':
462
			addargs(&args, "-q");
463
			addargs(&remote_remote_args, "-q");
464
			showprogress = 0;
465
			break;
466
467
		/* Server options. */
468
		case 'd':
469
			targetshouldbedirectory = 1;
470
			break;
471
		case 'f':	/* "from" */
472
5
			iamremote = 1;
473
			fflag = 1;
474
5
			break;
475
		case 't':	/* "to" */
476
			iamremote = 1;
477
			tflag = 1;
478
			break;
479
		default:
480
			usage();
481
		}
482
5
	argc -= optind;
483
5
	argv += optind;
484
485
5
	if ((pwd = getpwuid(userid = getuid())) == NULL)
486
		fatal("unknown user %u", (u_int) userid);
487
488
5
	if (!isatty(STDOUT_FILENO))
489
5
		showprogress = 0;
490
491
5
	if (pflag) {
492
		/* Cannot pledge: -p allows setuid/setgid files... */
493
	} else {
494
10
		if (pledge("stdio rpath wpath cpath fattr tty proc exec flock rpath cpath wpath",
495
5
		    NULL) == -1) {
496
			perror("pledge");
497
			exit(1);
498
		}
499
	}
500
501
5
	remin = STDIN_FILENO;
502
5
	remout = STDOUT_FILENO;
503
504
5
	if (fflag) {
505
		/* Follow "protocol", send data. */
506
		(void) response();
507
		source(argc, argv);
508
		exit(errs != 0);
509
	}
510
	if (tflag) {
511
		/* Receive data. */
512
		sink(argc, argv);
513
		exit(errs != 0);
514
	}
515
	if (argc < 2)
516
		usage();
517
	if (argc > 2)
518
		targetshouldbedirectory = 1;
519
520
	remin = remout = -1;
521
	do_cmd_pid = -1;
522
	/* Command to be executed on remote system using "ssh". */
523
	(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
524
	    verbose_mode ? " -v" : "",
525
	    iamrecursive ? " -r" : "", pflag ? " -p" : "",
526
	    targetshouldbedirectory ? " -d" : "");
527
528
	(void) signal(SIGPIPE, lostconn);
529
530
	if (colon(argv[argc - 1]))	/* Dest is remote host. */
531
		toremote(argc, argv);
532
	else {
533
		if (targetshouldbedirectory)
534
			verifydir(argv[argc - 1]);
535
		tolocal(argc, argv);	/* Dest is local host. */
536
	}
537
	/*
538
	 * Finally check the exit status of the ssh process, if one was forked
539
	 * and no error has occurred yet
540
	 */
541
	if (do_cmd_pid != -1 && errs == 0) {
542
		if (remin != -1)
543
		    (void) close(remin);
544
		if (remout != -1)
545
		    (void) close(remout);
546
		if (waitpid(do_cmd_pid, &status, 0) == -1)
547
			errs = 1;
548
		else {
549
			if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
550
				errs = 1;
551
		}
552
	}
553
	exit(errs != 0);
554
}
555
556
/* Callback from atomicio6 to update progress meter and limit bandwidth */
557
static int
558
scpio(void *_cnt, size_t s)
559
{
560
229446
	off_t *cnt = (off_t *)_cnt;
561
562
114723
	*cnt += s;
563
114723
	if (limit_kbps > 0)
564
		bandwidth_limit(&bwlimit, s);
565
114723
	return 0;
566
}
567
568
static int
569
do_times(int fd, int verb, const struct stat *sb)
570
{
571
	/* strlen(2^64) == 20; strlen(10^6) == 7 */
572
	char buf[(20 + 7 + 2) * 2 + 2];
573
574
	(void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
575
	    (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
576
	    (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
577
	if (verb) {
578
		fprintf(stderr, "File mtime %lld atime %lld\n",
579
		    (long long)sb->st_mtime, (long long)sb->st_atime);
580
		fprintf(stderr, "Sending file timestamps: %s", buf);
581
	}
582
	(void) atomicio(vwrite, fd, buf, strlen(buf));
583
	return (response());
584
}
585
586
void
587
toremote(int argc, char **argv)
588
{
589
	char *suser = NULL, *host = NULL, *src = NULL;
590
	char *bp, *tuser, *thost, *targ;
591
	int sport = -1, tport = -1;
592
	arglist alist;
593
	int i, r;
594
	u_int j;
595
596
	memset(&alist, '\0', sizeof(alist));
597
	alist.list = NULL;
598
599
	/* Parse target */
600
	r = parse_uri("scp", argv[argc - 1], &tuser, &thost, &tport, &targ);
601
	if (r == -1)
602
		goto out;	/* invalid URI */
603
	if (r != 0) {
604
		if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
605
		    &targ) == -1)
606
			goto out;
607
	}
608
	if (tuser != NULL && !okname(tuser))
609
		goto out;
610
611
	/* Parse source files */
612
	for (i = 0; i < argc - 1; i++) {
613
		free(suser);
614
		free(host);
615
		free(src);
616
		r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
617
		if (r == -1)
618
			continue;	/* invalid URI */
619
		if (r != 0)
620
			parse_user_host_path(argv[i], &suser, &host, &src);
621
		if (suser != NULL && !okname(suser)) {
622
			++errs;
623
			continue;
624
		}
625
		if (host && throughlocal) {	/* extended remote to remote */
626
			xasprintf(&bp, "%s -f %s%s", cmd,
627
			    *src == '-' ? "-- " : "", src);
628
			if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
629
				exit(1);
630
			free(bp);
631
			xasprintf(&bp, "%s -t %s%s", cmd,
632
			    *targ == '-' ? "-- " : "", targ);
633
			if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0)
634
				exit(1);
635
			free(bp);
636
			(void) close(remin);
637
			(void) close(remout);
638
			remin = remout = -1;
639
		} else if (host) {	/* standard remote to remote */
640
			if (tport != -1 && tport != SSH_DEFAULT_PORT) {
641
				/* This would require the remote support URIs */
642
				fatal("target port not supported with two "
643
				    "remote hosts without the -3 option");
644
			}
645
646
			freeargs(&alist);
647
			addargs(&alist, "%s", ssh_program);
648
			addargs(&alist, "-x");
649
			addargs(&alist, "-oClearAllForwardings=yes");
650
			addargs(&alist, "-n");
651
			for (j = 0; j < remote_remote_args.num; j++) {
652
				addargs(&alist, "%s",
653
				    remote_remote_args.list[j]);
654
			}
655
656
			if (sport != -1) {
657
				addargs(&alist, "-p");
658
				addargs(&alist, "%d", sport);
659
			}
660
			if (suser) {
661
				addargs(&alist, "-l");
662
				addargs(&alist, "%s", suser);
663
			}
664
			addargs(&alist, "--");
665
			addargs(&alist, "%s", host);
666
			addargs(&alist, "%s", cmd);
667
			addargs(&alist, "%s", src);
668
			addargs(&alist, "%s%s%s:%s",
669
			    tuser ? tuser : "", tuser ? "@" : "",
670
			    thost, targ);
671
			if (do_local_cmd(&alist) != 0)
672
				errs = 1;
673
		} else {	/* local to remote */
674
			if (remin == -1) {
675
				xasprintf(&bp, "%s -t %s%s", cmd,
676
				    *targ == '-' ? "-- " : "", targ);
677
				if (do_cmd(thost, tuser, tport, bp, &remin,
678
				    &remout) < 0)
679
					exit(1);
680
				if (response() < 0)
681
					exit(1);
682
				free(bp);
683
			}
684
			source(1, argv + i);
685
		}
686
	}
687
out:
688
	free(tuser);
689
	free(thost);
690
	free(targ);
691
	free(suser);
692
	free(host);
693
	free(src);
694
}
695
696
void
697
tolocal(int argc, char **argv)
698
{
699
	char *bp, *host = NULL, *src = NULL, *suser = NULL;
700
	arglist alist;
701
	int i, r, sport = -1;
702
703
	memset(&alist, '\0', sizeof(alist));
704
	alist.list = NULL;
705
706
	for (i = 0; i < argc - 1; i++) {
707
		free(suser);
708
		free(host);
709
		free(src);
710
		r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
711
		if (r == -1) {
712
			++errs;
713
			continue;
714
		}
715
		if (r != 0)
716
			parse_user_host_path(argv[i], &suser, &host, &src);
717
		if (suser != NULL && !okname(suser)) {
718
			++errs;
719
			continue;
720
		}
721
		if (!host) {	/* Local to local. */
722
			freeargs(&alist);
723
			addargs(&alist, "%s", _PATH_CP);
724
			if (iamrecursive)
725
				addargs(&alist, "-r");
726
			if (pflag)
727
				addargs(&alist, "-p");
728
			addargs(&alist, "--");
729
			addargs(&alist, "%s", argv[i]);
730
			addargs(&alist, "%s", argv[argc-1]);
731
			if (do_local_cmd(&alist))
732
				++errs;
733
			continue;
734
		}
735
		/* Remote to local. */
736
		xasprintf(&bp, "%s -f %s%s",
737
		    cmd, *src == '-' ? "-- " : "", src);
738
		if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
739
			free(bp);
740
			++errs;
741
			continue;
742
		}
743
		free(bp);
744
		sink(1, argv + argc - 1);
745
		(void) close(remin);
746
		remin = remout = -1;
747
	}
748
	free(suser);
749
	free(host);
750
	free(src);
751
}
752
753
void
754
source(int argc, char **argv)
755
{
756
10
	struct stat stb;
757
	static BUF buffer;
758
	BUF *bp;
759
5
	off_t i, statbytes;
760
	size_t amt, nr;
761
	int fd = -1, haderr, indx;
762
5
	char *last, *name, buf[2048], encname[PATH_MAX];
763
	int len;
764
765
28754
	for (indx = 0; indx < argc; ++indx) {
766
14372
		name = argv[indx];
767
14372
		statbytes = 0;
768
14372
		len = strlen(name);
769

57488
		while (len > 1 && name[len-1] == '/')
770
			name[--len] = '\0';
771
14372
		if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0)
772
			goto syserr;
773
14372
		if (strchr(name, '\n') != NULL) {
774
			strnvis(encname, name, sizeof(encname), VIS_NL);
775
			name = encname;
776
		}
777
14372
		if (fstat(fd, &stb) < 0) {
778
syserr:			run_err("%s: %s", name, strerror(errno));
779
			goto next;
780
		}
781
14372
		if (stb.st_size < 0) {
782
			run_err("%s: %s", name, "Negative file size");
783
			goto next;
784
		}
785
14372
		unset_nonblock(fd);
786
14372
		switch (stb.st_mode & S_IFMT) {
787
		case S_IFREG:
788
			break;
789
		case S_IFDIR:
790
			if (iamrecursive) {
791
				rsource(name, &stb);
792
				goto next;
793
			}
794
			/* FALLTHROUGH */
795
		default:
796
			run_err("%s: not a regular file", name);
797
			goto next;
798
		}
799
14372
		if ((last = strrchr(name, '/')) == NULL)
800
			last = name;
801
		else
802
14372
			++last;
803
14372
		curfile = last;
804
14372
		if (pflag) {
805
			if (do_times(remout, verbose_mode, &stb) < 0)
806
				goto next;
807
		}
808
#define	FILEMODEMASK	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
809
28744
		snprintf(buf, sizeof buf, "C%04o %lld %s\n",
810
14372
		    (u_int) (stb.st_mode & FILEMODEMASK),
811
14372
		    (long long)stb.st_size, last);
812
14372
		if (verbose_mode)
813
			fmprintf(stderr, "Sending file modes: %s", buf);
814
14372
		(void) atomicio(vwrite, remout, buf, strlen(buf));
815
14372
		if (response() < 0)
816
			goto next;
817
14372
		if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
818
next:			if (fd != -1) {
819
				(void) close(fd);
820
				fd = -1;
821
			}
822
			continue;
823
		}
824
14372
		if (showprogress)
825
			start_progress_meter(curfile, stb.st_size, &statbytes);
826
14372
		set_nonblock(remout);
827
258190
		for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
828
114723
			amt = bp->cnt;
829
114723
			if (i + (off_t)amt > stb.st_size)
830
14372
				amt = stb.st_size - i;
831
114723
			if (!haderr) {
832
229446
				if ((nr = atomicio(read, fd,
833
229446
				    bp->buf, amt)) != amt) {
834
					haderr = errno;
835
					memset(bp->buf + nr, 0, amt - nr);
836
				}
837
			}
838
			/* Keep writing after error to retain sync */
839
114723
			if (haderr) {
840
				(void)atomicio(vwrite, remout, bp->buf, amt);
841
				memset(bp->buf, 0, amt);
842
				continue;
843
			}
844
229446
			if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
845
114723
			    &statbytes) != amt)
846
				haderr = errno;
847
		}
848
14372
		unset_nonblock(remout);
849
850
14372
		if (fd != -1) {
851
14372
			if (close(fd) < 0 && !haderr)
852
				haderr = errno;
853
			fd = -1;
854
14372
		}
855
14372
		if (!haderr)
856
14372
			(void) atomicio(vwrite, remout, "", 1);
857
		else
858
			run_err("%s: %s", name, strerror(haderr));
859
14372
		(void) response();
860
14372
		if (showprogress)
861
			stop_progress_meter();
862
	}
863
5
}
864
865
void
866
rsource(char *name, struct stat *statp)
867
{
868
	DIR *dirp;
869
	struct dirent *dp;
870
	char *last, *vect[1], path[PATH_MAX];
871
872
	if (!(dirp = opendir(name))) {
873
		run_err("%s: %s", name, strerror(errno));
874
		return;
875
	}
876
	last = strrchr(name, '/');
877
	if (last == NULL)
878
		last = name;
879
	else
880
		last++;
881
	if (pflag) {
882
		if (do_times(remout, verbose_mode, statp) < 0) {
883
			closedir(dirp);
884
			return;
885
		}
886
	}
887
	(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
888
	    (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
889
	if (verbose_mode)
890
		fmprintf(stderr, "Entering directory: %s", path);
891
	(void) atomicio(vwrite, remout, path, strlen(path));
892
	if (response() < 0) {
893
		closedir(dirp);
894
		return;
895
	}
896
	while ((dp = readdir(dirp)) != NULL) {
897
		if (dp->d_ino == 0)
898
			continue;
899
		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
900
			continue;
901
		if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
902
			run_err("%s/%s: name too long", name, dp->d_name);
903
			continue;
904
		}
905
		(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
906
		vect[0] = path;
907
		source(1, vect);
908
	}
909
	(void) closedir(dirp);
910
	(void) atomicio(vwrite, remout, "E\n", 2);
911
	(void) response();
912
}
913
914
#define TYPE_OVERFLOW(type, val) \
915
	((sizeof(type) == 4 && (val) > INT32_MAX) || \
916
	 (sizeof(type) == 8 && (val) > INT64_MAX) || \
917
	 (sizeof(type) != 4 && sizeof(type) != 8))
918
919
void
920
sink(int argc, char **argv)
921
{
922
	static BUF buffer;
923
	struct stat stb;
924
	enum {
925
		YES, NO, DISPLAYED
926
	} wrerr;
927
	BUF *bp;
928
	off_t i;
929
	size_t j, count;
930
	int amt, exists, first, ofd;
931
	mode_t mode, omode, mask;
932
	off_t size, statbytes;
933
	unsigned long long ull;
934
	int setimes, targisdir, wrerrno = 0;
935
	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
936
	struct timeval tv[2];
937
938
#define	atime	tv[0]
939
#define	mtime	tv[1]
940
#define	SCREWUP(str)	{ why = str; goto screwup; }
941
942
	if (TYPE_OVERFLOW(time_t, 0) || TYPE_OVERFLOW(off_t, 0))
943
		SCREWUP("Unexpected off_t/time_t size");
944
945
	setimes = targisdir = 0;
946
	mask = umask(0);
947
	if (!pflag)
948
		(void) umask(mask);
949
	if (argc != 1) {
950
		run_err("ambiguous target");
951
		exit(1);
952
	}
953
	targ = *argv;
954
	if (targetshouldbedirectory)
955
		verifydir(targ);
956
957
	(void) atomicio(vwrite, remout, "", 1);
958
	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
959
		targisdir = 1;
960
	for (first = 1;; first = 0) {
961
		cp = buf;
962
		if (atomicio(read, remin, cp, 1) != 1)
963
			return;
964
		if (*cp++ == '\n')
965
			SCREWUP("unexpected <newline>");
966
		do {
967
			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
968
				SCREWUP("lost connection");
969
			*cp++ = ch;
970
		} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
971
		*cp = 0;
972
		if (verbose_mode)
973
			fmprintf(stderr, "Sink: %s", buf);
974
975
		if (buf[0] == '\01' || buf[0] == '\02') {
976
			if (iamremote == 0) {
977
				(void) snmprintf(visbuf, sizeof(visbuf),
978
				    NULL, "%s", buf + 1);
979
				(void) atomicio(vwrite, STDERR_FILENO,
980
				    visbuf, strlen(visbuf));
981
			}
982
			if (buf[0] == '\02')
983
				exit(1);
984
			++errs;
985
			continue;
986
		}
987
		if (buf[0] == 'E') {
988
			(void) atomicio(vwrite, remout, "", 1);
989
			return;
990
		}
991
		if (ch == '\n')
992
			*--cp = 0;
993
994
		cp = buf;
995
		if (*cp == 'T') {
996
			setimes++;
997
			cp++;
998
			if (!isdigit((unsigned char)*cp))
999
				SCREWUP("mtime.sec not present");
1000
			ull = strtoull(cp, &cp, 10);
1001
			if (!cp || *cp++ != ' ')
1002
				SCREWUP("mtime.sec not delimited");
1003
			if (TYPE_OVERFLOW(time_t, ull))
1004
				setimes = 0;	/* out of range */
1005
			mtime.tv_sec = ull;
1006
			mtime.tv_usec = strtol(cp, &cp, 10);
1007
			if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 ||
1008
			    mtime.tv_usec > 999999)
1009
				SCREWUP("mtime.usec not delimited");
1010
			if (!isdigit((unsigned char)*cp))
1011
				SCREWUP("atime.sec not present");
1012
			ull = strtoull(cp, &cp, 10);
1013
			if (!cp || *cp++ != ' ')
1014
				SCREWUP("atime.sec not delimited");
1015
			if (TYPE_OVERFLOW(time_t, ull))
1016
				setimes = 0;	/* out of range */
1017
			atime.tv_sec = ull;
1018
			atime.tv_usec = strtol(cp, &cp, 10);
1019
			if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
1020
			    atime.tv_usec > 999999)
1021
				SCREWUP("atime.usec not delimited");
1022
			(void) atomicio(vwrite, remout, "", 1);
1023
			continue;
1024
		}
1025
		if (*cp != 'C' && *cp != 'D') {
1026
			/*
1027
			 * Check for the case "rcp remote:foo\* local:bar".
1028
			 * In this case, the line "No match." can be returned
1029
			 * by the shell before the rcp command on the remote is
1030
			 * executed so the ^Aerror_message convention isn't
1031
			 * followed.
1032
			 */
1033
			if (first) {
1034
				run_err("%s", cp);
1035
				exit(1);
1036
			}
1037
			SCREWUP("expected control record");
1038
		}
1039
		mode = 0;
1040
		for (++cp; cp < buf + 5; cp++) {
1041
			if (*cp < '0' || *cp > '7')
1042
				SCREWUP("bad mode");
1043
			mode = (mode << 3) | (*cp - '0');
1044
		}
1045
		if (*cp++ != ' ')
1046
			SCREWUP("mode not delimited");
1047
1048
		if (!isdigit((unsigned char)*cp))
1049
			SCREWUP("size not present");
1050
		ull = strtoull(cp, &cp, 10);
1051
		if (!cp || *cp++ != ' ')
1052
			SCREWUP("size not delimited");
1053
		if (TYPE_OVERFLOW(off_t, ull))
1054
			SCREWUP("size out of range");
1055
		size = (off_t)ull;
1056
1057
		if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
1058
			run_err("error: unexpected filename: %s", cp);
1059
			exit(1);
1060
		}
1061
		if (targisdir) {
1062
			static char *namebuf;
1063
			static size_t cursize;
1064
			size_t need;
1065
1066
			need = strlen(targ) + strlen(cp) + 250;
1067
			if (need > cursize) {
1068
				free(namebuf);
1069
				namebuf = xmalloc(need);
1070
				cursize = need;
1071
			}
1072
			(void) snprintf(namebuf, need, "%s%s%s", targ,
1073
			    strcmp(targ, "/") ? "/" : "", cp);
1074
			np = namebuf;
1075
		} else
1076
			np = targ;
1077
		curfile = cp;
1078
		exists = stat(np, &stb) == 0;
1079
		if (buf[0] == 'D') {
1080
			int mod_flag = pflag;
1081
			if (!iamrecursive)
1082
				SCREWUP("received directory without -r");
1083
			if (exists) {
1084
				if (!S_ISDIR(stb.st_mode)) {
1085
					errno = ENOTDIR;
1086
					goto bad;
1087
				}
1088
				if (pflag)
1089
					(void) chmod(np, mode);
1090
			} else {
1091
				/* Handle copying from a read-only
1092
				   directory */
1093
				mod_flag = 1;
1094
				if (mkdir(np, mode | S_IRWXU) < 0)
1095
					goto bad;
1096
			}
1097
			vect[0] = xstrdup(np);
1098
			sink(1, vect);
1099
			if (setimes) {
1100
				setimes = 0;
1101
				if (utimes(vect[0], tv) < 0)
1102
					run_err("%s: set times: %s",
1103
					    vect[0], strerror(errno));
1104
			}
1105
			if (mod_flag)
1106
				(void) chmod(vect[0], mode);
1107
			free(vect[0]);
1108
			continue;
1109
		}
1110
		omode = mode;
1111
		mode |= S_IWUSR;
1112
		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
1113
bad:			run_err("%s: %s", np, strerror(errno));
1114
			continue;
1115
		}
1116
		(void) atomicio(vwrite, remout, "", 1);
1117
		if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
1118
			(void) close(ofd);
1119
			continue;
1120
		}
1121
		cp = bp->buf;
1122
		wrerr = NO;
1123
1124
		statbytes = 0;
1125
		if (showprogress)
1126
			start_progress_meter(curfile, size, &statbytes);
1127
		set_nonblock(remin);
1128
		for (count = i = 0; i < size; i += bp->cnt) {
1129
			amt = bp->cnt;
1130
			if (i + amt > size)
1131
				amt = size - i;
1132
			count += amt;
1133
			do {
1134
				j = atomicio6(read, remin, cp, amt,
1135
				    scpio, &statbytes);
1136
				if (j == 0) {
1137
					run_err("%s", j != EPIPE ?
1138
					    strerror(errno) :
1139
					    "dropped connection");
1140
					exit(1);
1141
				}
1142
				amt -= j;
1143
				cp += j;
1144
			} while (amt > 0);
1145
1146
			if (count == bp->cnt) {
1147
				/* Keep reading so we stay sync'd up. */
1148
				if (wrerr == NO) {
1149
					if (atomicio(vwrite, ofd, bp->buf,
1150
					    count) != count) {
1151
						wrerr = YES;
1152
						wrerrno = errno;
1153
					}
1154
				}
1155
				count = 0;
1156
				cp = bp->buf;
1157
			}
1158
		}
1159
		unset_nonblock(remin);
1160
		if (count != 0 && wrerr == NO &&
1161
		    atomicio(vwrite, ofd, bp->buf, count) != count) {
1162
			wrerr = YES;
1163
			wrerrno = errno;
1164
		}
1165
		if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
1166
		    ftruncate(ofd, size) != 0) {
1167
			run_err("%s: truncate: %s", np, strerror(errno));
1168
			wrerr = DISPLAYED;
1169
		}
1170
		if (pflag) {
1171
			if (exists || omode != mode)
1172
				if (fchmod(ofd, omode)) {
1173
					run_err("%s: set mode: %s",
1174
					    np, strerror(errno));
1175
					wrerr = DISPLAYED;
1176
				}
1177
		} else {
1178
			if (!exists && omode != mode)
1179
				if (fchmod(ofd, omode & ~mask)) {
1180
					run_err("%s: set mode: %s",
1181
					    np, strerror(errno));
1182
					wrerr = DISPLAYED;
1183
				}
1184
		}
1185
		if (close(ofd) == -1) {
1186
			wrerr = YES;
1187
			wrerrno = errno;
1188
		}
1189
		(void) response();
1190
		if (showprogress)
1191
			stop_progress_meter();
1192
		if (setimes && wrerr == NO) {
1193
			setimes = 0;
1194
			if (utimes(np, tv) < 0) {
1195
				run_err("%s: set times: %s",
1196
				    np, strerror(errno));
1197
				wrerr = DISPLAYED;
1198
			}
1199
		}
1200
		switch (wrerr) {
1201
		case YES:
1202
			run_err("%s: %s", np, strerror(wrerrno));
1203
			break;
1204
		case NO:
1205
			(void) atomicio(vwrite, remout, "", 1);
1206
			break;
1207
		case DISPLAYED:
1208
			break;
1209
		}
1210
	}
1211
screwup:
1212
	run_err("protocol error: %s", why);
1213
	exit(1);
1214
}
1215
1216
int
1217
response(void)
1218
{
1219
57498
	char ch, *cp, resp, rbuf[2048], visbuf[2048];
1220
1221
28749
	if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
1222
		lostconn(0);
1223
1224
28749
	cp = rbuf;
1225

28749
	switch (resp) {
1226
	case 0:		/* ok */
1227
28749
		return (0);
1228
	default:
1229
		*cp++ = resp;
1230
		/* FALLTHROUGH */
1231
	case 1:		/* error, followed by error msg */
1232
	case 2:		/* fatal error, "" */
1233
		do {
1234
			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
1235
				lostconn(0);
1236
			*cp++ = ch;
1237
		} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
1238
1239
		if (!iamremote) {
1240
			cp[-1] = '\0';
1241
			(void) snmprintf(visbuf, sizeof(visbuf),
1242
			    NULL, "%s\n", rbuf);
1243
			(void) atomicio(vwrite, STDERR_FILENO,
1244
			    visbuf, strlen(visbuf));
1245
		}
1246
		++errs;
1247
		if (resp == 1)
1248
			return (-1);
1249
		exit(1);
1250
	}
1251
	/* NOTREACHED */
1252
28749
}
1253
1254
void
1255
usage(void)
1256
{
1257
	(void) fprintf(stderr,
1258
	    "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1259
	    "           [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
1260
	exit(1);
1261
}
1262
1263
void
1264
run_err(const char *fmt,...)
1265
{
1266
	static FILE *fp;
1267
	va_list ap;
1268
1269
	++errs;
1270
	if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
1271
		(void) fprintf(fp, "%c", 0x01);
1272
		(void) fprintf(fp, "scp: ");
1273
		va_start(ap, fmt);
1274
		(void) vfprintf(fp, fmt, ap);
1275
		va_end(ap);
1276
		(void) fprintf(fp, "\n");
1277
		(void) fflush(fp);
1278
	}
1279
1280
	if (!iamremote) {
1281
		va_start(ap, fmt);
1282
		vfmprintf(stderr, fmt, ap);
1283
		va_end(ap);
1284
		fprintf(stderr, "\n");
1285
	}
1286
}
1287
1288
void
1289
verifydir(char *cp)
1290
{
1291
	struct stat stb;
1292
1293
	if (!stat(cp, &stb)) {
1294
		if (S_ISDIR(stb.st_mode))
1295
			return;
1296
		errno = ENOTDIR;
1297
	}
1298
	run_err("%s: %s", cp, strerror(errno));
1299
	killchild(0);
1300
}
1301
1302
int
1303
okname(char *cp0)
1304
{
1305
	int c;
1306
	char *cp;
1307
1308
	cp = cp0;
1309
	do {
1310
		c = (int)*cp;
1311
		if (c & 0200)
1312
			goto bad;
1313
		if (!isalpha(c) && !isdigit((unsigned char)c)) {
1314
			switch (c) {
1315
			case '\'':
1316
			case '"':
1317
			case '`':
1318
			case ' ':
1319
			case '#':
1320
				goto bad;
1321
			default:
1322
				break;
1323
			}
1324
		}
1325
	} while (*++cp);
1326
	return (1);
1327
1328
bad:	fmprintf(stderr, "%s: invalid user name\n", cp0);
1329
	return (0);
1330
}
1331
1332
BUF *
1333
allocbuf(BUF *bp, int fd, int blksize)
1334
{
1335
	size_t size;
1336
28744
	struct stat stb;
1337
1338
14372
	if (fstat(fd, &stb) < 0) {
1339
		run_err("fstat: %s", strerror(errno));
1340
		return (0);
1341
	}
1342
14372
	size = ROUNDUP(stb.st_blksize, blksize);
1343
14372
	if (size == 0)
1344
		size = blksize;
1345
14372
	if (bp->cnt >= size)
1346
14367
		return (bp);
1347
5
	bp->buf = xrecallocarray(bp->buf, bp->cnt, size, 1);
1348
5
	bp->cnt = size;
1349
5
	return (bp);
1350
14372
}
1351
1352
void
1353
lostconn(int signo)
1354
{
1355
	if (!iamremote)
1356
		(void)write(STDERR_FILENO, "lost connection\n", 16);
1357
	if (signo)
1358
		_exit(1);
1359
	else
1360
		exit(1);
1361
}