xref: /dragonfly/bin/cpdup/hcproto.c (revision bcb3e04d)
1 /*
2  * HCPROTO.C
3  *
4  * This module implements a simple remote control protocol
5  *
6  * $DragonFly: src/bin/cpdup/hcproto.c,v 1.8 2008/11/11 04:36:00 dillon Exp $
7  */
8 
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
12 
13 static int hc_decode_stat(hctransaction_t trans, struct stat *, struct HCHead *);
14 static int hc_decode_stat_item(struct stat *st, struct HCLeaf *item);
15 static int rc_encode_stat(hctransaction_t trans, struct stat *);
16 
17 static int rc_hello(hctransaction_t trans, struct HCHead *);
18 static int rc_stat(hctransaction_t trans, struct HCHead *);
19 static int rc_lstat(hctransaction_t trans, struct HCHead *);
20 static int rc_opendir(hctransaction_t trans, struct HCHead *);
21 static int rc_readdir(hctransaction_t trans, struct HCHead *);
22 static int rc_closedir(hctransaction_t trans, struct HCHead *);
23 static int rc_scandir(hctransaction_t trans, struct HCHead *);
24 static int rc_open(hctransaction_t trans, struct HCHead *);
25 static int rc_close(hctransaction_t trans, struct HCHead *);
26 static int rc_read(hctransaction_t trans, struct HCHead *);
27 static int rc_readfile(hctransaction_t trans, struct HCHead *);
28 static int rc_write(hctransaction_t trans, struct HCHead *);
29 static int rc_remove(hctransaction_t trans, struct HCHead *);
30 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
31 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
32 static int rc_chown(hctransaction_t trans, struct HCHead *);
33 static int rc_lchown(hctransaction_t trans, struct HCHead *);
34 static int rc_chmod(hctransaction_t trans, struct HCHead *);
35 static int rc_mknod(hctransaction_t trans, struct HCHead *);
36 static int rc_link(hctransaction_t trans, struct HCHead *);
37 #ifdef _ST_FLAGS_PRESENT_
38 static int rc_chflags(hctransaction_t trans, struct HCHead *);
39 #endif
40 static int rc_readlink(hctransaction_t trans, struct HCHead *);
41 static int rc_umask(hctransaction_t trans, struct HCHead *);
42 static int rc_symlink(hctransaction_t trans, struct HCHead *);
43 static int rc_rename(hctransaction_t trans, struct HCHead *);
44 static int rc_utimes(hctransaction_t trans, struct HCHead *);
45 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
46 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
47 
48 static int getmygroups(gid_t **gidlist);
49 
50 struct HCDesc HCDispatchTable[] = {
51     { HC_HELLO,		rc_hello },
52     { HC_STAT,		rc_stat },
53     { HC_LSTAT,		rc_lstat },
54     { HC_OPENDIR,	rc_opendir },
55     { HC_READDIR,	rc_readdir },
56     { HC_CLOSEDIR,	rc_closedir },
57     { HC_OPEN,		rc_open },
58     { HC_CLOSE,		rc_close },
59     { HC_READ,		rc_read },
60     { HC_WRITE,		rc_write },
61     { HC_REMOVE,	rc_remove },
62     { HC_MKDIR,		rc_mkdir },
63     { HC_RMDIR,		rc_rmdir },
64     { HC_CHOWN,		rc_chown },
65     { HC_LCHOWN,	rc_lchown },
66     { HC_CHMOD,		rc_chmod },
67     { HC_MKNOD,		rc_mknod },
68     { HC_LINK,		rc_link },
69 #ifdef _ST_FLAGS_PRESENT_
70     { HC_CHFLAGS,	rc_chflags },
71 #endif
72     { HC_READLINK,	rc_readlink },
73     { HC_UMASK,		rc_umask },
74     { HC_SYMLINK,	rc_symlink },
75     { HC_RENAME,	rc_rename },
76     { HC_UTIMES,	rc_utimes },
77     { HC_GETEUID,	rc_geteuid },
78     { HC_GETGROUPS,	rc_getgroups },
79     { HC_SCANDIR,	rc_scandir },
80     { HC_READFILE,	rc_readfile },
81 };
82 
83 static int chown_warning;
84 static int chflags_warning;
85 
86 /*
87  * If not running as root generate a silent warning and return no error.
88  *
89  * If running as root return an error.
90  */
91 static int
92 silentwarning(int *didwarn, const char *ctl, ...)
93 {
94     va_list va;
95 
96     if (DstRootPrivs)
97 	return(-1);
98     if (*didwarn == 0 && QuietOpt == 0) {
99 	*didwarn = 1;
100 	fprintf(stderr, "WARNING: Not running as root, ");
101 	va_start(va, ctl);
102 	vfprintf(stderr, ctl, va);
103 	va_end(va);
104     }
105     return(0);
106 }
107 
108 int
109 hc_connect(struct HostConf *hc, int readonly)
110 {
111     if (hcc_connect(hc, readonly) < 0) {
112 	fprintf(stderr, "Unable to connect to %s\n", hc->host);
113 	return(-1);
114     }
115     return(hc_hello(hc));
116 }
117 
118 void
119 hc_slave(int fdin, int fdout)
120 {
121     hcc_slave(fdin, fdout, HCDispatchTable,
122 	      sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
123 
124 }
125 
126 /*
127  * A HELLO RPC is sent on the initial connect.
128  */
129 int
130 hc_hello(struct HostConf *hc)
131 {
132     struct HCHead *head;
133     struct HCLeaf *item;
134     hctransaction_t trans;
135     char hostbuf[256];
136     int error;
137 
138     bzero(hostbuf, sizeof(hostbuf));
139     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
140 	return(-1);
141     if (hostbuf[0] == 0)
142 	hostbuf[0] = '?';
143 
144     trans = hcc_start_command(hc, HC_HELLO);
145     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
146     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
147     if (UseCpFile)
148 	hcc_leaf_string(trans, LC_PATH1, UseCpFile);
149     if ((head = hcc_finish_command(trans)) == NULL) {
150 	fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
151 		hc->host);
152 	return(-1);
153     }
154 
155     if (head->error) {
156 	fprintf(stderr, "Connected to %s but remote returned error %d\n",
157 		hc->host, head->error);
158 	return(-1);
159     }
160 
161     error = -1;
162     FOR_EACH_ITEM(item, trans, head) {
163 	switch(item->leafid) {
164 	case LC_HELLOSTR:
165 	    if (QuietOpt == 0)
166 		fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
167 	    error = 0;
168 	    break;
169 	case LC_VERSION:
170 	    hc->version = HCC_INT32(item);
171 	    break;
172 	}
173     }
174     if (hc->version < HCPROTO_VERSION_COMPAT) {
175 	fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
176 		hc->host);
177 	error = -1;
178     } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
179 	fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
180 		"expect reduced speed\n", hc->host);
181     }
182     if (error < 0)
183 	fprintf(stderr, "Handshake failed with %s\n", hc->host);
184     return (error);
185 }
186 
187 static int
188 rc_hello(hctransaction_t trans, struct HCHead *head)
189 {
190     struct HCLeaf *item;
191     char hostbuf[256];
192 
193     FOR_EACH_ITEM(item, trans, head) {
194 	if (item->leafid == LC_PATH1)
195 	    UseCpFile = strdup(HCC_STRING(item));
196     }
197 
198     bzero(hostbuf, sizeof(hostbuf));
199     if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
200 	return(-1);
201     if (hostbuf[0] == 0)
202 	hostbuf[0] = '?';
203 
204     hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
205     hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
206     return(0);
207 }
208 
209 /*
210  * STAT, LSTAT
211  */
212 int
213 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
214 {
215     struct HCHead *head;
216     hctransaction_t trans;
217 
218     if (hc == NULL || hc->host == NULL)
219 	return(stat(path, st));
220 
221     trans = hcc_start_command(hc, HC_STAT);
222     hcc_leaf_string(trans, LC_PATH1, path);
223     if ((head = hcc_finish_command(trans)) == NULL)
224 	return(-1);
225     if (head->error)
226 	return(-1);
227     return(hc_decode_stat(trans, st, head));
228 }
229 
230 int
231 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
232 {
233     struct HCHead *head;
234     hctransaction_t trans;
235 
236     if (hc == NULL || hc->host == NULL)
237 	return(lstat(path, st));
238 
239     trans = hcc_start_command(hc, HC_LSTAT);
240     hcc_leaf_string(trans, LC_PATH1, path);
241     if ((head = hcc_finish_command(trans)) == NULL)
242 	return(-1);
243     if (head->error)
244 	return(-1);
245     return(hc_decode_stat(trans, st, head));
246 }
247 
248 static int
249 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
250 {
251     struct HCLeaf *item;
252 
253     bzero(st, sizeof(*st));
254     FOR_EACH_ITEM(item, trans, head)
255 	hc_decode_stat_item(st, item);
256     return(0);
257 }
258 
259 static int
260 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
261 {
262     switch(item->leafid) {
263     case LC_DEV:
264 	st->st_dev = HCC_INT32(item);
265 	break;
266     case LC_INO:
267 	st->st_ino = HCC_INT64(item);
268 	break;
269     case LC_MODE:
270 	st->st_mode = HCC_INT32(item);
271 	break;
272     case LC_NLINK:
273 	st->st_nlink = HCC_INT32(item);
274 	break;
275     case LC_UID:
276 	st->st_uid = HCC_INT32(item);
277 	break;
278     case LC_GID:
279 	st->st_gid = HCC_INT32(item);
280 	break;
281     case LC_RDEV:
282 	st->st_rdev = HCC_INT32(item);
283 	break;
284     case LC_ATIME:
285 	st->st_atime = (time_t)HCC_INT64(item);
286 	break;
287     case LC_MTIME:
288 	st->st_mtime = (time_t)HCC_INT64(item);
289 	break;
290     case LC_CTIME:
291 	st->st_ctime = (time_t)HCC_INT64(item);
292 	break;
293     case LC_FILESIZE:
294 	st->st_size = HCC_INT64(item);
295 	break;
296     case LC_FILEBLKS:
297 	st->st_blocks = HCC_INT64(item);
298 	break;
299     case LC_BLKSIZE:
300 	st->st_blksize = HCC_INT32(item);
301 	break;
302 #ifdef _ST_FSMID_PRESENT_
303     case LC_FSMID:
304 	st->st_fsmid = HCC_INT64(item);
305 	break;
306 #endif
307 #ifdef _ST_FLAGS_PRESENT_
308     case LC_FILEFLAGS:
309 	st->st_flags = (uint32_t)HCC_INT64(item);
310 	break;
311 #endif
312     }
313     return(0);
314 }
315 
316 static int
317 rc_stat(hctransaction_t trans, struct HCHead *head)
318 {
319     struct HCLeaf *item;
320     struct stat st;
321     const char *path = NULL;
322 
323     FOR_EACH_ITEM(item, trans, head) {
324 	if (item->leafid == LC_PATH1)
325 	    path = HCC_STRING(item);
326     }
327     if (path == NULL)
328 	return(-2);
329     if (stat(path, &st) < 0)
330 	return(-1);
331     return (rc_encode_stat(trans, &st));
332 }
333 
334 static int
335 rc_lstat(hctransaction_t trans, struct HCHead *head)
336 {
337     struct HCLeaf *item;
338     struct stat st;
339     const char *path = NULL;
340 
341     FOR_EACH_ITEM(item, trans, head) {
342 	if (item->leafid == LC_PATH1)
343 	    path = HCC_STRING(item);
344     }
345     if (path == NULL)
346 	return(-2);
347     if (lstat(path, &st) < 0)
348 	return(-1);
349     return (rc_encode_stat(trans, &st));
350 }
351 
352 /*
353  * Encode all entries of a stat structure.
354  *
355  * CAUTION:  If you add any more entries here, be sure to
356  *           increase the STAT_MAX_NUM_ENTRIES value!
357  */
358 #define STAT_MAX_NUM_ENTRIES 18
359 static int
360 rc_encode_stat(hctransaction_t trans, struct stat *st)
361 {
362     hcc_leaf_int32(trans, LC_DEV, st->st_dev);
363     hcc_leaf_int64(trans, LC_INO, st->st_ino);
364     hcc_leaf_int32(trans, LC_MODE, st->st_mode);
365     hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
366     hcc_leaf_int32(trans, LC_UID, st->st_uid);
367     hcc_leaf_int32(trans, LC_GID, st->st_gid);
368     hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
369     hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
370     hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
371     hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
372     hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
373     hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
374     hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
375 #ifdef _ST_FSMID_PRESENT_
376     hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
377 #endif
378 #ifdef _ST_FLAGS_PRESENT_
379     hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
380 #endif
381     return(0);
382 }
383 
384 /*
385  * OPENDIR
386  */
387 DIR *
388 hc_opendir(struct HostConf *hc, const char *path)
389 {
390     hctransaction_t trans;
391     struct HCHead *head;
392 
393     if (hc == NULL || hc->host == NULL)
394 	return(opendir(path));
395 
396     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
397 	struct HCLeaf *item;
398 	struct HCDirEntry *den;
399 	intptr_t desc = 0;
400 
401 	trans = hcc_start_command(hc, HC_OPENDIR);
402 	hcc_leaf_string(trans, LC_PATH1, path);
403 	if ((head = hcc_finish_command(trans)) == NULL)
404 	    return (NULL);
405 	if (head->error)
406 	    return (NULL);
407 	FOR_EACH_ITEM(item, trans, head) {
408 	    if (item->leafid == LC_DESCRIPTOR)
409 		desc = HCC_INT32(item);
410 	}
411 	if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
412 	    fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
413 		(intmax_t)desc);
414 	    return (NULL);
415 	}
416 	den = malloc(sizeof(*den));
417 	hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
418 	return ((void *)desc);
419     }
420 
421     /* hc->version >= 4: use HC_SCANDIR */
422     trans = hcc_start_command(hc, HC_SCANDIR);
423     hcc_leaf_string(trans, LC_PATH1, path);
424     if ((head = hcc_finish_command(trans)) == NULL || head->error)
425 	return (NULL);
426     return ((void *)head);
427 }
428 
429 static int
430 rc_opendir(hctransaction_t trans, struct HCHead *head)
431 {
432     struct HCLeaf *item;
433     const char *path = NULL;
434     DIR *dir;
435     int desc;
436 
437     FOR_EACH_ITEM(item, trans, head) {
438 	if (item->leafid == LC_PATH1)
439 	    path = HCC_STRING(item);
440     }
441     if (path == NULL)
442 	return(-2);
443     if ((dir = opendir(path)) == NULL) {
444 	head->error = errno;
445     } else {
446 	desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
447 	hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
448     }
449     return(0);
450 }
451 
452 /*
453  * READDIR
454  */
455 struct HCDirEntry *
456 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
457 {
458     int stat_ok = 0;
459     struct HCHead *head;
460     struct HCLeaf *item;
461     static struct HCDirEntry denbuf;
462 
463     *statpp = NULL;
464     if (hc == NULL || hc->host == NULL) {
465 	struct dirent *sysden;
466 
467 	if ((sysden = readdir(dir)) == NULL)
468 	    return (NULL);
469 	strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
470 	return (&denbuf);
471     }
472 
473     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
474 	hctransaction_t trans;
475 	struct HCDirEntry *den;
476 
477 	trans = hcc_start_command(hc, HC_READDIR);
478 	hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
479 	if ((head = hcc_finish_command(trans)) == NULL)
480 	    return (NULL);
481 	if (head->error)
482 	    return (NULL);	/* XXX errno */
483 	den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
484 	if (den == NULL)
485 	    return (NULL);	/* XXX errno */
486 	den->d_name[0] = 0;
487 	FOR_EACH_ITEM(item, trans, head) {
488 	    if (item->leafid == LC_PATH1)
489 		strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
490 	}
491 	return (den->d_name[0] ? den : NULL);
492     }
493 
494     /* hc->version >= 4: using HC_SCANDIR */
495     denbuf.d_name[0] = 0;
496     head = (void *)dir;
497     *statpp = malloc(sizeof(struct stat));
498     bzero(*statpp, sizeof(struct stat));
499     while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
500 	if (item->leafid == LC_PATH1) {  /* this must be the last item */
501 	    strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
502 	    break;
503 	} else {
504 	    stat_ok = 1;
505 	    hc_decode_stat_item(*statpp, item);
506 	}
507     }
508     if (!stat_ok) {
509 	free(*statpp);
510 	*statpp = NULL;
511     }
512     return (denbuf.d_name[0] ? &denbuf : NULL);
513 }
514 
515 static int
516 rc_readdir(hctransaction_t trans, struct HCHead *head)
517 {
518     struct HCLeaf *item;
519     struct dirent *den;
520     DIR *dir = NULL;
521 
522     FOR_EACH_ITEM(item, trans, head) {
523 	if (item->leafid == LC_DESCRIPTOR)
524 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
525     }
526     if (dir == NULL)
527 	return(-2);
528     if ((den = readdir(dir)) != NULL)
529 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
530     return(0);
531 }
532 
533 /*
534  * CLOSEDIR
535  *
536  * XXX cpdup needs to check error code to avoid truncated dirs?
537  */
538 int
539 hc_closedir(struct HostConf *hc, DIR *dir)
540 {
541     struct HCHead *head;
542 
543     if (hc == NULL || hc->host == NULL)
544 	return(closedir(dir));
545 
546     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
547 	hctransaction_t trans;
548 	struct dirent *den;
549 
550 	if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
551 	    free(den);
552 	    hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
553 	    trans = hcc_start_command(hc, HC_CLOSEDIR);
554 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
555 	    if ((head = hcc_finish_command(trans)) == NULL)
556 		return (-1);
557 	    if (head->error)
558 		return (-1);		/* XXX errno */
559 	    return (0);
560 	} else {
561 	    /* errno */
562 	    return(-1);
563 	}
564     }
565 
566     /* hc->version >= 4: using HC_SCANDIR */
567     head = (void *)dir;
568     /* skip any remaining items if the directory is closed prematurely */
569     while (hcc_nextchaineditem(hc, head) != NULL)
570 	/*nothing*/ ;
571     if (head->error)
572 	return (-1);
573     return (0);
574 }
575 
576 static int
577 rc_closedir(hctransaction_t trans, struct HCHead *head)
578 {
579     struct HCLeaf *item;
580     DIR *dir = NULL;
581 
582     FOR_EACH_ITEM(item, trans, head) {
583 	if (item->leafid == LC_DESCRIPTOR) {
584 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
585 	    if (dir != NULL) {
586 		    hcc_set_descriptor(trans->hc, HCC_INT32(item),
587 				       NULL, HC_DESC_DIR);
588 	    }
589 	}
590     }
591     if (dir == NULL)
592 	return(-2);
593     return(closedir(dir));
594 }
595 
596 /*
597  * SCANDIR
598  */
599 static int
600 rc_scandir(hctransaction_t trans, struct HCHead *head)
601 {
602     struct HCLeaf *item;
603     const char *path = NULL;
604     struct dirent *den;
605     DIR *dir;
606     char *fpath;
607     struct stat st;
608 
609     FOR_EACH_ITEM(item, trans, head) {
610 	if (item->leafid == LC_PATH1)
611 	    path = HCC_STRING(item);
612     }
613     if (path == NULL)
614 	return (-2);
615     if ((dir = opendir(path)) == NULL)
616 	return (-1);
617     while ((den = readdir(dir)) != NULL) {
618 	if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
619 		(den->d_name[1] == '.' && den->d_name[2] == '\0')))
620 	    continue;	/* skip "." and ".." */
621 	/*
622 	 * Check if there's enough space left in the current packet.
623 	 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
624 	 * one is a string, so we use strlen() + 1 (terminating zero).
625 	 * The remaining ones are numbers; we assume sizeof(int64_t) so
626 	 * we're on the safe side.
627 	 */
628 	if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
629 		(STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
630 		strlen(den->d_name) + 1)) {
631 	    closedir(dir);
632 	    return (-1);
633 	}
634 	fpath = mprintf("%s/%s", path, den->d_name);
635 	if (lstat(fpath, &st) == 0)
636 	    rc_encode_stat(trans, &st);
637 	/* The name must be the last item! */
638 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
639 	free(fpath);
640     }
641     return (closedir(dir));
642 }
643 
644 /*
645  * OPEN
646  */
647 int
648 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
649 {
650     hctransaction_t trans;
651     struct HCHead *head;
652     struct HCLeaf *item;
653     int *fdp;
654     int desc = 0;
655     int nflags;
656 
657     if (hc == NULL || hc->host == NULL) {
658 #ifdef O_LARGEFILE
659 	flags |= O_LARGEFILE;
660 #endif
661 	return(open(path, flags, mode));
662     }
663 
664     if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
665 	trans = hcc_start_command(hc, HC_READFILE);
666 	hcc_leaf_string(trans, LC_PATH1, path);
667 	if ((head = hcc_finish_command(trans)) == NULL || head->error)
668 	    return (-1);
669 	head->magic = 0; /* used to indicate offset within buffer */
670 	return (1); /* dummy */
671     }
672 
673     nflags = flags & XO_NATIVEMASK;
674     if (flags & O_CREAT)
675 	nflags |= XO_CREAT;
676     if (flags & O_EXCL)
677 	nflags |= XO_EXCL;
678     if (flags & O_TRUNC)
679 	nflags |= XO_TRUNC;
680 
681     trans = hcc_start_command(hc, HC_OPEN);
682     hcc_leaf_string(trans, LC_PATH1, path);
683     hcc_leaf_int32(trans, LC_OFLAGS, nflags);
684     hcc_leaf_int32(trans, LC_MODE, mode);
685 
686     if ((head = hcc_finish_command(trans)) == NULL)
687 	return(-1);
688     if (head->error)
689 	return(-1);
690     FOR_EACH_ITEM(item, trans, head) {
691 	if (item->leafid == LC_DESCRIPTOR)
692 	    desc = HCC_INT32(item);
693     }
694     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
695 	fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
696 		desc);
697 	return(-1);
698     }
699     fdp = malloc(sizeof(int));
700     *fdp = desc;	/* really just a dummy */
701     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
702     return(desc);
703 }
704 
705 static int
706 rc_open(hctransaction_t trans, struct HCHead *head)
707 {
708     struct HCLeaf *item;
709     const char *path = NULL;
710     int nflags = 0;
711     int flags;
712     mode_t mode = 0666;
713     int desc;
714     int *fdp;
715     int fd;
716 
717     FOR_EACH_ITEM(item, trans, head) {
718 	switch(item->leafid) {
719 	case LC_PATH1:
720 	    path = HCC_STRING(item);
721 	    break;
722 	case LC_OFLAGS:
723 	    nflags = HCC_INT32(item);
724 	    break;
725 	case LC_MODE:
726 	    mode = HCC_INT32(item);
727 	    break;
728 	}
729     }
730     if (path == NULL)
731 	return(-2);
732 
733     flags = nflags & XO_NATIVEMASK;
734     if (nflags & XO_CREAT)
735 	flags |= O_CREAT;
736     if (nflags & XO_EXCL)
737 	flags |= O_EXCL;
738     if (nflags & XO_TRUNC)
739 	flags |= O_TRUNC;
740 
741     if (ReadOnlyOpt) {
742 	if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
743 	    head->error = EACCES;
744 	    return (0);
745 	}
746 	flags |= O_RDONLY;
747     }
748 
749 #ifdef O_LARGEFILE
750     flags |= O_LARGEFILE;
751 #endif
752     if ((fd = open(path, flags, mode)) < 0)
753 	return(-1);
754     fdp = malloc(sizeof(int));
755     *fdp = fd;
756     desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
757     hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
758     return(0);
759 }
760 
761 /*
762  * CLOSE
763  */
764 int
765 hc_close(struct HostConf *hc, int fd)
766 {
767     hctransaction_t trans;
768     struct HCHead *head;
769     int *fdp;
770 
771     if (hc == NULL || hc->host == NULL)
772 	return(close(fd));
773 
774     if (fd == 1 && hc->version >= 4) {	/* using HC_READFILE */
775 	head = (void *)hc->trans.rbuf;
776 	/* skip any remaining items if the file is closed prematurely */
777 	while (hcc_nextchaineditem(hc, head) != NULL)
778 	    /*nothing*/ ;
779 	if (head->error)
780 	    return (-1);
781 	return (0);
782     }
783 
784     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
785     if (fdp) {
786 	free(fdp);
787 	hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
788 
789 	trans = hcc_start_command(hc, HC_CLOSE);
790 	hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
791 	if ((head = hcc_finish_command(trans)) == NULL)
792 	    return(-1);
793 	if (head->error)
794 	    return(-1);
795 	return(0);
796     } else {
797 	return(-1);
798     }
799 }
800 
801 static int
802 rc_close(hctransaction_t trans, struct HCHead *head)
803 {
804     struct HCLeaf *item;
805     int *fdp = NULL;
806     int fd;
807     int desc = -1;
808 
809     FOR_EACH_ITEM(item, trans, head) {
810 	if (item->leafid == LC_DESCRIPTOR)
811 	    desc = HCC_INT32(item);
812     }
813     if (desc < 0)
814 	return(-2);
815     if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
816 	return(-2);
817     fd = *fdp;
818     free(fdp);
819     hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
820     return(close(fd));
821 }
822 
823 static int
824 getiolimit(void)
825 {
826     return(32768);
827 }
828 
829 /*
830  * READ
831  */
832 ssize_t
833 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
834 {
835     hctransaction_t trans;
836     struct HCHead *head;
837     struct HCLeaf *item;
838     int *fdp;
839     int offset;
840     int r = 0;
841     int x = 0;
842 
843     if (hc == NULL || hc->host == NULL)
844 	return(read(fd, buf, bytes));
845 
846     if (fd == 1 && hc->version >= 4) {	/* using HC_READFILE */
847 	head = (void *)hc->trans.rbuf;
848 	while (bytes) {
849 	    if ((offset = head->magic) != 0)
850 		item = hcc_currentchaineditem(hc, head);
851 	    else
852 		item = hcc_nextchaineditem(hc, head);
853 	    if (item == NULL)
854 		return (r);
855 	    if (item->leafid != LC_DATA)
856 		return (-1);
857 	    x = item->bytes - sizeof(*item) - offset;
858 	    if (x > (int)bytes) {
859 		x = (int)bytes;
860 		head->magic += x;  /* leave bytes in the buffer */
861 	    }
862 	    else
863 		head->magic = 0;  /* all bytes used up */
864 	    bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
865 	    buf = (char *)buf + x;
866 	    bytes -= (size_t)x;
867 	    r += x;
868 	}
869 	return (r);
870     }
871 
872     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
873     if (fdp) {
874 	while (bytes) {
875 	    size_t limit = getiolimit();
876 	    int n = (bytes > limit) ? limit : bytes;
877 
878 	    trans = hcc_start_command(hc, HC_READ);
879 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
880 	    hcc_leaf_int32(trans, LC_BYTES, n);
881 	    if ((head = hcc_finish_command(trans)) == NULL)
882 		return(-1);
883 	    if (head->error)
884 		return(-1);
885 	    FOR_EACH_ITEM(item, trans, head) {
886 		if (item->leafid == LC_DATA) {
887 		    x = item->bytes - sizeof(*item);
888 		    if (x > (int)bytes)
889 			x = (int)bytes;
890 		    bcopy(HCC_BINARYDATA(item), buf, x);
891 		    buf = (char *)buf + x;
892 		    bytes -= (size_t)x;
893 		    r += x;
894 		}
895 	    }
896 	    if (x < n)
897 		break;
898 	}
899 	return(r);
900     } else {
901 	return(-1);
902     }
903 }
904 
905 static int
906 rc_read(hctransaction_t trans, struct HCHead *head)
907 {
908     struct HCLeaf *item;
909     int *fdp = NULL;
910     char buf[32768];
911     int bytes = -1;
912     int n;
913 
914     FOR_EACH_ITEM(item, trans, head) {
915 	switch(item->leafid) {
916 	case LC_DESCRIPTOR:
917 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
918 	    break;
919 	case LC_BYTES:
920 	    bytes = HCC_INT32(item);
921 	    break;
922 	}
923     }
924     if (fdp == NULL)
925 	return(-2);
926     if (bytes < 0 || bytes > 32768)
927 	return(-2);
928     n = read(*fdp, buf, bytes);
929     if (n < 0)
930 	return(-1);
931     hcc_leaf_data(trans, LC_DATA, buf, n);
932     return(0);
933 }
934 
935 /*
936  * READFILE
937  */
938 static int
939 rc_readfile(hctransaction_t trans, struct HCHead *head)
940 {
941     struct HCLeaf *item;
942     const char *path = NULL;
943     char buf[32768];
944     int n;
945     int fd;
946 
947     FOR_EACH_ITEM(item, trans, head) {
948 	if (item->leafid == LC_PATH1)
949 	    path = HCC_STRING(item);
950     }
951     if (path == NULL)
952 	return (-2);
953     if ((fd = open(path, O_RDONLY)) < 0)
954 	return(-1);
955     while ((n = read(fd, buf, 32768)) >= 0) {
956 	if (!hcc_check_space(trans, head, 1, n)) {
957 	    close(fd);
958 	    return (-1);
959 	}
960 	hcc_leaf_data(trans, LC_DATA, buf, n);
961 	if (n == 0)
962 		break;
963     }
964     if (n < 0) {
965 	close(fd);
966 	return (-1);
967     }
968     return (close(fd));
969 }
970 
971 /*
972  * WRITE
973  */
974 ssize_t
975 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
976 {
977     hctransaction_t trans;
978     struct HCHead *head;
979     struct HCLeaf *item;
980     int *fdp;
981     int r;
982 
983     if (hc == NULL || hc->host == NULL)
984 	return(write(fd, buf, bytes));
985 
986     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
987     if (fdp) {
988 	r = 0;
989 	while (bytes) {
990 	    size_t limit = getiolimit();
991 	    int n = (bytes > limit) ? limit : bytes;
992 	    int x = 0;
993 
994 	    trans = hcc_start_command(hc, HC_WRITE);
995 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
996 	    hcc_leaf_data(trans, LC_DATA, buf, n);
997 	    if ((head = hcc_finish_command(trans)) == NULL)
998 		return(-1);
999 	    if (head->error)
1000 		return(-1);
1001 	    FOR_EACH_ITEM(item, trans, head) {
1002 		if (item->leafid == LC_BYTES)
1003 		    x = HCC_INT32(item);
1004 	    }
1005 	    if (x < 0 || x > n)
1006 		return(-1);
1007 	    r += x;
1008 	    buf = (const char *)buf + x;
1009 	    bytes -= x;
1010 	    if (x < n)
1011 		break;
1012 	}
1013 	return(r);
1014     } else {
1015 	return(-1);
1016     }
1017 }
1018 
1019 static int
1020 rc_write(hctransaction_t trans, struct HCHead *head)
1021 {
1022     struct HCLeaf *item;
1023     int *fdp = NULL;
1024     void *buf = NULL;
1025     int n = -1;
1026 
1027     FOR_EACH_ITEM(item, trans, head) {
1028 	switch(item->leafid) {
1029 	case LC_DESCRIPTOR:
1030 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1031 	    break;
1032 	case LC_DATA:
1033 	    buf = HCC_BINARYDATA(item);
1034 	    n = item->bytes - sizeof(*item);
1035 	    break;
1036 	}
1037     }
1038     if (ReadOnlyOpt) {
1039 	head->error = EACCES;
1040 	return (0);
1041     }
1042     if (fdp == NULL)
1043 	return(-2);
1044     if (n < 0 || n > 32768)
1045 	return(-2);
1046     n = write(*fdp, buf, n);
1047     if (n < 0)
1048 	return (-1);
1049     hcc_leaf_int32(trans, LC_BYTES, n);
1050     return(0);
1051 }
1052 
1053 /*
1054  * REMOVE
1055  *
1056  * NOTE: This function returns -errno if an error occured.
1057  */
1058 int
1059 hc_remove(struct HostConf *hc, const char *path)
1060 {
1061     hctransaction_t trans;
1062     struct HCHead *head;
1063     int res;
1064 
1065     if (hc == NULL || hc->host == NULL) {
1066 	res = remove(path);
1067 	if (res < 0)
1068 		res = -errno;
1069 	return(res);
1070     }
1071 
1072     trans = hcc_start_command(hc, HC_REMOVE);
1073     hcc_leaf_string(trans, LC_PATH1, path);
1074     if ((head = hcc_finish_command(trans)) == NULL)
1075 	return(-EIO);
1076     if (head->error)
1077 	return(-(int)head->error);
1078     return(0);
1079 }
1080 
1081 static int
1082 rc_remove(hctransaction_t trans, struct HCHead *head)
1083 {
1084     struct HCLeaf *item;
1085     const char *path = NULL;
1086 
1087     FOR_EACH_ITEM(item, trans, head) {
1088 	if (item->leafid == LC_PATH1)
1089 	    path = HCC_STRING(item);
1090     }
1091     if (path == NULL)
1092 	return(-2);
1093     if (ReadOnlyOpt) {
1094 	head->error = EACCES;
1095 	return (0);
1096     }
1097     return(remove(path));
1098 }
1099 
1100 /*
1101  * MKDIR
1102  */
1103 int
1104 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1105 {
1106     hctransaction_t trans;
1107     struct HCHead *head;
1108 
1109     if (hc == NULL || hc->host == NULL)
1110 	return(mkdir(path, mode));
1111 
1112     trans = hcc_start_command(hc, HC_MKDIR);
1113     hcc_leaf_string(trans, LC_PATH1, path);
1114     hcc_leaf_int32(trans, LC_MODE, mode);
1115     if ((head = hcc_finish_command(trans)) == NULL)
1116 	return(-1);
1117     if (head->error)
1118 	return(-1);
1119     return(0);
1120 }
1121 
1122 static int
1123 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1124 {
1125     struct HCLeaf *item;
1126     const char *path = NULL;
1127     mode_t mode = 0777;
1128 
1129     FOR_EACH_ITEM(item, trans, head) {
1130 	switch(item->leafid) {
1131 	case LC_PATH1:
1132 	    path = HCC_STRING(item);
1133 	    break;
1134 	case LC_MODE:
1135 	    mode = HCC_INT32(item);
1136 	    break;
1137 	}
1138     }
1139     if (ReadOnlyOpt) {
1140 	head->error = EACCES;
1141 	return (0);
1142     }
1143     if (path == NULL)
1144 	return(-2);
1145     return(mkdir(path, mode));
1146 }
1147 
1148 /*
1149  * RMDIR
1150  */
1151 int
1152 hc_rmdir(struct HostConf *hc, const char *path)
1153 {
1154     hctransaction_t trans;
1155     struct HCHead *head;
1156 
1157     if (hc == NULL || hc->host == NULL)
1158 	return(rmdir(path));
1159 
1160     trans = hcc_start_command(hc, HC_RMDIR);
1161     hcc_leaf_string(trans, LC_PATH1, path);
1162     if ((head = hcc_finish_command(trans)) == NULL)
1163 	return(-1);
1164     if (head->error)
1165 	return(-1);
1166     return(0);
1167 }
1168 
1169 static int
1170 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1171 {
1172     struct HCLeaf *item;
1173     const char *path = NULL;
1174 
1175     FOR_EACH_ITEM(item, trans, head) {
1176 	if (item->leafid == LC_PATH1)
1177 	    path = HCC_STRING(item);
1178     }
1179     if (ReadOnlyOpt) {
1180 	head->error = EACCES;
1181 	return (0);
1182     }
1183     if (path == NULL)
1184 	return(-2);
1185     return(rmdir(path));
1186 }
1187 
1188 /*
1189  * CHOWN
1190  *
1191  * Almost silently ignore chowns that fail if we are not root.
1192  */
1193 int
1194 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1195 {
1196     hctransaction_t trans;
1197     struct HCHead *head;
1198     int rc;
1199 
1200     if (!DstRootPrivs)
1201 	owner = -1;
1202 
1203     if (hc == NULL || hc->host == NULL) {
1204 	rc = chown(path, owner, group);
1205 	if (rc < 0)
1206 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1207 	return(rc);
1208     }
1209 
1210     trans = hcc_start_command(hc, HC_CHOWN);
1211     hcc_leaf_string(trans, LC_PATH1, path);
1212     hcc_leaf_int32(trans, LC_UID, owner);
1213     hcc_leaf_int32(trans, LC_GID, group);
1214     if ((head = hcc_finish_command(trans)) == NULL)
1215 	return(-1);
1216     if (head->error)
1217 	return(-1);
1218     return(0);
1219 }
1220 
1221 static int
1222 rc_chown(hctransaction_t trans, struct HCHead *head)
1223 {
1224     struct HCLeaf *item;
1225     const char *path = NULL;
1226     uid_t uid = (uid_t)-1;
1227     gid_t gid = (gid_t)-1;
1228     int rc;
1229 
1230     FOR_EACH_ITEM(item, trans, head) {
1231 	switch(item->leafid) {
1232 	case LC_PATH1:
1233 	    path = HCC_STRING(item);
1234 	    break;
1235 	case LC_UID:
1236 	    uid = HCC_INT32(item);
1237 	    break;
1238 	case LC_GID:
1239 	    gid = HCC_INT32(item);
1240 	    break;
1241 	}
1242     }
1243     if (ReadOnlyOpt) {
1244 	head->error = EACCES;
1245 	return (0);
1246     }
1247     if (path == NULL)
1248 	return(-2);
1249     rc = chown(path, uid, gid);
1250     if (rc < 0)
1251 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1252     return(rc);
1253 }
1254 
1255 /*
1256  * LCHOWN
1257  */
1258 int
1259 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1260 {
1261     hctransaction_t trans;
1262     struct HCHead *head;
1263     int rc;
1264 
1265     if (!DstRootPrivs)
1266 	owner = -1;
1267 
1268     if (hc == NULL || hc->host == NULL) {
1269 	rc = lchown(path, owner, group);
1270 	if (rc < 0)
1271 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1272 	return(rc);
1273     }
1274 
1275     trans = hcc_start_command(hc, HC_LCHOWN);
1276     hcc_leaf_string(trans, LC_PATH1, path);
1277     hcc_leaf_int32(trans, LC_UID, owner);
1278     hcc_leaf_int32(trans, LC_GID, group);
1279     if ((head = hcc_finish_command(trans)) == NULL)
1280 	return(-1);
1281     if (head->error)
1282 	return(-1);
1283     return(0);
1284 }
1285 
1286 static int
1287 rc_lchown(hctransaction_t trans, struct HCHead *head)
1288 {
1289     struct HCLeaf *item;
1290     const char *path = NULL;
1291     uid_t uid = (uid_t)-1;
1292     gid_t gid = (gid_t)-1;
1293     int rc;
1294 
1295     FOR_EACH_ITEM(item, trans, head) {
1296 	switch(item->leafid) {
1297 	case LC_PATH1:
1298 	    path = HCC_STRING(item);
1299 	    break;
1300 	case LC_UID:
1301 	    uid = HCC_INT32(item);
1302 	    break;
1303 	case LC_GID:
1304 	    gid = HCC_INT32(item);
1305 	    break;
1306 	}
1307     }
1308     if (ReadOnlyOpt) {
1309 	head->error = EACCES;
1310 	return (0);
1311     }
1312     if (path == NULL)
1313 	return(-2);
1314     rc = lchown(path, uid, gid);
1315     if (rc < 0)
1316 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1317     return(rc);
1318 }
1319 
1320 /*
1321  * CHMOD
1322  */
1323 int
1324 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1325 {
1326     hctransaction_t trans;
1327     struct HCHead *head;
1328 
1329     if (hc == NULL || hc->host == NULL)
1330 	return(chmod(path, mode));
1331 
1332     trans = hcc_start_command(hc, HC_CHMOD);
1333     hcc_leaf_string(trans, LC_PATH1, path);
1334     hcc_leaf_int32(trans, LC_MODE, mode);
1335     if ((head = hcc_finish_command(trans)) == NULL)
1336 	return(-1);
1337     if (head->error)
1338 	return(-1);
1339     return(0);
1340 }
1341 
1342 static int
1343 rc_chmod(hctransaction_t trans, struct HCHead *head)
1344 {
1345     struct HCLeaf *item;
1346     const char *path = NULL;
1347     mode_t mode = 0666;
1348 
1349     FOR_EACH_ITEM(item, trans, head) {
1350 	switch(item->leafid) {
1351 	case LC_PATH1:
1352 	    path = HCC_STRING(item);
1353 	    break;
1354 	case LC_MODE:
1355 	    mode = HCC_INT32(item);
1356 	    break;
1357 	}
1358     }
1359     if (ReadOnlyOpt) {
1360 	head->error = EACCES;
1361 	return (0);
1362     }
1363     if (path == NULL)
1364 	return(-2);
1365     return(chmod(path, mode));
1366 }
1367 
1368 /*
1369  * MKNOD
1370  */
1371 int
1372 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1373 {
1374     hctransaction_t trans;
1375     struct HCHead *head;
1376 
1377     if (!DstRootPrivs) {
1378 	/* mknod() requires root privs, so don't bother. */
1379 	errno = EPERM;
1380 	return (-1);
1381     }
1382 
1383     if (hc == NULL || hc->host == NULL)
1384 	return(mknod(path, mode, rdev));
1385 
1386     trans = hcc_start_command(hc, HC_MKNOD);
1387     hcc_leaf_string(trans, LC_PATH1, path);
1388     hcc_leaf_int32(trans, LC_MODE, mode);
1389     hcc_leaf_int32(trans, LC_RDEV, rdev);
1390     if ((head = hcc_finish_command(trans)) == NULL)
1391 	return(-1);
1392     if (head->error)
1393 	return(-1);
1394     return(0);
1395 }
1396 
1397 static int
1398 rc_mknod(hctransaction_t trans, struct HCHead *head)
1399 {
1400     struct HCLeaf *item;
1401     const char *path = NULL;
1402     mode_t mode = 0666;
1403     dev_t rdev = 0;
1404 
1405     FOR_EACH_ITEM(item, trans, head) {
1406 	switch(item->leafid) {
1407 	case LC_PATH1:
1408 	    path = HCC_STRING(item);
1409 	    break;
1410 	case LC_MODE:
1411 	    mode = HCC_INT32(item);
1412 	    break;
1413 	case LC_RDEV:
1414 	    rdev = HCC_INT32(item);
1415 	    break;
1416 	}
1417     }
1418     if (ReadOnlyOpt) {
1419 	head->error = EACCES;
1420 	return (0);
1421     }
1422     if (path == NULL)
1423 	return(-2);
1424     return(mknod(path, mode, rdev));
1425 }
1426 
1427 /*
1428  * LINK
1429  */
1430 int
1431 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1432 {
1433     hctransaction_t trans;
1434     struct HCHead *head;
1435 
1436     if (hc == NULL || hc->host == NULL)
1437 	return(link(name1, name2));
1438 
1439     trans = hcc_start_command(hc, HC_LINK);
1440     hcc_leaf_string(trans, LC_PATH1, name1);
1441     hcc_leaf_string(trans, LC_PATH2, name2);
1442     if ((head = hcc_finish_command(trans)) == NULL)
1443 	return(-1);
1444     if (head->error)
1445 	return(-1);
1446     return(0);
1447 }
1448 
1449 static int
1450 rc_link(hctransaction_t trans, struct HCHead *head)
1451 {
1452     struct HCLeaf *item;
1453     const char *name1 = NULL;
1454     const char *name2 = NULL;
1455 
1456     FOR_EACH_ITEM(item, trans, head) {
1457 	switch(item->leafid) {
1458 	case LC_PATH1:
1459 	    name1 = HCC_STRING(item);
1460 	    break;
1461 	case LC_PATH2:
1462 	    name2 = HCC_STRING(item);
1463 	    break;
1464 	}
1465     }
1466     if (ReadOnlyOpt) {
1467 	head->error = EACCES;
1468 	return (-0);
1469     }
1470     if (name1 == NULL || name2 == NULL)
1471 	return(-2);
1472     return(link(name1, name2));
1473 }
1474 
1475 #ifdef _ST_FLAGS_PRESENT_
1476 /*
1477  * CHFLAGS
1478  */
1479 int
1480 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1481 {
1482     hctransaction_t trans;
1483     struct HCHead *head;
1484     int rc;
1485 
1486     if (!DstRootPrivs)
1487 	flags &= UF_SETTABLE;
1488 
1489     if (hc == NULL || hc->host == NULL) {
1490 	if ((rc = chflags(path, flags)) < 0)
1491 	    rc = silentwarning(&chflags_warning, "file flags may differ\n");
1492 	return (rc);
1493     }
1494 
1495     trans = hcc_start_command(hc, HC_CHFLAGS);
1496     hcc_leaf_string(trans, LC_PATH1, path);
1497     hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1498     if ((head = hcc_finish_command(trans)) == NULL)
1499 	return(-1);
1500     if (head->error)
1501 	return(-1);
1502     return(0);
1503 }
1504 
1505 static int
1506 rc_chflags(hctransaction_t trans, struct HCHead *head)
1507 {
1508     struct HCLeaf *item;
1509     const char *path = NULL;
1510     u_long flags = 0;
1511     int rc;
1512 
1513     FOR_EACH_ITEM(item, trans, head) {
1514 	switch(item->leafid) {
1515 	case LC_PATH1:
1516 	    path = HCC_STRING(item);
1517 	    break;
1518 	case LC_FILEFLAGS:
1519 	    flags = (u_long)HCC_INT64(item);
1520 	    break;
1521 	}
1522     }
1523     if (ReadOnlyOpt) {
1524 	head->error = EACCES;
1525 	return (0);
1526     }
1527     if (path == NULL)
1528 	return(-2);
1529     if ((rc = chflags(path, flags)) < 0)
1530 	rc = silentwarning(&chflags_warning, "file flags may differ\n");
1531     return(rc);
1532 }
1533 
1534 #endif
1535 
1536 /*
1537  * READLINK
1538  */
1539 int
1540 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1541 {
1542     hctransaction_t trans;
1543     struct HCHead *head;
1544     struct HCLeaf *item;
1545     int r;
1546 
1547     if (hc == NULL || hc->host == NULL)
1548 	return(readlink(path, buf, bufsiz));
1549 
1550     trans = hcc_start_command(hc, HC_READLINK);
1551     hcc_leaf_string(trans, LC_PATH1, path);
1552     if ((head = hcc_finish_command(trans)) == NULL)
1553 	return(-1);
1554     if (head->error)
1555 	return(-1);
1556 
1557     r = 0;
1558     FOR_EACH_ITEM(item, trans, head) {
1559 	if (item->leafid == LC_DATA) {
1560 	    r = item->bytes - sizeof(*item);
1561 	    if (r < 0)
1562 		r = 0;
1563 	    if (r > bufsiz)
1564 		r = bufsiz;
1565 	    bcopy(HCC_BINARYDATA(item), buf, r);
1566 	}
1567     }
1568     return(r);
1569 }
1570 
1571 static int
1572 rc_readlink(hctransaction_t trans, struct HCHead *head)
1573 {
1574     struct HCLeaf *item;
1575     const char *path = NULL;
1576     char buf[1024];
1577     int r;
1578 
1579     FOR_EACH_ITEM(item, trans, head) {
1580 	if (item->leafid == LC_PATH1)
1581 	    path = HCC_STRING(item);
1582     }
1583     if (path == NULL)
1584 	return(-2);
1585     r = readlink(path, buf, sizeof(buf));
1586     if (r < 0)
1587 	return(-1);
1588     hcc_leaf_data(trans, LC_DATA, buf, r);
1589     return(0);
1590 }
1591 
1592 /*
1593  * UMASK
1594  */
1595 mode_t
1596 hc_umask(struct HostConf *hc, mode_t numask)
1597 {
1598     hctransaction_t trans;
1599     struct HCHead *head;
1600     struct HCLeaf *item;
1601 
1602     if (hc == NULL || hc->host == NULL)
1603 	return(umask(numask));
1604 
1605     trans = hcc_start_command(hc, HC_UMASK);
1606     hcc_leaf_int32(trans, LC_MODE, numask);
1607     if ((head = hcc_finish_command(trans)) == NULL)
1608 	return((mode_t)-1);
1609     if (head->error)
1610 	return((mode_t)-1);
1611 
1612     numask = (mode_t) ~0666U;
1613     FOR_EACH_ITEM(item, trans, head) {
1614 	if (item->leafid == LC_MODE)
1615 	    numask = HCC_INT32(item);
1616     }
1617     return(numask);
1618 }
1619 
1620 static int
1621 rc_umask(hctransaction_t trans, struct HCHead *head)
1622 {
1623     struct HCLeaf *item;
1624     mode_t numask = (mode_t) ~0666U;
1625 
1626     FOR_EACH_ITEM(item, trans, head) {
1627 	if (item->leafid == LC_MODE)
1628 	    numask = HCC_INT32(item);
1629     }
1630     numask = umask(numask);
1631     hcc_leaf_int32(trans, LC_MODE, numask);
1632     return(0);
1633 }
1634 
1635 /*
1636  * SYMLINK
1637  */
1638 int
1639 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1640 {
1641     hctransaction_t trans;
1642     struct HCHead *head;
1643 
1644     if (hc == NULL || hc->host == NULL)
1645 	return(symlink(name1, name2));
1646 
1647     trans = hcc_start_command(hc, HC_SYMLINK);
1648     hcc_leaf_string(trans, LC_PATH1, name1);
1649     hcc_leaf_string(trans, LC_PATH2, name2);
1650     if ((head = hcc_finish_command(trans)) == NULL)
1651 	return(-1);
1652     if (head->error)
1653 	return(-1);
1654     return(0);
1655 }
1656 
1657 static int
1658 rc_symlink(hctransaction_t trans, struct HCHead *head)
1659 {
1660     struct HCLeaf *item;
1661     const char *name1 = NULL;
1662     const char *name2 = NULL;
1663 
1664     FOR_EACH_ITEM(item, trans, head) {
1665 	switch(item->leafid) {
1666 	case LC_PATH1:
1667 	    name1 = HCC_STRING(item);
1668 	    break;
1669 	case LC_PATH2:
1670 	    name2 = HCC_STRING(item);
1671 	    break;
1672 	}
1673     }
1674     if (ReadOnlyOpt) {
1675 	head->error = EACCES;
1676 	return (0);
1677     }
1678     if (name1 == NULL || name2 == NULL)
1679 	return(-2);
1680     return(symlink(name1, name2));
1681 }
1682 
1683 /*
1684  * RENAME
1685  */
1686 int
1687 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1688 {
1689     hctransaction_t trans;
1690     struct HCHead *head;
1691 
1692     if (hc == NULL || hc->host == NULL)
1693 	return(rename(name1, name2));
1694 
1695     trans = hcc_start_command(hc, HC_RENAME);
1696     hcc_leaf_string(trans, LC_PATH1, name1);
1697     hcc_leaf_string(trans, LC_PATH2, name2);
1698     if ((head = hcc_finish_command(trans)) == NULL)
1699 	return(-1);
1700     if (head->error)
1701 	return(-1);
1702     return(0);
1703 }
1704 
1705 static int
1706 rc_rename(hctransaction_t trans, struct HCHead *head)
1707 {
1708     struct HCLeaf *item;
1709     const char *name1 = NULL;
1710     const char *name2 = NULL;
1711 
1712     FOR_EACH_ITEM(item, trans, head) {
1713 	switch(item->leafid) {
1714 	case LC_PATH1:
1715 	    name1 = HCC_STRING(item);
1716 	    break;
1717 	case LC_PATH2:
1718 	    name2 = HCC_STRING(item);
1719 	    break;
1720 	}
1721     }
1722     if (ReadOnlyOpt) {
1723 	head->error = EACCES;
1724 	return (0);
1725     }
1726     if (name1 == NULL || name2 == NULL)
1727 	return(-2);
1728     return(rename(name1, name2));
1729 }
1730 
1731 /*
1732  * UTIMES
1733  */
1734 int
1735 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1736 {
1737     hctransaction_t trans;
1738     struct HCHead *head;
1739 
1740     if (hc == NULL || hc->host == NULL)
1741 	return(utimes(path, times));
1742 
1743     trans = hcc_start_command(hc, HC_UTIMES);
1744     hcc_leaf_string(trans, LC_PATH1, path);
1745     hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1746     hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1747     if ((head = hcc_finish_command(trans)) == NULL)
1748 	return(-1);
1749     if (head->error)
1750 	return(-1);
1751     return(0);
1752 }
1753 
1754 static int
1755 rc_utimes(hctransaction_t trans, struct HCHead *head)
1756 {
1757     struct HCLeaf *item;
1758     struct timeval times[2];
1759     const char *path;
1760 
1761     bzero(times, sizeof(times));
1762     path = NULL;
1763 
1764     FOR_EACH_ITEM(item, trans, head) {
1765 	switch(item->leafid) {
1766 	case LC_PATH1:
1767 	    path = HCC_STRING(item);
1768 	    break;
1769 	case LC_ATIME:
1770 	    times[0].tv_sec = HCC_INT64(item);
1771 	    break;
1772 	case LC_MTIME:
1773 	    times[1].tv_sec = HCC_INT64(item);
1774 	    break;
1775 	}
1776     }
1777     if (ReadOnlyOpt) {
1778 	head->error = EACCES;
1779 	return (0);
1780     }
1781     if (path == NULL)
1782 	return(-2);
1783     return(utimes(path, times));
1784 }
1785 
1786 uid_t
1787 hc_geteuid(struct HostConf *hc)
1788 {
1789     hctransaction_t trans;
1790     struct HCHead *head;
1791     struct HCLeaf *item;
1792 
1793     if (hc == NULL || hc->host == NULL)
1794 	return (geteuid());
1795 
1796     if (hc->version < 3) {
1797 	fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1798 	/* Return 0 on error, so the caller assumes root privileges. */
1799 	return (0);
1800     }
1801 
1802     trans = hcc_start_command(hc, HC_GETEUID);
1803     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1804 	return(0);
1805     FOR_EACH_ITEM(item, trans, head) {
1806 	if (item->leafid == LC_UID)
1807 	    return (HCC_INT32(item));
1808     }
1809     return(0); /* shouldn't happen */
1810 }
1811 
1812 static int
1813 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1814 {
1815     hcc_leaf_int32(trans, LC_UID, geteuid());
1816     return (0);
1817 }
1818 
1819 static int
1820 getmygroups(gid_t **gidlist)
1821 {
1822     int count;
1823 
1824     if ((count = getgroups(0, *gidlist)) > 0) {
1825 	if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1826 	    if ((count = getgroups(count, *gidlist)) <= 0)
1827 		free(*gidlist);
1828 	}
1829 	else
1830 	    count = -1;
1831     }
1832     else
1833 	*gidlist = NULL;
1834     return (count);
1835 }
1836 
1837 int
1838 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1839 {
1840     int count, i;
1841     hctransaction_t trans;
1842     struct HCHead *head;
1843     struct HCLeaf *item;
1844 
1845     if (hc == NULL || hc->host == NULL)
1846 	return (getmygroups(gidlist));
1847 
1848     i = 0;
1849     count = 0;
1850     *gidlist = NULL;
1851 
1852     if (hc->version < 3) {
1853 	fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1854 	return (-1);
1855     }
1856 
1857     trans = hcc_start_command(hc, HC_GETGROUPS);
1858     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1859 	return(-1);
1860     FOR_EACH_ITEM(item, trans, head) {
1861 	switch(item->leafid) {
1862 	case LC_COUNT:
1863 	    count = HCC_INT32(item);
1864 	    if (*gidlist != NULL) { /* protocol error */
1865 		free(*gidlist);
1866 		*gidlist = NULL;
1867 		return (-1);
1868 	    }
1869 	    if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1870 		return (-1);
1871 	    break;
1872 	case LC_GID:
1873 	    if (*gidlist == NULL || i >= count) { /* protocol error */
1874 		if (*gidlist != NULL)
1875 		    free(*gidlist);
1876 		*gidlist = NULL;
1877 		return (-1);
1878 	    }
1879 	    (*gidlist)[i++] = HCC_INT32(item);
1880 	    break;
1881 	}
1882     }
1883     return (count);
1884 }
1885 
1886 static int
1887 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1888 {
1889     int count, i;
1890     gid_t *gidlist;
1891 
1892     if ((count = getmygroups(&gidlist)) < 0)
1893 	return (-1);
1894     hcc_leaf_int32(trans, LC_COUNT, count);
1895     for (i = 0; i < count; i++)
1896 	hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1897     if (gidlist != NULL)
1898 	free(gidlist);
1899     return (0);
1900 }
1901