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