GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/scp/../scp.c Lines: 178 729 24.4 %
Date: 2017-11-07 Branches: 83 492 16.9 %

Line Branch Exec Source
1
/* $OpenBSD: scp.c,v 1.192 2017/05/31 09:15:42 deraadt 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 "atomicio.h"
100
#include "pathnames.h"
101
#include "log.h"
102
#include "misc.h"
103
#include "progressmeter.h"
104
#include "utf8.h"
105
106
#define COPY_BUFLEN	16384
107
108
int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
109
int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout);
110
111
/* Struct for addargs */
112
arglist args;
113
arglist remote_remote_args;
114
115
/* Bandwidth limit */
116
long long limit_kbps = 0;
117
struct bwlimit bwlimit;
118
119
/* Name of current file being transferred. */
120
char *curfile;
121
122
/* This is set to non-zero to enable verbose mode. */
123
int verbose_mode = 0;
124
125
/* This is set to zero if the progressmeter is not desired. */
126
int showprogress = 1;
127
128
/*
129
 * This is set to non-zero if remote-remote copy should be piped
130
 * through this process.
131
 */
132
int throughlocal = 0;
133
134
/* This is the program to execute for the secured connection. ("ssh" or -S) */
135
char *ssh_program = _PATH_SSH_PROGRAM;
136
137
/* This is used to store the pid of ssh_program */
138
pid_t do_cmd_pid = -1;
139
140
static void
141
killchild(int signo)
142
{
143
	if (do_cmd_pid > 1) {
144
		kill(do_cmd_pid, signo ? signo : SIGTERM);
145
		waitpid(do_cmd_pid, NULL, 0);
146
	}
147
148
	if (signo)
149
		_exit(1);
150
	exit(1);
151
}
152
153
static void
154
suspchild(int signo)
155
{
156
	int status;
157
158
	if (do_cmd_pid > 1) {
159
		kill(do_cmd_pid, signo);
160
		while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 &&
161
		    errno == EINTR)
162
			;
163
		kill(getpid(), SIGSTOP);
164
	}
165
}
166
167
static int
168
do_local_cmd(arglist *a)
169
{
170
	u_int i;
171
	int status;
172
	pid_t pid;
173
174
	if (a->num == 0)
175
		fatal("do_local_cmd: no arguments");
176
177
	if (verbose_mode) {
178
		fprintf(stderr, "Executing:");
179
		for (i = 0; i < a->num; i++)
180
			fmprintf(stderr, " %s", a->list[i]);
181
		fprintf(stderr, "\n");
182
	}
183
	if ((pid = fork()) == -1)
184
		fatal("do_local_cmd: fork: %s", strerror(errno));
185
186
	if (pid == 0) {
187
		execvp(a->list[0], a->list);
188
		perror(a->list[0]);
189
		exit(1);
190
	}
191
192
	do_cmd_pid = pid;
193
	signal(SIGTERM, killchild);
194
	signal(SIGINT, killchild);
195
	signal(SIGHUP, killchild);
196
197
	while (waitpid(pid, &status, 0) == -1)
198
		if (errno != EINTR)
199
			fatal("do_local_cmd: waitpid: %s", strerror(errno));
200
201
	do_cmd_pid = -1;
202
203
	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
204
		return (-1);
205
206
	return (0);
207
}
208
209
/*
210
 * This function executes the given command as the specified user on the
211
 * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
212
 * assigns the input and output file descriptors on success.
213
 */
214
215
int
216
do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
217
{
218
2
	int pin[2], pout[2], reserved[2];
219
220
1
	if (verbose_mode)
221
		fmprintf(stderr,
222
		    "Executing: program %s host %s, user %s, command %s\n",
223
		    ssh_program, host,
224
		    remuser ? remuser : "(unspecified)", cmd);
225
226
	/*
227
	 * Reserve two descriptors so that the real pipes won't get
228
	 * descriptors 0 and 1 because that will screw up dup2 below.
229
	 */
230
1
	if (pipe(reserved) < 0)
231
		fatal("pipe: %s", strerror(errno));
232
233
	/* Create a socket pair for communicating with ssh. */
234
1
	if (pipe(pin) < 0)
235
		fatal("pipe: %s", strerror(errno));
236
1
	if (pipe(pout) < 0)
237
		fatal("pipe: %s", strerror(errno));
238
239
	/* Free the reserved descriptors. */
240
1
	close(reserved[0]);
241
1
	close(reserved[1]);
242
243
1
	signal(SIGTSTP, suspchild);
244
1
	signal(SIGTTIN, suspchild);
245
1
	signal(SIGTTOU, suspchild);
246
247
	/* Fork a child to execute the command on the remote host using ssh. */
248
1
	do_cmd_pid = fork();
249
1
	if (do_cmd_pid == 0) {
250
		/* Child. */
251
		close(pin[1]);
252
		close(pout[0]);
253
		dup2(pin[0], 0);
254
		dup2(pout[1], 1);
255
		close(pin[0]);
256
		close(pout[1]);
257
258
		replacearg(&args, 0, "%s", ssh_program);
259
		if (remuser != NULL) {
260
			addargs(&args, "-l");
261
			addargs(&args, "%s", remuser);
262
		}
263
		addargs(&args, "--");
264
		addargs(&args, "%s", host);
265
		addargs(&args, "%s", cmd);
266
267
		execvp(ssh_program, args.list);
268
		perror(ssh_program);
269
		exit(1);
270
1
	} else if (do_cmd_pid == -1) {
271
		fatal("fork: %s", strerror(errno));
272
	}
273
	/* Parent.  Close the other side, and return the local side. */
274
1
	close(pin[0]);
275
1
	*fdout = pin[1];
276
1
	close(pout[1]);
277
1
	*fdin = pout[0];
278
1
	signal(SIGTERM, killchild);
279
1
	signal(SIGINT, killchild);
280
1
	signal(SIGHUP, killchild);
281
1
	return 0;
282
1
}
283
284
/*
285
 * This functions executes a command simlar to do_cmd(), but expects the
286
 * input and output descriptors to be setup by a previous call to do_cmd().
287
 * This way the input and output of two commands can be connected.
288
 */
289
int
290
do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
291
{
292
	pid_t pid;
293
	int status;
294
295
	if (verbose_mode)
296
		fmprintf(stderr,
297
		    "Executing: 2nd program %s host %s, user %s, command %s\n",
298
		    ssh_program, host,
299
		    remuser ? remuser : "(unspecified)", cmd);
300
301
	/* Fork a child to execute the command on the remote host using ssh. */
302
	pid = fork();
303
	if (pid == 0) {
304
		dup2(fdin, 0);
305
		dup2(fdout, 1);
306
307
		replacearg(&args, 0, "%s", ssh_program);
308
		if (remuser != NULL) {
309
			addargs(&args, "-l");
310
			addargs(&args, "%s", remuser);
311
		}
312
		addargs(&args, "--");
313
		addargs(&args, "%s", host);
314
		addargs(&args, "%s", cmd);
315
316
		execvp(ssh_program, args.list);
317
		perror(ssh_program);
318
		exit(1);
319
	} else if (pid == -1) {
320
		fatal("fork: %s", strerror(errno));
321
	}
322
	while (waitpid(pid, &status, 0) == -1)
323
		if (errno != EINTR)
324
			fatal("do_cmd2: waitpid: %s", strerror(errno));
325
	return 0;
326
}
327
328
typedef struct {
329
	size_t cnt;
330
	char *buf;
331
} BUF;
332
333
BUF *allocbuf(BUF *, int, int);
334
void lostconn(int);
335
int okname(char *);
336
void run_err(const char *,...);
337
void verifydir(char *);
338
339
struct passwd *pwd;
340
uid_t userid;
341
int errs, remin, remout;
342
int pflag, iamremote, iamrecursive, targetshouldbedirectory;
343
344
#define	CMDNEEDS	64
345
char cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
346
347
int response(void);
348
void rsource(char *, struct stat *);
349
void sink(int, char *[]);
350
void source(int, char *[]);
351
void tolocal(int, char *[]);
352
void toremote(char *, int, char *[]);
353
void usage(void);
354
355
int
356
main(int argc, char **argv)
357
{
358
10
	int ch, fflag, tflag, status, n;
359
	char *targ, **newargv;
360
5
	const char *errstr;
361
	extern char *optarg;
362
	extern int optind;
363
364
	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
365
5
	sanitise_stdfd();
366
367
5
	setlocale(LC_CTYPE, "");
368
369
	/* Copy argv, because we modify it */
370
5
	newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
371
34986
	for (n = 0; n < argc; n++)
372
17488
		newargv[n] = xstrdup(argv[n]);
373
	argv = newargv;
374
375
5
	memset(&args, '\0', sizeof(args));
376
5
	memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
377
5
	args.list = remote_remote_args.list = NULL;
378
5
	addargs(&args, "%s", ssh_program);
379
5
	addargs(&args, "-x");
380
5
	addargs(&args, "-oForwardAgent=no");
381
5
	addargs(&args, "-oPermitLocalCommand=no");
382
5
	addargs(&args, "-oClearAllForwardings=yes");
383
384
	fflag = tflag = 0;
385
18
	while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
386





16
		switch (ch) {
387
		/* User-visible flags. */
388
		case '1':
389
			fatal("SSH protocol v.1 is no longer supported");
390
			break;
391
		case '2':
392
			/* Ignored */
393
			break;
394
		case '4':
395
		case '6':
396
		case 'C':
397
			addargs(&args, "-%c", ch);
398
			addargs(&remote_remote_args, "-%c", ch);
399
			break;
400
		case '3':
401
			throughlocal = 1;
402
			break;
403
		case 'o':
404
		case 'c':
405
		case 'i':
406
		case 'F':
407
			addargs(&remote_remote_args, "-%c", ch);
408
			addargs(&remote_remote_args, "%s", optarg);
409
			addargs(&args, "-%c", ch);
410
			addargs(&args, "%s", optarg);
411
			break;
412
		case 'P':
413
			addargs(&remote_remote_args, "-p");
414
			addargs(&remote_remote_args, "%s", optarg);
415
			addargs(&args, "-p");
416
			addargs(&args, "%s", optarg);
417
			break;
418
		case 'B':
419
			addargs(&remote_remote_args, "-oBatchmode=yes");
420
			addargs(&args, "-oBatchmode=yes");
421
			break;
422
		case 'l':
423
			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
424
			    &errstr);
425
			if (errstr != NULL)
426
				usage();
427
			limit_kbps *= 1024; /* kbps */
428
			bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
429
			break;
430
		case 'p':
431
			pflag = 1;
432
			break;
433
		case 'r':
434
4
			iamrecursive = 1;
435
4
			break;
436
		case 'S':
437
			ssh_program = xstrdup(optarg);
438
			break;
439
		case 'v':
440
			addargs(&args, "-v");
441
			addargs(&remote_remote_args, "-v");
442
			verbose_mode = 1;
443
			break;
444
		case 'q':
445
			addargs(&args, "-q");
446
			addargs(&remote_remote_args, "-q");
447
			showprogress = 0;
448
			break;
449
450
		/* Server options. */
451
		case 'd':
452
			targetshouldbedirectory = 1;
453
			break;
454
		case 'f':	/* "from" */
455
4
			iamremote = 1;
456
			fflag = 1;
457
4
			break;
458
		case 't':	/* "to" */
459
			iamremote = 1;
460
			tflag = 1;
461
			break;
462
		default:
463
			usage();
464
		}
465
5
	argc -= optind;
466
5
	argv += optind;
467
468
5
	if ((pwd = getpwuid(userid = getuid())) == NULL)
469
		fatal("unknown user %u", (u_int) userid);
470
471
5
	if (!isatty(STDOUT_FILENO))
472
4
		showprogress = 0;
473
474
5
	if (pflag) {
475
		/* Cannot pledge: -p allows setuid/setgid files... */
476
	} else {
477
10
		if (pledge("stdio flock rpath wpath cpath fattr tty proc exec",
478
5
		    NULL) == -1) {
479
			perror("pledge");
480
			exit(1);
481
		}
482
	}
483
484
5
	remin = STDIN_FILENO;
485
5
	remout = STDOUT_FILENO;
486
487
5
	if (fflag) {
488
		/* Follow "protocol", send data. */
489
		(void) response();
490
		source(argc, argv);
491
		exit(errs != 0);
492
	}
493
1
	if (tflag) {
494
		/* Receive data. */
495
		sink(argc, argv);
496
		exit(errs != 0);
497
	}
498
1
	if (argc < 2)
499
		usage();
500
1
	if (argc > 2)
501
1
		targetshouldbedirectory = 1;
502
503
1
	remin = remout = -1;
504
1
	do_cmd_pid = -1;
505
	/* Command to be executed on remote system using "ssh". */
506
1
	(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
507
1
	    verbose_mode ? " -v" : "",
508
1
	    iamrecursive ? " -r" : "", pflag ? " -p" : "",
509
1
	    targetshouldbedirectory ? " -d" : "");
510
511
1
	(void) signal(SIGPIPE, lostconn);
512
513
1
	if ((targ = colon(argv[argc - 1])))	/* Dest is remote host. */
514
1
		toremote(targ, argc, argv);
515
	else {
516
		if (targetshouldbedirectory)
517
			verifydir(argv[argc - 1]);
518
		tolocal(argc, argv);	/* Dest is local host. */
519
	}
520
	/*
521
	 * Finally check the exit status of the ssh process, if one was forked
522
	 * and no error has occurred yet
523
	 */
524
1
	if (do_cmd_pid != -1 && errs == 0) {
525
1
		if (remin != -1)
526
1
		    (void) close(remin);
527
1
		if (remout != -1)
528
1
		    (void) close(remout);
529
1
		if (waitpid(do_cmd_pid, &status, 0) == -1)
530
			errs = 1;
531
		else {
532

2
			if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
533
				errs = 1;
534
		}
535
	}
536
	exit(errs != 0);
537
}
538
539
/* Callback from atomicio6 to update progress meter and limit bandwidth */
540
static int
541
scpio(void *_cnt, size_t s)
542
{
543
316768
	off_t *cnt = (off_t *)_cnt;
544
545
158384
	*cnt += s;
546
158384
	if (limit_kbps > 0)
547
		bandwidth_limit(&bwlimit, s);
548
158384
	return 0;
549
}
550
551
static int
552
do_times(int fd, int verb, const struct stat *sb)
553
{
554
	/* strlen(2^64) == 20; strlen(10^6) == 7 */
555
	char buf[(20 + 7 + 2) * 2 + 2];
556
557
	(void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
558
	    (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
559
	    (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
560
	if (verb) {
561
		fprintf(stderr, "File mtime %lld atime %lld\n",
562
		    (long long)sb->st_mtime, (long long)sb->st_atime);
563
		fprintf(stderr, "Sending file timestamps: %s", buf);
564
	}
565
	(void) atomicio(vwrite, fd, buf, strlen(buf));
566
	return (response());
567
}
568
569
void
570
toremote(char *targ, int argc, char **argv)
571
{
572
2
	char *bp, *host, *src, *suser, *thost, *tuser, *arg;
573
1
	arglist alist;
574
	int i;
575
	u_int j;
576
577
1
	memset(&alist, '\0', sizeof(alist));
578
1
	alist.list = NULL;
579
580
1
	*targ++ = 0;
581
1
	if (*targ == 0)
582
		targ = ".";
583
584
1
	arg = xstrdup(argv[argc - 1]);
585
1
	if ((thost = strrchr(arg, '@'))) {
586
		/* user@host */
587
1
		*thost++ = 0;
588
		tuser = arg;
589
1
		if (*tuser == '\0')
590
			tuser = NULL;
591
1
	} else {
592
		thost = arg;
593
		tuser = NULL;
594
	}
595
596

2
	if (tuser != NULL && !okname(tuser)) {
597
		free(arg);
598
		return;
599
	}
600
601
9496
	for (i = 0; i < argc - 1; i++) {
602
4747
		src = colon(argv[i]);
603
4747
		if (src && throughlocal) {	/* extended remote to remote */
604
			*src++ = 0;
605
			if (*src == 0)
606
				src = ".";
607
			host = strrchr(argv[i], '@');
608
			if (host) {
609
				*host++ = 0;
610
				host = cleanhostname(host);
611
				suser = argv[i];
612
				if (*suser == '\0')
613
					suser = pwd->pw_name;
614
				else if (!okname(suser))
615
					continue;
616
			} else {
617
				host = cleanhostname(argv[i]);
618
				suser = NULL;
619
			}
620
			xasprintf(&bp, "%s -f %s%s", cmd,
621
			    *src == '-' ? "-- " : "", src);
622
			if (do_cmd(host, suser, bp, &remin, &remout) < 0)
623
				exit(1);
624
			free(bp);
625
			host = cleanhostname(thost);
626
			xasprintf(&bp, "%s -t %s%s", cmd,
627
			    *targ == '-' ? "-- " : "", targ);
628
			if (do_cmd2(host, tuser, bp, remin, remout) < 0)
629
				exit(1);
630
			free(bp);
631
			(void) close(remin);
632
			(void) close(remout);
633
			remin = remout = -1;
634
4747
		} else if (src) {	/* standard remote to remote */
635
			freeargs(&alist);
636
			addargs(&alist, "%s", ssh_program);
637
			addargs(&alist, "-x");
638
			addargs(&alist, "-oClearAllForwardings=yes");
639
			addargs(&alist, "-n");
640
			for (j = 0; j < remote_remote_args.num; j++) {
641
				addargs(&alist, "%s",
642
				    remote_remote_args.list[j]);
643
			}
644
			*src++ = 0;
645
			if (*src == 0)
646
				src = ".";
647
			host = strrchr(argv[i], '@');
648
649
			if (host) {
650
				*host++ = 0;
651
				host = cleanhostname(host);
652
				suser = argv[i];
653
				if (*suser == '\0')
654
					suser = pwd->pw_name;
655
				else if (!okname(suser))
656
					continue;
657
				addargs(&alist, "-l");
658
				addargs(&alist, "%s", suser);
659
			} else {
660
				host = cleanhostname(argv[i]);
661
			}
662
			addargs(&alist, "--");
663
			addargs(&alist, "%s", host);
664
			addargs(&alist, "%s", cmd);
665
			addargs(&alist, "%s", src);
666
			addargs(&alist, "%s%s%s:%s",
667
			    tuser ? tuser : "", tuser ? "@" : "",
668
			    thost, targ);
669
			if (do_local_cmd(&alist) != 0)
670
				errs = 1;
671
		} else {	/* local to remote */
672
4747
			if (remin == -1) {
673
1
				xasprintf(&bp, "%s -t %s%s", cmd,
674
1
				    *targ == '-' ? "-- " : "", targ);
675
1
				host = cleanhostname(thost);
676
2
				if (do_cmd(host, tuser, bp, &remin,
677
1
				    &remout) < 0)
678
					exit(1);
679
1
				if (response() < 0)
680
					exit(1);
681
1
				free(bp);
682
1
			}
683
4747
			source(1, argv + i);
684
		}
685
	}
686
1
	free(arg);
687
2
}
688
689
void
690
tolocal(int argc, char **argv)
691
{
692
	char *bp, *host, *src, *suser;
693
	arglist alist;
694
	int i;
695
696
	memset(&alist, '\0', sizeof(alist));
697
	alist.list = NULL;
698
699
	for (i = 0; i < argc - 1; i++) {
700
		if (!(src = colon(argv[i]))) {	/* Local to local. */
701
			freeargs(&alist);
702
			addargs(&alist, "%s", _PATH_CP);
703
			if (iamrecursive)
704
				addargs(&alist, "-r");
705
			if (pflag)
706
				addargs(&alist, "-p");
707
			addargs(&alist, "--");
708
			addargs(&alist, "%s", argv[i]);
709
			addargs(&alist, "%s", argv[argc-1]);
710
			if (do_local_cmd(&alist))
711
				++errs;
712
			continue;
713
		}
714
		*src++ = 0;
715
		if (*src == 0)
716
			src = ".";
717
		if ((host = strrchr(argv[i], '@')) == NULL) {
718
			host = argv[i];
719
			suser = NULL;
720
		} else {
721
			*host++ = 0;
722
			suser = argv[i];
723
			if (*suser == '\0')
724
				suser = pwd->pw_name;
725
		}
726
		host = cleanhostname(host);
727
		xasprintf(&bp, "%s -f %s%s",
728
		    cmd, *src == '-' ? "-- " : "", src);
729
		if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
730
			free(bp);
731
			++errs;
732
			continue;
733
		}
734
		free(bp);
735
		sink(1, argv + argc - 1);
736
		(void) close(remin);
737
		remin = remout = -1;
738
	}
739
}
740
741
void
742
source(int argc, char **argv)
743
{
744
9502
	struct stat stb;
745
	static BUF buffer;
746
	BUF *bp;
747
4751
	off_t i, statbytes;
748
	size_t amt, nr;
749
	int fd = -1, haderr, indx;
750
4751
	char *last, *name, buf[2048], encname[PATH_MAX];
751
	int len;
752
753
44450
	for (indx = 0; indx < argc; ++indx) {
754
17474
		name = argv[indx];
755
17474
		statbytes = 0;
756
17474
		len = strlen(name);
757

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

34953
	switch (resp) {
1214
	case 0:		/* ok */
1215
34953
		return (0);
1216
	default:
1217
		*cp++ = resp;
1218
		/* FALLTHROUGH */
1219
	case 1:		/* error, followed by error msg */
1220
	case 2:		/* fatal error, "" */
1221
		do {
1222
			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
1223
				lostconn(0);
1224
			*cp++ = ch;
1225
		} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
1226
1227
		if (!iamremote) {
1228
			cp[-1] = '\0';
1229
			(void) snmprintf(visbuf, sizeof(visbuf),
1230
			    NULL, "%s\n", rbuf);
1231
			(void) atomicio(vwrite, STDERR_FILENO,
1232
			    visbuf, strlen(visbuf));
1233
		}
1234
		++errs;
1235
		if (resp == 1)
1236
			return (-1);
1237
		exit(1);
1238
	}
1239
	/* NOTREACHED */
1240
34953
}
1241
1242
void
1243
usage(void)
1244
{
1245
	(void) fprintf(stderr,
1246
	    "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1247
	    "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
1248
	    "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
1249
	exit(1);
1250
}
1251
1252
void
1253
run_err(const char *fmt,...)
1254
{
1255
	static FILE *fp;
1256
	va_list ap;
1257
1258
	++errs;
1259
	if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
1260
		(void) fprintf(fp, "%c", 0x01);
1261
		(void) fprintf(fp, "scp: ");
1262
		va_start(ap, fmt);
1263
		(void) vfprintf(fp, fmt, ap);
1264
		va_end(ap);
1265
		(void) fprintf(fp, "\n");
1266
		(void) fflush(fp);
1267
	}
1268
1269
	if (!iamremote) {
1270
		va_start(ap, fmt);
1271
		vfmprintf(stderr, fmt, ap);
1272
		va_end(ap);
1273
		fprintf(stderr, "\n");
1274
	}
1275
}
1276
1277
void
1278
verifydir(char *cp)
1279
{
1280
	struct stat stb;
1281
1282
	if (!stat(cp, &stb)) {
1283
		if (S_ISDIR(stb.st_mode))
1284
			return;
1285
		errno = ENOTDIR;
1286
	}
1287
	run_err("%s: %s", cp, strerror(errno));
1288
	killchild(0);
1289
}
1290
1291
int
1292
okname(char *cp0)
1293
{
1294
	int c;
1295
	char *cp;
1296
1297
	cp = cp0;
1298
2
	do {
1299
7
		c = (int)*cp;
1300
7
		if (c & 0200)
1301
			goto bad;
1302

7
		if (!isalpha(c) && !isdigit((unsigned char)c)) {
1303
			switch (c) {
1304
			case '\'':
1305
			case '"':
1306
			case '`':
1307
			case ' ':
1308
			case '#':
1309
				goto bad;
1310
			default:
1311
				break;
1312
			}
1313
		}
1314
7
	} while (*++cp);
1315
1
	return (1);
1316
1317
bad:	fmprintf(stderr, "%s: invalid user name\n", cp0);
1318
	return (0);
1319
1
}
1320
1321
BUF *
1322
allocbuf(BUF *bp, int fd, int blksize)
1323
{
1324
	size_t size;
1325
34948
	struct stat stb;
1326
1327
17474
	if (fstat(fd, &stb) < 0) {
1328
		run_err("fstat: %s", strerror(errno));
1329
		return (0);
1330
	}
1331
17474
	size = ROUNDUP(stb.st_blksize, blksize);
1332
17474
	if (size == 0)
1333
		size = blksize;
1334
17474
	if (bp->cnt >= size)
1335
17469
		return (bp);
1336
5
	bp->buf = xrecallocarray(bp->buf, bp->cnt, size, 1);
1337
5
	bp->cnt = size;
1338
5
	return (bp);
1339
17474
}
1340
1341
void
1342
lostconn(int signo)
1343
{
1344
	if (!iamremote)
1345
		(void)write(STDERR_FILENO, "lost connection\n", 16);
1346
	if (signo)
1347
		_exit(1);
1348
	else
1349
		exit(1);
1350
}