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