xref: /openbsd/usr.bin/rdistd/server.c (revision 9b7c3dbb)
1 /*	$OpenBSD: server.c,v 1.42 2016/03/30 20:51:59 millert 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 >= 0 && 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 }
1800