GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rdistd/server.c Lines: 0 785 0.0 %
Date: 2017-11-13 Branches: 0 563 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: server.c,v 1.43 2017/08/30 07:43:52 otto Exp $	*/
2
3
/*
4
 * Copyright (c) 1983 Regents of the University of California.
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 * 3. Neither the name of the University nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include <ctype.h>
33
#include <dirent.h>
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <grp.h>
37
#include <limits.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <time.h>
42
#include <unistd.h>
43
44
#include "server.h"
45
46
/*
47
 * Server routines
48
 */
49
50
char	tempname[sizeof _RDIST_TMP + 1]; /* Tmp file name */
51
char	buf[BUFSIZ];		/* general purpose buffer */
52
char	target[PATH_MAX];	/* target/source directory name */
53
char	*ptarget;		/* pointer to end of target name */
54
int	catname = 0;		/* cat name to target name */
55
char	*sptarget[32];		/* stack of saved ptarget's for directories */
56
char   *fromhost = NULL;	/* Client hostname */
57
static int64_t min_freespace = 0; /* Minimium free space on a filesystem */
58
static int64_t min_freefiles = 0; /* Minimium free # files on a filesystem */
59
int	oumask;			/* Old umask */
60
61
static int cattarget(char *);
62
static int setownership(char *, int, uid_t, gid_t, int);
63
static int setfilemode(char *, int, int, int);
64
static int fchog(int, char *, char *, char *, int);
65
static int removefile(struct stat *, int);
66
static void doclean(char *);
67
static void clean(char *);
68
static void dospecial(char *);
69
static void docmdspecial(void);
70
static void query(char *);
71
static int chkparent(char *, opt_t);
72
static char *savetarget(char *, opt_t);
73
static void recvfile(char *, opt_t, int, char *, char *, time_t, time_t, off_t);
74
static void recvdir(opt_t, int, char *, char *);
75
static void recvlink(char *, opt_t, int, off_t);
76
static void hardlink(char *);
77
static void setconfig(char *);
78
static void recvit(char *, int);
79
static void dochmog(char *);
80
static void settarget(char *, int);
81
82
/*
83
 * Cat "string" onto the target buffer with error checking.
84
 */
85
static int
86
cattarget(char *string)
87
{
88
	if (strlen(string) + strlen(target) + 2 > sizeof(target)) {
89
		message(MT_INFO, "target buffer is not large enough.");
90
		return(-1);
91
	}
92
	if (!ptarget) {
93
		message(MT_INFO, "NULL target pointer set.");
94
		return(-10);
95
	}
96
97
	(void) snprintf(ptarget, sizeof(target) - (ptarget - target),
98
			"/%s", string);
99
100
	return(0);
101
}
102
103
/*
104
 * Set uid and gid ownership of a file.
105
 */
106
static int
107
setownership(char *file, int fd, uid_t uid, gid_t gid, int islink)
108
{
109
	static int is_root = -1;
110
	int status = -1;
111
112
	/*
113
	 * We assume only the Superuser can change uid ownership.
114
	 */
115
	switch (is_root) {
116
	case -1:
117
		is_root = getuid() == 0;
118
		if (is_root)
119
			break;
120
		/* FALLTHROUGH */
121
	case 0:
122
		uid = -1;
123
		break;
124
	case 1:
125
		break;
126
	}
127
128
	if (fd != -1 && !islink)
129
		status = fchown(fd, uid, gid);
130
	else
131
		status = fchownat(AT_FDCWD, file, uid, gid,
132
		    AT_SYMLINK_NOFOLLOW);
133
134
	if (status < 0) {
135
		if (uid == (uid_t)-1)
136
			message(MT_NOTICE, "%s: chgrp %d failed: %s",
137
				target, gid, SYSERR);
138
		else
139
			message(MT_NOTICE, "%s: chown %d:%d failed: %s",
140
				target, uid, gid, SYSERR);
141
		return(-1);
142
	}
143
144
	return(0);
145
}
146
147
/*
148
 * Set mode of a file
149
 */
150
static int
151
setfilemode(char *file, int fd, int mode, int islink)
152
{
153
	int status = -1;
154
155
	if (mode == -1)
156
		return(0);
157
158
	if (islink)
159
		status = fchmodat(AT_FDCWD, file, mode, AT_SYMLINK_NOFOLLOW);
160
161
	if (fd != -1 && !islink)
162
		status = fchmod(fd, mode);
163
164
	if (status < 0 && !islink)
165
		status = chmod(file, mode);
166
167
	if (status < 0) {
168
		message(MT_NOTICE, "%s: chmod failed: %s", target, SYSERR);
169
		return(-1);
170
	}
171
172
	return(0);
173
}
174
/*
175
 * Change owner, group and mode of file.
176
 */
177
static int
178
fchog(int fd, char *file, char *owner, char *group, int mode)
179
{
180
	static struct group *gr = NULL;
181
	int i;
182
	struct stat st;
183
	uid_t uid;
184
	gid_t gid;
185
	gid_t primegid = (gid_t)-2;
186
187
	uid = userid;
188
	if (userid == 0) {	/* running as root; take anything */
189
		if (*owner == ':') {
190
			uid = (uid_t) atoi(owner + 1);
191
		} else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
192
			if ((pw = getpwnam(owner)) == NULL) {
193
				if (mode != -1 && IS_ON(mode, S_ISUID)) {
194
					message(MT_NOTICE,
195
			      "%s: unknown login name \"%s\", clearing setuid",
196
						target, owner);
197
					mode &= ~S_ISUID;
198
					uid = 0;
199
				} else
200
					message(MT_NOTICE,
201
					"%s: unknown login name \"%s\"",
202
						target, owner);
203
			} else
204
				uid = pw->pw_uid;
205
		} else {
206
			uid = pw->pw_uid;
207
			primegid = pw->pw_gid;
208
		}
209
		if (*group == ':') {
210
			gid = (gid_t)atoi(group + 1);
211
			goto ok;
212
		}
213
	} else {	/* not root, setuid only if user==owner */
214
		struct passwd *lupw;
215
216
		if (mode != -1) {
217
			if (IS_ON(mode, S_ISUID) &&
218
			    strcmp(locuser, owner) != 0)
219
				mode &= ~S_ISUID;
220
			if (mode)
221
				mode &= ~S_ISVTX; /* and strip sticky too */
222
		}
223
224
		if ((lupw = getpwnam(locuser)) != NULL)
225
			primegid = lupw->pw_gid;
226
	}
227
228
	gid = (gid_t)-1;
229
	if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
230
		if ((*group == ':' &&
231
		     (getgrgid(gid = atoi(group + 1)) == NULL))
232
		    || ((gr = (struct group *)getgrnam(group)) == NULL)) {
233
			if (mode != -1 && IS_ON(mode, S_ISGID)) {
234
				message(MT_NOTICE,
235
				"%s: unknown group \"%s\", clearing setgid",
236
					target, group);
237
				mode &= ~S_ISGID;
238
			} else
239
				message(MT_NOTICE,
240
					"%s: unknown group \"%s\"",
241
					target, group);
242
		} else
243
			gid = gr->gr_gid;
244
	} else
245
		gid = gr->gr_gid;
246
247
	if (userid && gid != (gid_t)-1 && gid != primegid) {
248
		if (gr)
249
			for (i = 0; gr->gr_mem[i] != NULL; i++)
250
				if (strcmp(locuser, gr->gr_mem[i]) == 0)
251
					goto ok;
252
		if (mode != -1 && IS_ON(mode, S_ISGID)) {
253
			message(MT_NOTICE,
254
				"%s: user %s not in group %s, clearing setgid",
255
				target, locuser, group);
256
			mode &= ~S_ISGID;
257
		}
258
		gid = (gid_t)-1;
259
	}
260
ok:
261
	if (stat(file, &st) == -1) {
262
		error("%s: Stat failed %s", file, SYSERR);
263
		return -1;
264
	}
265
	/*
266
	 * Set uid and gid ownership.  If that fails, strip setuid and
267
	 * setgid bits from mode.  Once ownership is set, successful
268
	 * or otherwise, set the new file mode.
269
	 */
270
	if (setownership(file, fd, uid, gid, S_ISLNK(st.st_mode)) < 0) {
271
		if (mode != -1 && IS_ON(mode, S_ISUID)) {
272
			message(MT_NOTICE,
273
				"%s: chown failed, clearing setuid", target);
274
			mode &= ~S_ISUID;
275
		}
276
		if (mode != -1 && IS_ON(mode, S_ISGID)) {
277
			message(MT_NOTICE,
278
				"%s: chown failed, clearing setgid", target);
279
			mode &= ~S_ISGID;
280
		}
281
	}
282
	(void) setfilemode(file, fd, mode, S_ISLNK(st.st_mode));
283
284
285
	return(0);
286
}
287
288
/*
289
 * Remove a file or directory (recursively) and send back an acknowledge
290
 * or an error message.
291
 */
292
static int
293
removefile(struct stat *statb, int silent)
294
{
295
	DIR *d;
296
	static struct dirent *dp;
297
	char *cp;
298
	struct stat stb;
299
	char *optarget;
300
	int len, failures = 0;
301
302
	switch (statb->st_mode & S_IFMT) {
303
	case S_IFREG:
304
	case S_IFLNK:
305
	case S_IFCHR:
306
	case S_IFBLK:
307
	case S_IFSOCK:
308
	case S_IFIFO:
309
		if (unlink(target) < 0) {
310
			if (errno == ETXTBSY) {
311
				if (!silent)
312
					message(MT_REMOTE|MT_NOTICE,
313
						"%s: unlink failed: %s",
314
						target, SYSERR);
315
				return(0);
316
			} else {
317
				error("%s: unlink failed: %s", target, SYSERR);
318
				return(-1);
319
			}
320
		}
321
		goto removed;
322
323
	case S_IFDIR:
324
		break;
325
326
	default:
327
		error("%s: not a plain file", target);
328
		return(-1);
329
	}
330
331
	errno = 0;
332
	if ((d = opendir(target)) == NULL) {
333
		error("%s: opendir failed: %s", target, SYSERR);
334
		return(-1);
335
	}
336
337
	optarget = ptarget;
338
	len = ptarget - target;
339
	while ((dp = readdir(d)) != NULL) {
340
		if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
341
		    (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
342
			continue;
343
344
		if (len + 1 + (int)strlen(dp->d_name) >= PATH_MAX - 1) {
345
			if (!silent)
346
				message(MT_REMOTE|MT_WARNING,
347
					"%s/%s: Name too long",
348
					target, dp->d_name);
349
			continue;
350
		}
351
		ptarget = optarget;
352
		*ptarget++ = '/';
353
		cp = dp->d_name;
354
		while ((*ptarget++ = *cp++) != '\0')
355
			continue;
356
		ptarget--;
357
		if (lstat(target, &stb) < 0) {
358
			if (!silent)
359
				message(MT_REMOTE|MT_WARNING,
360
					"%s: lstat failed: %s",
361
					target, SYSERR);
362
			continue;
363
		}
364
		if (removefile(&stb, 0) < 0)
365
			++failures;
366
	}
367
	(void) closedir(d);
368
	ptarget = optarget;
369
	*ptarget = CNULL;
370
371
	if (failures)
372
		return(-1);
373
374
	if (rmdir(target) < 0) {
375
		error("%s: rmdir failed: %s", target, SYSERR);
376
		return(-1);
377
	}
378
removed:
379
#if NEWWAY
380
	if (!silent)
381
		message(MT_CHANGE|MT_REMOTE, "%s: removed", target);
382
#else
383
	/*
384
	 * We use MT_NOTICE instead of MT_CHANGE because this function is
385
	 * sometimes called by other functions that are suppose to return a
386
	 * single ack() back to the client (rdist).  This is a kludge until
387
	 * the Rdist protocol is re-done.  Sigh.
388
	 */
389
	message(MT_NOTICE|MT_REMOTE, "%s: removed", target);
390
#endif
391
	return(0);
392
}
393
394
/*
395
 * Check the current directory (initialized by the 'T' command to server())
396
 * for extraneous files and remove them.
397
 */
398
static void
399
doclean(char *cp)
400
{
401
	DIR *d;
402
	struct dirent *dp;
403
	struct stat stb;
404
	char *optarget, *ep;
405
	int len;
406
	opt_t opts;
407
	char targ[PATH_MAX*4];
408
409
	opts = strtol(cp, &ep, 8);
410
	if (*ep != CNULL) {
411
		error("clean: options not delimited");
412
		return;
413
	}
414
	if ((d = opendir(target)) == NULL) {
415
		error("%s: opendir failed: %s", target, SYSERR);
416
		return;
417
	}
418
	ack();
419
420
	optarget = ptarget;
421
	len = ptarget - target;
422
	while ((dp = readdir(d)) != NULL) {
423
		if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
424
		    (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
425
			continue;
426
427
		if (len + 1 + (int)strlen(dp->d_name) >= PATH_MAX - 1) {
428
			message(MT_REMOTE|MT_WARNING, "%s/%s: Name too long",
429
				target, dp->d_name);
430
			continue;
431
		}
432
		ptarget = optarget;
433
		*ptarget++ = '/';
434
		cp = dp->d_name;
435
		while ((*ptarget++ = *cp++) != '\0')
436
			continue;
437
		ptarget--;
438
		if (lstat(target, &stb) < 0) {
439
			message(MT_REMOTE|MT_WARNING, "%s: lstat failed: %s",
440
				target, SYSERR);
441
			continue;
442
		}
443
444
		ENCODE(targ, dp->d_name);
445
		(void) sendcmd(CC_QUERY, "%s", targ);
446
		(void) remline(cp = buf, sizeof(buf), TRUE);
447
448
		if (*cp != CC_YES)
449
			continue;
450
451
		if (IS_ON(opts, DO_VERIFY))
452
			message(MT_REMOTE|MT_INFO, "%s: need to remove",
453
				target);
454
		else
455
			(void) removefile(&stb, 0);
456
	}
457
	(void) closedir(d);
458
459
	ptarget = optarget;
460
	*ptarget = CNULL;
461
}
462
463
/*
464
 * Frontend to doclean().
465
 */
466
static void
467
clean(char *cp)
468
{
469
	doclean(cp);
470
	(void) sendcmd(CC_END, NULL);
471
	(void) response();
472
}
473
474
/*
475
 * Execute a shell command to handle special cases.
476
 * We can't really set an alarm timeout here since we
477
 * have no idea how long the command should take.
478
 */
479
static void
480
dospecial(char *xcmd)
481
{
482
	char cmd[BUFSIZ];
483
	if (DECODE(cmd, xcmd) == -1) {
484
		error("dospecial: Cannot decode command.");
485
		return;
486
	}
487
	runcommand(cmd);
488
}
489
490
/*
491
 * Do a special cmd command.  This differs from normal special
492
 * commands in that it's done after an entire command has been updated.
493
 * The list of updated target files is sent one at a time with RC_FILE
494
 * commands.  Each one is added to an environment variable defined by
495
 * E_FILES.  When an RC_COMMAND is finally received, the E_FILES variable
496
 * is stuffed into our environment and a normal dospecial() command is run.
497
 */
498
static void
499
docmdspecial(void)
500
{
501
	char *cp;
502
	char *cmd, *env = NULL;
503
	int n;
504
	size_t len;
505
506
	/* We're ready */
507
	ack();
508
509
	for ( ; ; ) {
510
		n = remline(cp = buf, sizeof(buf), FALSE);
511
		if (n <= 0) {
512
			error("cmdspecial: premature end of input.");
513
			return;
514
		}
515
516
		switch (*cp++) {
517
		case RC_FILE:
518
			if (env == NULL) {
519
				len = (2 * sizeof(E_FILES)) + strlen(cp) + 10;
520
				env = xmalloc(len);
521
				(void) snprintf(env, len, "export %s;%s=%s",
522
					       E_FILES, E_FILES, cp);
523
			} else {
524
				len = strlen(env) + 1 + strlen(cp) + 1;
525
				env = xrealloc(env, len);
526
				(void) strlcat(env, ":", len);
527
				(void) strlcat(env, cp, len);
528
			}
529
			ack();
530
			break;
531
532
		case RC_COMMAND:
533
			if (env) {
534
				len = strlen(env) + 1 + strlen(cp) + 1;
535
				env = xrealloc(env, len);
536
				(void) strlcat(env, ";", len);
537
				(void) strlcat(env, cp, len);
538
				cmd = env;
539
			} else
540
				cmd = cp;
541
542
			dospecial(cmd);
543
			if (env)
544
				(void) free(env);
545
			return;
546
547
		default:
548
			error("Unknown cmdspecial command '%s'.", cp);
549
			return;
550
		}
551
	}
552
}
553
554
/*
555
 * Query. Check to see if file exists. Return one of the following:
556
 *
557
 *  QC_ONNFS		- resides on a NFS
558
 *  QC_ONRO		- resides on a Read-Only filesystem
559
 *  QC_NO		- doesn't exist
560
 *  QC_YESsize mtime 	- exists and its a regular file (size & mtime of file)
561
 *  QC_YES		- exists and its a directory or symbolic link
562
 *  QC_ERRMSGmessage 	- error message
563
 */
564
static void
565
query(char *xname)
566
{
567
	static struct stat stb;
568
	int s = -1, stbvalid = 0;
569
	char name[PATH_MAX];
570
571
	if (DECODE(name, xname) == -1) {
572
		error("query: Cannot decode filename");
573
		return;
574
	}
575
576
	if (catname && cattarget(name) < 0)
577
		return;
578
579
	if (IS_ON(options, DO_CHKNFS)) {
580
		s = is_nfs_mounted(target, &stb, &stbvalid);
581
		if (s > 0)
582
			(void) sendcmd(QC_ONNFS, NULL);
583
584
		/* Either the above check was true or an error occurred */
585
		/* and is_nfs_mounted sent the error message */
586
		if (s != 0) {
587
			*ptarget = CNULL;
588
			return;
589
		}
590
	}
591
592
	if (IS_ON(options, DO_CHKREADONLY)) {
593
		s = is_ro_mounted(target, &stb, &stbvalid);
594
		if (s > 0)
595
			(void) sendcmd(QC_ONRO, NULL);
596
597
		/* Either the above check was true or an error occurred */
598
		/* and is_ro_mounted sent the error message */
599
		if (s != 0) {
600
			*ptarget = CNULL;
601
			return;
602
		}
603
	}
604
605
	if (IS_ON(options, DO_CHKSYM)) {
606
		if (is_symlinked(target, &stb, &stbvalid) > 0) {
607
			(void) sendcmd(QC_SYM, NULL);
608
			return;
609
		}
610
	}
611
612
	/*
613
	 * If stbvalid is false, "stb" is not valid because the stat()
614
	 * by is_*_mounted() either failed or does not match "target".
615
	 */
616
	if (!stbvalid && lstat(target, &stb) < 0) {
617
		if (errno == ENOENT)
618
			(void) sendcmd(QC_NO, NULL);
619
		else
620
			error("%s: lstat failed: %s", target, SYSERR);
621
		*ptarget = CNULL;
622
		return;
623
	}
624
625
	switch (stb.st_mode & S_IFMT) {
626
	case S_IFLNK:
627
	case S_IFDIR:
628
	case S_IFREG:
629
		(void) sendcmd(QC_YES, "%lld %lld %o %s %s",
630
			       (long long) stb.st_size,
631
			       (long long) stb.st_mtime,
632
			       stb.st_mode & 07777,
633
			       getusername(stb.st_uid, target, options),
634
			       getgroupname(stb.st_gid, target, options));
635
		break;
636
637
	default:
638
		error("%s: not a file or directory", target);
639
		break;
640
	}
641
	*ptarget = CNULL;
642
}
643
644
/*
645
 * Check to see if parent directory exists and create one if not.
646
 */
647
static int
648
chkparent(char *name, opt_t opts)
649
{
650
	char *cp;
651
	struct stat stb;
652
	int r = -1;
653
654
	debugmsg(DM_CALL, "chkparent(%s, %#x) start\n", name, opts);
655
656
	cp = strrchr(name, '/');
657
	if (cp == NULL || cp == name)
658
		return(0);
659
660
	*cp = CNULL;
661
662
	if (lstat(name, &stb) < 0) {
663
		if (errno == ENOENT && chkparent(name, opts) >= 0) {
664
			if (mkdir(name, 0777 & ~oumask) == 0) {
665
				message(MT_NOTICE, "%s: mkdir", name);
666
				r = 0;
667
			} else
668
				debugmsg(DM_MISC,
669
					 "chkparent(%s, %#04o) mkdir fail: %s\n",
670
					 name, opts, SYSERR);
671
		}
672
	} else	/* It exists */
673
		r = 0;
674
675
	/* Put back what we took away */
676
	*cp = '/';
677
678
	return(r);
679
}
680
681
/*
682
 * Save a copy of 'file' by renaming it.
683
 */
684
static char *
685
savetarget(char *file, opt_t opts)
686
{
687
	static char savefile[PATH_MAX];
688
689
	if (strlen(file) + sizeof(SAVE_SUFFIX) + 1 > PATH_MAX) {
690
		error("%s: Cannot save: Save name too long", file);
691
		return(NULL);
692
	}
693
694
	if (IS_ON(opts, DO_HISTORY)) {
695
		int i;
696
		struct stat st;
697
		/*
698
		 * There is a race here, but the worst that can happen
699
		 * is to lose a version of the file
700
		 */
701
		for (i = 1; i < 1000; i++) {
702
			(void) snprintf(savefile, sizeof(savefile),
703
					"%s;%.3d", file, i);
704
			if (lstat(savefile, &st) == -1 && errno == ENOENT)
705
				break;
706
707
		}
708
		if (i == 1000) {
709
			message(MT_NOTICE,
710
			    "%s: More than 1000 versions for %s; reusing 1\n",
711
				savefile, SYSERR);
712
			i = 1;
713
			(void) snprintf(savefile, sizeof(savefile),
714
					"%s;%.3d", file, i);
715
		}
716
	}
717
	else {
718
		(void) snprintf(savefile, sizeof(savefile), "%s%s",
719
				file, SAVE_SUFFIX);
720
721
		if (unlink(savefile) != 0 && errno != ENOENT) {
722
			message(MT_NOTICE, "%s: remove failed: %s",
723
				savefile, SYSERR);
724
			return(NULL);
725
		}
726
	}
727
728
	if (rename(file, savefile) != 0 && errno != ENOENT) {
729
		error("%s -> %s: rename failed: %s",
730
		      file, savefile, SYSERR);
731
		return(NULL);
732
	}
733
734
	return(savefile);
735
}
736
737
/*
738
 * Receive a file
739
 */
740
static void
741
recvfile(char *new, opt_t opts, int mode, char *owner, char *group,
742
	 time_t mtime, time_t atime, off_t size)
743
{
744
	int f, wrerr, olderrno;
745
	off_t i;
746
	char *cp;
747
	char *savefile = NULL;
748
	static struct stat statbuff;
749
750
	/*
751
	 * Create temporary file
752
	 */
753
	if (chkparent(new, opts) < 0 || (f = mkstemp(new)) < 0) {
754
		error("%s: create failed: %s", new, SYSERR);
755
		return;
756
	}
757
758
	/*
759
	 * Receive the file itself
760
	 */
761
	ack();
762
	wrerr = 0;
763
	olderrno = 0;
764
	for (i = 0; i < size; i += BUFSIZ) {
765
		off_t amt = BUFSIZ;
766
767
		cp = buf;
768
		if (i + amt > size)
769
			amt = size - i;
770
		do {
771
			ssize_t j;
772
773
			j = readrem(cp, amt);
774
			if (j <= 0) {
775
				(void) close(f);
776
				(void) unlink(new);
777
				fatalerr(
778
				   "Read error occurred while receiving file.");
779
				finish();
780
			}
781
			amt -= j;
782
			cp += j;
783
		} while (amt > 0);
784
		amt = BUFSIZ;
785
		if (i + amt > size)
786
			amt = size - i;
787
		if (wrerr == 0 && xwrite(f, buf, amt) != amt) {
788
			olderrno = errno;
789
			wrerr++;
790
		}
791
	}
792
793
	if (response() < 0) {
794
		(void) close(f);
795
		(void) unlink(new);
796
		return;
797
	}
798
799
	if (wrerr) {
800
		error("%s: Write error: %s", new, strerror(olderrno));
801
		(void) close(f);
802
		(void) unlink(new);
803
		return;
804
	}
805
806
	/*
807
	 * Do file comparison if enabled
808
	 */
809
	if (IS_ON(opts, DO_COMPARE)) {
810
		FILE *f1, *f2;
811
		int c;
812
813
		errno = 0;	/* fopen is not a syscall */
814
		if ((f1 = fopen(target, "r")) == NULL) {
815
			error("%s: open for read failed: %s", target, SYSERR);
816
			(void) close(f);
817
			(void) unlink(new);
818
			return;
819
		}
820
		errno = 0;
821
		if ((f2 = fopen(new, "r")) == NULL) {
822
			error("%s: open for read failed: %s", new, SYSERR);
823
			(void) fclose(f1);
824
			(void) close(f);
825
			(void) unlink(new);
826
			return;
827
		}
828
		while ((c = getc(f1)) == getc(f2))
829
			if (c == EOF) {
830
				debugmsg(DM_MISC,
831
					 "Files are the same '%s' '%s'.",
832
					 target, new);
833
				(void) fclose(f1);
834
				(void) fclose(f2);
835
				(void) close(f);
836
				(void) unlink(new);
837
				/*
838
				 * This isn't an error per-se, but we
839
				 * need to indicate to the master that
840
				 * the file was not updated.
841
				 */
842
				error(NULL);
843
				return;
844
			}
845
		debugmsg(DM_MISC, "Files are different '%s' '%s'.",
846
			 target, new);
847
		(void) fclose(f1);
848
		(void) fclose(f2);
849
		if (IS_ON(opts, DO_VERIFY)) {
850
			message(MT_REMOTE|MT_INFO, "%s: need to update",
851
				target);
852
			(void) close(f);
853
			(void) unlink(new);
854
			return;
855
		}
856
	}
857
858
	/*
859
	 * Set owner, group, and file mode
860
	 */
861
	if (fchog(f, new, owner, group, mode) < 0) {
862
		(void) close(f);
863
		(void) unlink(new);
864
		return;
865
	}
866
	(void) close(f);
867
868
	/*
869
	 * Perform utimes() after file is closed to make
870
	 * certain OS's, such as NeXT 2.1, happy.
871
	 */
872
	if (setfiletime(new, time(NULL), mtime) < 0)
873
		message(MT_NOTICE, "%s: utimes failed: %s", new, SYSERR);
874
875
	/*
876
	 * Try to save target file from being over-written
877
	 */
878
	if (IS_ON(opts, DO_SAVETARGETS))
879
		if ((savefile = savetarget(target, opts)) == NULL) {
880
			(void) unlink(new);
881
			return;
882
		}
883
884
	/*
885
	 * If the target is a directory, we need to remove it first
886
	 * before we can rename the new file.
887
	 */
888
	if ((stat(target, &statbuff) == 0) && S_ISDIR(statbuff.st_mode)) {
889
		char *saveptr = ptarget;
890
891
		ptarget = &target[strlen(target)];
892
		removefile(&statbuff, 0);
893
		ptarget = saveptr;
894
	}
895
896
	/*
897
	 * Install new (temporary) file as the actual target
898
	 */
899
	if (rename(new, target) < 0) {
900
		static const char fmt[] = "%s -> %s: rename failed: %s";
901
		struct stat stb;
902
		/*
903
		 * If the rename failed due to "Text file busy", then
904
		 * try to rename the target file and retry the rename.
905
		 */
906
		switch (errno) {
907
		case ETXTBSY:
908
			/* Save the target */
909
			if ((savefile = savetarget(target, opts)) != NULL) {
910
				/* Retry installing new file as target */
911
				if (rename(new, target) < 0) {
912
					error(fmt, new, target, SYSERR);
913
					/* Try to put back save file */
914
					if (rename(savefile, target) < 0)
915
						error(fmt,
916
						      savefile, target, SYSERR);
917
					(void) unlink(new);
918
				} else
919
					message(MT_NOTICE, "%s: renamed to %s",
920
						target, savefile);
921
				/*
922
				 * XXX: We should remove the savefile here.
923
				 *	But we are nice to nfs clients and
924
				 *	we keep it.
925
				 */
926
			}
927
			break;
928
		case EISDIR:
929
			/*
930
			 * See if target is a directory and remove it if it is
931
			 */
932
			if (lstat(target, &stb) == 0) {
933
				if (S_ISDIR(stb.st_mode)) {
934
					char *optarget = ptarget;
935
					for (ptarget = target; *ptarget;
936
						ptarget++);
937
					/* If we failed to remove, we'll catch
938
					   it later */
939
					(void) removefile(&stb, 1);
940
					ptarget = optarget;
941
				}
942
			}
943
			if (rename(new, target) >= 0)
944
				break;
945
			/*FALLTHROUGH*/
946
947
		default:
948
			error(fmt, new, target, SYSERR);
949
			(void) unlink(new);
950
			break;
951
		}
952
	}
953
954
	if (IS_ON(opts, DO_COMPARE))
955
		message(MT_REMOTE|MT_CHANGE, "%s: updated", target);
956
	else
957
		ack();
958
}
959
960
/*
961
 * Receive a directory
962
 */
963
static void
964
recvdir(opt_t opts, int mode, char *owner, char *group)
965
{
966
	static char lowner[100], lgroup[100];
967
	char *cp;
968
	struct stat stb;
969
	int s;
970
971
	s = lstat(target, &stb);
972
	if (s == 0) {
973
		/*
974
		 * If target is not a directory, remove it
975
		 */
976
		if (!S_ISDIR(stb.st_mode)) {
977
			if (IS_ON(opts, DO_VERIFY))
978
				message(MT_NOTICE, "%s: need to remove",
979
					target);
980
			else {
981
				if (unlink(target) < 0) {
982
					error("%s: remove failed: %s",
983
					      target, SYSERR);
984
					return;
985
				}
986
			}
987
			s = -1;
988
			errno = ENOENT;
989
		} else {
990
			if (!IS_ON(opts, DO_NOCHKMODE) &&
991
			    (stb.st_mode & 07777) != mode) {
992
				if (IS_ON(opts, DO_VERIFY))
993
					message(MT_NOTICE,
994
						"%s: need to chmod to %#04o",
995
						target, mode);
996
				else if (chmod(target, mode) != 0)
997
					message(MT_NOTICE,
998
				  "%s: chmod from %#04o to %#04o failed: %s",
999
						target,
1000
						stb.st_mode & 07777,
1001
						mode,
1002
						SYSERR);
1003
				else
1004
					message(MT_NOTICE,
1005
						"%s: chmod from %#04o to %#04o",
1006
						target,
1007
						stb.st_mode & 07777,
1008
						mode);
1009
			}
1010
1011
			/*
1012
			 * Check ownership and set if necessary
1013
			 */
1014
			lowner[0] = CNULL;
1015
			lgroup[0] = CNULL;
1016
1017
			if (!IS_ON(opts, DO_NOCHKOWNER) && owner) {
1018
				int o;
1019
1020
				o = (owner[0] == ':') ? opts & DO_NUMCHKOWNER :
1021
					opts;
1022
				if ((cp = getusername(stb.st_uid, target, o))
1023
				    != NULL)
1024
					if (strcmp(owner, cp))
1025
						(void) strlcpy(lowner, cp,
1026
						    sizeof(lowner));
1027
			}
1028
			if (!IS_ON(opts, DO_NOCHKGROUP) && group) {
1029
				int o;
1030
1031
				o = (group[0] == ':') ? opts & DO_NUMCHKGROUP :
1032
					opts;
1033
				if ((cp = getgroupname(stb.st_gid, target, o))
1034
				    != NULL)
1035
					if (strcmp(group, cp))
1036
						(void) strlcpy(lgroup, cp,
1037
						    sizeof(lgroup));
1038
			}
1039
1040
			/*
1041
			 * Need to set owner and/or group
1042
			 */
1043
#define PRN(n) ((n[0] == ':') ? n+1 : n)
1044
			if (lowner[0] != CNULL || lgroup[0] != CNULL) {
1045
				if (lowner[0] == CNULL &&
1046
				    (cp = getusername(stb.st_uid,
1047
						      target, opts)))
1048
					(void) strlcpy(lowner, cp,
1049
					    sizeof(lowner));
1050
				if (lgroup[0] == CNULL &&
1051
				    (cp = getgroupname(stb.st_gid,
1052
						       target, opts)))
1053
					(void) strlcpy(lgroup, cp,
1054
					    sizeof(lgroup));
1055
1056
				if (IS_ON(opts, DO_VERIFY))
1057
					message(MT_NOTICE,
1058
				"%s: need to chown from %s:%s to %s:%s",
1059
						target,
1060
						PRN(lowner), PRN(lgroup),
1061
						PRN(owner), PRN(group));
1062
				else {
1063
					if (fchog(-1, target, owner,
1064
						  group, -1) == 0)
1065
						message(MT_NOTICE,
1066
					       "%s: chown from %s:%s to %s:%s",
1067
							target,
1068
							PRN(lowner),
1069
							PRN(lgroup),
1070
							PRN(owner),
1071
							PRN(group));
1072
				}
1073
			}
1074
#undef PRN
1075
			ack();
1076
			return;
1077
		}
1078
	}
1079
1080
	if (IS_ON(opts, DO_VERIFY)) {
1081
		ack();
1082
		return;
1083
	}
1084
1085
	/*
1086
	 * Create the directory
1087
	 */
1088
	if (s < 0) {
1089
		if (errno == ENOENT) {
1090
			if (mkdir(target, mode) == 0 ||
1091
			    (chkparent(target, opts) == 0 &&
1092
			    mkdir(target, mode) == 0)) {
1093
				message(MT_NOTICE, "%s: mkdir", target);
1094
				(void) fchog(-1, target, owner, group, mode);
1095
				ack();
1096
			} else {
1097
				error("%s: mkdir failed: %s", target, SYSERR);
1098
				ptarget = sptarget[--catname];
1099
				*ptarget = CNULL;
1100
			}
1101
			return;
1102
		}
1103
	}
1104
	error("%s: lstat failed: %s", target, SYSERR);
1105
	ptarget = sptarget[--catname];
1106
	*ptarget = CNULL;
1107
}
1108
1109
/*
1110
 * Receive a link
1111
 */
1112
static void
1113
recvlink(char *new, opt_t opts, int mode, off_t size)
1114
{
1115
	char tbuf[PATH_MAX], dbuf[BUFSIZ];
1116
	struct stat stb;
1117
	char *optarget;
1118
	int uptodate;
1119
	off_t i;
1120
1121
	/*
1122
	 * Read basic link info
1123
	 */
1124
	ack();
1125
	(void) remline(buf, sizeof(buf), TRUE);
1126
1127
	if (response() < 0) {
1128
		err();
1129
		return;
1130
	}
1131
1132
	if (DECODE(dbuf, buf) == -1) {
1133
		error("recvlink: cannot decode symlink target");
1134
		return;
1135
	}
1136
1137
	uptodate = 0;
1138
	if ((i = readlink(target, tbuf, sizeof(tbuf)-1)) != -1) {
1139
		tbuf[i] = '\0';
1140
		if (i == size && strncmp(dbuf, tbuf, (int) size) == 0)
1141
			uptodate = 1;
1142
	}
1143
	mode &= 0777;
1144
1145
	if (IS_ON(opts, DO_VERIFY) || uptodate) {
1146
		if (uptodate)
1147
			message(MT_REMOTE|MT_INFO, NULL);
1148
		else
1149
			message(MT_REMOTE|MT_INFO, "%s: need to update",
1150
				target);
1151
		if (IS_ON(opts, DO_COMPARE))
1152
			return;
1153
		(void) sendcmd(C_END, NULL);
1154
		(void) response();
1155
		return;
1156
	}
1157
1158
	/*
1159
	 * Make new symlink using a temporary name
1160
	 */
1161
	if (chkparent(new, opts) < 0 || mktemp(new) == NULL ||
1162
	    symlink(dbuf, new) < 0) {
1163
		error("%s -> %s: symlink failed: %s", new, dbuf, SYSERR);
1164
		return;
1165
	}
1166
1167
	/*
1168
	 * See if target is a directory and remove it if it is
1169
	 */
1170
	if (lstat(target, &stb) == 0) {
1171
		if (S_ISDIR(stb.st_mode)) {
1172
			optarget = ptarget;
1173
			for (ptarget = target; *ptarget; ptarget++);
1174
			if (removefile(&stb, 0) < 0) {
1175
				ptarget = optarget;
1176
				(void) unlink(new);
1177
				(void) sendcmd(C_END, NULL);
1178
				(void) response();
1179
				return;
1180
			}
1181
			ptarget = optarget;
1182
		}
1183
	}
1184
1185
	/*
1186
	 * Install link as the target
1187
	 */
1188
	if (rename(new, target) < 0) {
1189
		error("%s -> %s: symlink rename failed: %s",
1190
		      new, target, SYSERR);
1191
		(void) unlink(new);
1192
		(void) sendcmd(C_END, NULL);
1193
		(void) response();
1194
		return;
1195
	}
1196
1197
	message(MT_REMOTE|MT_CHANGE, "%s: updated", target);
1198
1199
	/*
1200
	 * Indicate end of receive operation
1201
	 */
1202
	(void) sendcmd(C_END, NULL);
1203
	(void) response();
1204
}
1205
1206
/*
1207
 * Creat a hard link to existing file.
1208
 */
1209
static void
1210
hardlink(char *cmd)
1211
{
1212
	struct stat stb;
1213
	int exists = 0;
1214
	char *xoldname, *xnewname;
1215
	char *cp = cmd;
1216
	static char expbuf[BUFSIZ];
1217
	char oldname[BUFSIZ], newname[BUFSIZ];
1218
1219
	/* Skip over opts */
1220
	(void) strtol(cp, &cp, 8);
1221
	if (*cp++ != ' ') {
1222
		error("hardlink: options not delimited");
1223
		return;
1224
	}
1225
1226
	xoldname = strtok(cp, " ");
1227
	if (xoldname == NULL) {
1228
		error("hardlink: oldname name not delimited");
1229
		return;
1230
	}
1231
1232
	if (DECODE(oldname, xoldname) == -1) {
1233
		error("hardlink: Cannot decode oldname");
1234
		return;
1235
	}
1236
1237
	xnewname = strtok(NULL, " ");
1238
	if (xnewname == NULL) {
1239
		error("hardlink: new name not specified");
1240
		return;
1241
	}
1242
1243
	if (DECODE(newname, xnewname) == -1) {
1244
		error("hardlink: Cannot decode newname");
1245
		return;
1246
	}
1247
1248
	if (exptilde(expbuf, oldname, sizeof(expbuf)) == NULL) {
1249
		error("hardlink: tilde expansion failed");
1250
		return;
1251
	}
1252
1253
	if (catname && cattarget(newname) < 0) {
1254
		error("Cannot set newname target.");
1255
		return;
1256
	}
1257
1258
	if (lstat(target, &stb) == 0) {
1259
		int mode = stb.st_mode & S_IFMT;
1260
1261
		if (mode != S_IFREG && mode != S_IFLNK) {
1262
			error("%s: not a regular file", target);
1263
			return;
1264
		}
1265
		exists = 1;
1266
	}
1267
1268
	if (chkparent(target, options) < 0 ) {
1269
		error("%s: no parent: %s ", target, SYSERR);
1270
		return;
1271
	}
1272
	if (exists && (unlink(target) < 0)) {
1273
		error("%s: unlink failed: %s", target, SYSERR);
1274
		return;
1275
	}
1276
	if (linkat(AT_FDCWD, expbuf, AT_FDCWD, target, 0) < 0) {
1277
		error("%s: cannot link to %s: %s", target, oldname, SYSERR);
1278
		return;
1279
	}
1280
	ack();
1281
}
1282
1283
/*
1284
 * Set configuration information.
1285
 *
1286
 * A key letter is followed immediately by the value
1287
 * to set.  The keys are:
1288
 *	SC_FREESPACE	- Set minimium free space of filesystem
1289
 *	SC_FREEFILES	- Set minimium free number of files of filesystem
1290
 */
1291
static void
1292
setconfig(char *cmd)
1293
{
1294
	char *cp = cmd;
1295
	char *estr;
1296
	const char *errstr;
1297
1298
	switch (*cp++) {
1299
	case SC_HOSTNAME:	/* Set hostname */
1300
		/*
1301
		 * Only use info if we don't know who this is.
1302
		 */
1303
		if (!fromhost) {
1304
			fromhost = xstrdup(cp);
1305
			message(MT_SYSLOG, "startup for %s", fromhost);
1306
			setproctitle("serving %s", cp);
1307
		}
1308
		break;
1309
1310
	case SC_FREESPACE: 	/* Minimium free space */
1311
		min_freespace = (int64_t)strtonum(cp, 0, LLONG_MAX, &errstr);
1312
		if (errstr)
1313
			fatalerr("Minimum free space is %s: '%s'", errstr,
1314
				optarg);
1315
		break;
1316
1317
	case SC_FREEFILES: 	/* Minimium free files */
1318
		min_freefiles = (int64_t)strtonum(cp, 0, LLONG_MAX, &errstr);
1319
		if (errstr)
1320
			fatalerr("Minimum free files is %s: '%s'", errstr,
1321
				optarg);
1322
		break;
1323
1324
	case SC_LOGGING:	/* Logging options */
1325
		if ((estr = msgparseopts(cp, TRUE)) != NULL) {
1326
			fatalerr("Bad message option string (%s): %s",
1327
				 cp, estr);
1328
			return;
1329
		}
1330
		break;
1331
1332
	case SC_DEFOWNER:
1333
		(void) strlcpy(defowner, cp, sizeof(defowner));
1334
		break;
1335
1336
	case SC_DEFGROUP:
1337
		(void) strlcpy(defgroup, cp, sizeof(defgroup));
1338
		break;
1339
1340
	default:
1341
		message(MT_NOTICE, "Unknown config command \"%s\".", cp-1);
1342
		return;
1343
	}
1344
}
1345
1346
/*
1347
 * Receive something
1348
 */
1349
static void
1350
recvit(char *cmd, int type)
1351
{
1352
	int mode;
1353
	opt_t opts;
1354
	off_t size;
1355
	time_t mtime, atime;
1356
	char *owner, *group, *file;
1357
	char new[PATH_MAX];
1358
	char fileb[PATH_MAX];
1359
	int64_t freespace = -1, freefiles = -1;
1360
	char *cp = cmd;
1361
1362
	/*
1363
	 * Get rdist option flags
1364
	 */
1365
	opts = strtol(cp, &cp, 8);
1366
	if (*cp++ != ' ') {
1367
		error("recvit: options not delimited");
1368
		return;
1369
	}
1370
1371
	/*
1372
	 * Get file mode
1373
	 */
1374
	mode = strtol(cp, &cp, 8);
1375
	if (*cp++ != ' ') {
1376
		error("recvit: mode not delimited");
1377
		return;
1378
	}
1379
1380
	/*
1381
	 * Get file size
1382
	 */
1383
	size = (off_t) strtoll(cp, &cp, 10);
1384
	if (*cp++ != ' ') {
1385
		error("recvit: size not delimited");
1386
		return;
1387
	}
1388
1389
	/*
1390
	 * Get modification time
1391
	 */
1392
	mtime = (time_t) strtoll(cp, &cp, 10);
1393
	if (*cp++ != ' ') {
1394
		error("recvit: mtime not delimited");
1395
		return;
1396
	}
1397
1398
	/*
1399
	 * Get access time
1400
	 */
1401
	atime = (time_t) strtoll(cp, &cp, 10);
1402
	if (*cp++ != ' ') {
1403
		error("recvit: atime not delimited");
1404
		return;
1405
	}
1406
1407
	/*
1408
	 * Get file owner name
1409
	 */
1410
	owner = strtok(cp, " ");
1411
	if (owner == NULL) {
1412
		error("recvit: owner name not delimited");
1413
		return;
1414
	}
1415
1416
	/*
1417
	 * Get file group name
1418
	 */
1419
	group = strtok(NULL, " ");
1420
	if (group == NULL) {
1421
		error("recvit: group name not delimited");
1422
		return;
1423
	}
1424
1425
	/*
1426
	 * Get file name. Can't use strtok() since there could
1427
	 * be white space in the file name.
1428
	 */
1429
	if (DECODE(fileb, group + strlen(group) + 1) == -1) {
1430
		error("recvit: Cannot decode file name");
1431
		return;
1432
	}
1433
1434
	if (fileb[0] == '\0') {
1435
		error("recvit: no file name");
1436
		return;
1437
	}
1438
	file = fileb;
1439
1440
	debugmsg(DM_MISC,
1441
		 "recvit: opts = %#x mode = %#04o size = %lld mtime = %lld",
1442
		 opts, mode, (long long) size, (long long)mtime);
1443
	debugmsg(DM_MISC,
1444
       "recvit: owner = '%s' group = '%s' file = '%s' catname = %d isdir = %d",
1445
		 owner, group, file, catname, (type == S_IFDIR) ? 1 : 0);
1446
1447
	if (type == S_IFDIR) {
1448
		if ((size_t) catname >= sizeof(sptarget)) {
1449
			error("%s: too many directory levels", target);
1450
			return;
1451
		}
1452
		sptarget[catname] = ptarget;
1453
		if (catname++) {
1454
			*ptarget++ = '/';
1455
			while ((*ptarget++ = *file++) != '\0')
1456
			    continue;
1457
			ptarget--;
1458
		}
1459
	} else {
1460
		/*
1461
		 * Create name of temporary file
1462
		 */
1463
		if (catname && cattarget(file) < 0) {
1464
			error("Cannot set file name.");
1465
			return;
1466
		}
1467
		file = strrchr(target, '/');
1468
		if (file == NULL)
1469
			(void) strlcpy(new, tempname, sizeof(new));
1470
		else if (file == target)
1471
			(void) snprintf(new, sizeof(new), "/%s", tempname);
1472
		else {
1473
			*file = CNULL;
1474
			(void) snprintf(new, sizeof(new), "%s/%s", target,
1475
					tempname);
1476
			*file = '/';
1477
		}
1478
	}
1479
1480
	/*
1481
	 * Check to see if there is enough free space and inodes
1482
	 * to install this file.
1483
	 */
1484
	if (min_freespace || min_freefiles) {
1485
		/* Convert file size to kilobytes */
1486
		int64_t fsize = (int64_t)size / 1024;
1487
1488
		if (getfilesysinfo(target, &freespace, &freefiles) != 0)
1489
			return;
1490
1491
		/*
1492
		 * filesystem values < 0 indicate unsupported or unavailable
1493
		 * information.
1494
		 */
1495
		if (min_freespace && (freespace >= 0) &&
1496
		    (freespace - fsize < min_freespace)) {
1497
			error(
1498
		     "%s: Not enough free space on filesystem: min %lld "
1499
		     "free %lld", target, min_freespace, freespace);
1500
			return;
1501
		}
1502
		if (min_freefiles && (freefiles >= 0) &&
1503
		    (freefiles - 1 < min_freefiles)) {
1504
			error(
1505
		     "%s: Not enough free files on filesystem: min %lld free "
1506
		     "%lld", target, min_freefiles, freefiles);
1507
			return;
1508
		}
1509
	}
1510
1511
	/*
1512
	 * Call appropriate receive function to receive file
1513
	 */
1514
	switch (type) {
1515
	case S_IFDIR:
1516
		recvdir(opts, mode, owner, group);
1517
		break;
1518
1519
	case S_IFLNK:
1520
		recvlink(new, opts, mode, size);
1521
		break;
1522
1523
	case S_IFREG:
1524
		recvfile(new, opts, mode, owner, group, mtime, atime, size);
1525
		break;
1526
1527
	default:
1528
		error("%d: unknown file type", type);
1529
		break;
1530
	}
1531
}
1532
1533
/*
1534
 * Chmog something
1535
 */
1536
static void
1537
dochmog(char *cmd)
1538
{
1539
	int mode;
1540
	opt_t opts;
1541
	char *owner, *group, *file;
1542
	char *cp = cmd;
1543
	char fileb[PATH_MAX];
1544
1545
	/*
1546
	 * Get rdist option flags
1547
	 */
1548
	opts = strtol(cp, &cp, 8);
1549
	if (*cp++ != ' ') {
1550
		error("dochmog: options not delimited");
1551
		return;
1552
	}
1553
1554
	/*
1555
	 * Get file mode
1556
	 */
1557
	mode = strtol(cp, &cp, 8);
1558
	if (*cp++ != ' ') {
1559
		error("dochmog: mode not delimited");
1560
		return;
1561
	}
1562
1563
	/*
1564
	 * Get file owner name
1565
	 */
1566
	owner = strtok(cp, " ");
1567
	if (owner == NULL) {
1568
		error("dochmog: owner name not delimited");
1569
		return;
1570
	}
1571
1572
	/*
1573
	 * Get file group name
1574
	 */
1575
	group = strtok(NULL, " ");
1576
	if (group == NULL) {
1577
		error("dochmog: group name not delimited");
1578
		return;
1579
	}
1580
1581
	/*
1582
	 * Get file name. Can't use strtok() since there could
1583
	 * be white space in the file name.
1584
	 */
1585
	if (DECODE(fileb, group + strlen(group) + 1) == -1) {
1586
		error("dochmog: Cannot decode file name");
1587
		return;
1588
	}
1589
1590
	if (fileb[0] == '\0') {
1591
		error("dochmog: no file name");
1592
		return;
1593
	}
1594
	file = fileb;
1595
1596
	debugmsg(DM_MISC,
1597
		 "dochmog: opts = %#x mode = %#04o", opts, mode);
1598
	debugmsg(DM_MISC,
1599
	         "dochmog: owner = '%s' group = '%s' file = '%s' catname = %d",
1600
		 owner, group, file, catname);
1601
1602
	if (catname && cattarget(file) < 0) {
1603
		error("Cannot set newname target.");
1604
		return;
1605
	}
1606
1607
	(void) fchog(-1, target, owner, group, mode);
1608
1609
	ack();
1610
}
1611
1612
/*
1613
 * Set target information
1614
 */
1615
static void
1616
settarget(char *cmd, int isdir)
1617
{
1618
	char *cp = cmd;
1619
	opt_t opts;
1620
	char file[BUFSIZ];
1621
1622
	catname = isdir;
1623
1624
	/*
1625
	 * Parse options for this target
1626
	 */
1627
	opts = strtol(cp, &cp, 8);
1628
	if (*cp++ != ' ') {
1629
		error("settarget: options not delimited");
1630
		return;
1631
	}
1632
	options = opts;
1633
1634
	if (DECODE(file, cp) == -1) {
1635
		error("settarget: Cannot decode target name");
1636
		return;
1637
	}
1638
1639
	/*
1640
	 * Handle target
1641
	 */
1642
	if (exptilde(target, cp, sizeof(target)) == NULL)
1643
		return;
1644
	ptarget = target;
1645
	while (*ptarget)
1646
		ptarget++;
1647
1648
	ack();
1649
}
1650
1651
/*
1652
 * Cleanup in preparation for exiting.
1653
 */
1654
void
1655
cleanup(int dummy)
1656
{
1657
	/* We don't need to do anything */
1658
}
1659
1660
/*
1661
 * Server routine to read requests and process them.
1662
 */
1663
void
1664
server(void)
1665
{
1666
	static char cmdbuf[BUFSIZ];
1667
	char *cp;
1668
	int n, proto_version;
1669
1670
	if (setjmp(finish_jmpbuf))
1671
		return;
1672
	(void) signal(SIGHUP, sighandler);
1673
	(void) signal(SIGINT, sighandler);
1674
	(void) signal(SIGQUIT, sighandler);
1675
	(void) signal(SIGTERM, sighandler);
1676
	(void) signal(SIGPIPE, sighandler);
1677
	(void) umask(oumask = umask(0));
1678
	(void) strlcpy(tempname, _RDIST_TMP, sizeof(tempname));
1679
	if (fromhost) {
1680
		message(MT_SYSLOG, "Startup for %s", fromhost);
1681
#if 	defined(SETARGS)
1682
		setproctitle("Serving %s", fromhost);
1683
#endif	/* SETARGS */
1684
	}
1685
1686
	/*
1687
	 * Let client know we want it to send it's version number
1688
	 */
1689
	(void) sendcmd(S_VERSION, NULL);
1690
1691
	if (remline(cmdbuf, sizeof(cmdbuf), TRUE) < 0) {
1692
		error("server: expected control record");
1693
		return;
1694
	}
1695
1696
	if (cmdbuf[0] != S_VERSION || !isdigit((unsigned char)cmdbuf[1])) {
1697
		error("Expected version command, received: \"%s\".", cmdbuf);
1698
		return;
1699
	}
1700
1701
	proto_version = atoi(&cmdbuf[1]);
1702
	if (proto_version != VERSION) {
1703
		error("Protocol version %d is not supported.", proto_version);
1704
		return;
1705
	}
1706
1707
	/* Version number is okay */
1708
	ack();
1709
1710
	/*
1711
	 * Main command loop
1712
	 */
1713
	for ( ; ; ) {
1714
		n = remline(cp = cmdbuf, sizeof(cmdbuf), TRUE);
1715
		if (n == -1)		/* EOF */
1716
			return;
1717
		if (n == 0) {
1718
			error("server: expected control record");
1719
			continue;
1720
		}
1721
1722
		switch (*cp++) {
1723
		case C_SETCONFIG:  	/* Configuration info */
1724
		        setconfig(cp);
1725
			ack();
1726
			continue;
1727
1728
		case C_DIRTARGET:  	/* init target file/directory name */
1729
			settarget(cp, TRUE);
1730
			continue;
1731
1732
		case C_TARGET:  	/* init target file/directory name */
1733
			settarget(cp, FALSE);
1734
			continue;
1735
1736
		case C_RECVREG:  	/* Transfer a regular file. */
1737
			recvit(cp, S_IFREG);
1738
			continue;
1739
1740
		case C_RECVDIR:  	/* Transfer a directory. */
1741
			recvit(cp, S_IFDIR);
1742
			continue;
1743
1744
		case C_RECVSYMLINK:  	/* Transfer symbolic link. */
1745
			recvit(cp, S_IFLNK);
1746
			continue;
1747
1748
		case C_RECVHARDLINK:  	/* Transfer hard link. */
1749
			hardlink(cp);
1750
			continue;
1751
1752
		case C_END:  		/* End of transfer */
1753
			*ptarget = CNULL;
1754
			if (catname <= 0) {
1755
				error("server: too many '%c's", C_END);
1756
				continue;
1757
			}
1758
			ptarget = sptarget[--catname];
1759
			*ptarget = CNULL;
1760
			ack();
1761
			continue;
1762
1763
		case C_CLEAN:  		/* Clean. Cleanup a directory */
1764
			clean(cp);
1765
			continue;
1766
1767
		case C_QUERY:  		/* Query file/directory */
1768
			query(cp);
1769
			continue;
1770
1771
		case C_SPECIAL:  	/* Special. Execute commands */
1772
			dospecial(cp);
1773
			continue;
1774
1775
		case C_CMDSPECIAL:  	/* Cmd Special. Execute commands */
1776
			docmdspecial();
1777
			continue;
1778
1779
	        case C_CHMOG:  		/* Set owner, group, mode */
1780
			dochmog(cp);
1781
			continue;
1782
1783
		case C_ERRMSG:		/* Normal error message */
1784
			if (cp && *cp)
1785
				message(MT_NERROR|MT_NOREMOTE, "%s", cp);
1786
			continue;
1787
1788
		case C_FERRMSG:		/* Fatal error message */
1789
			if (cp && *cp)
1790
				message(MT_FERROR|MT_NOREMOTE, "%s", cp);
1791
			return;
1792
1793
		default:
1794
			error("server: unknown command '%s'", cp - 1);
1795
		case CNULL:
1796
			continue;
1797
		}
1798
	}
1799
}