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