xref: /dragonfly/bin/cpdup/hcproto.c (revision 16dd80e4)
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     if (hc->trans.state == HCT_FAIL)
514 	return NULL;
515     return (denbuf.d_name[0] ? &denbuf : NULL);
516 }
517 
518 static int
519 rc_readdir(hctransaction_t trans, struct HCHead *head)
520 {
521     struct HCLeaf *item;
522     struct dirent *den;
523     DIR *dir = NULL;
524 
525     FOR_EACH_ITEM(item, trans, head) {
526 	if (item->leafid == LC_DESCRIPTOR)
527 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
528     }
529     if (dir == NULL)
530 	return(-2);
531     if ((den = readdir(dir)) != NULL)
532 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
533     return(0);
534 }
535 
536 /*
537  * CLOSEDIR
538  *
539  * XXX cpdup needs to check error code to avoid truncated dirs?
540  */
541 int
542 hc_closedir(struct HostConf *hc, DIR *dir)
543 {
544     struct HCHead *head;
545 
546     if (hc == NULL || hc->host == NULL)
547 	return(closedir(dir));
548 
549     if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
550 	hctransaction_t trans;
551 	struct dirent *den;
552 
553 	if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
554 	    free(den);
555 	    hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
556 	    trans = hcc_start_command(hc, HC_CLOSEDIR);
557 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
558 	    if ((head = hcc_finish_command(trans)) == NULL)
559 		return (-1);
560 	    if (head->error)
561 		return (-1);		/* XXX errno */
562 	    return (0);
563 	} else {
564 	    /* errno */
565 	    return(-1);
566 	}
567     }
568 
569     /* hc->version >= 4: using HC_SCANDIR */
570     head = (void *)dir;
571     /* skip any remaining items if the directory is closed prematurely */
572     while (hcc_nextchaineditem(hc, head) != NULL)
573 	/*nothing*/ ;
574     if (hc->trans.state == HCT_FAIL || head->error)
575 	return (-1);
576     return (0);
577 }
578 
579 static int
580 rc_closedir(hctransaction_t trans, struct HCHead *head)
581 {
582     struct HCLeaf *item;
583     DIR *dir = NULL;
584 
585     FOR_EACH_ITEM(item, trans, head) {
586 	if (item->leafid == LC_DESCRIPTOR) {
587 	    dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
588 	    if (dir != NULL) {
589 		    hcc_set_descriptor(trans->hc, HCC_INT32(item),
590 				       NULL, HC_DESC_DIR);
591 	    }
592 	}
593     }
594     if (dir == NULL)
595 	return(-2);
596     return(closedir(dir));
597 }
598 
599 /*
600  * SCANDIR
601  */
602 static int
603 rc_scandir(hctransaction_t trans, struct HCHead *head)
604 {
605     struct HCLeaf *item;
606     const char *path = NULL;
607     struct dirent *den;
608     DIR *dir;
609     char *fpath;
610     struct stat st;
611 
612     FOR_EACH_ITEM(item, trans, head) {
613 	if (item->leafid == LC_PATH1)
614 	    path = HCC_STRING(item);
615     }
616     if (path == NULL)
617 	return (-2);
618     if ((dir = opendir(path)) == NULL)
619 	return (-1);
620     while ((den = readdir(dir)) != NULL) {
621 	if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
622 		(den->d_name[1] == '.' && den->d_name[2] == '\0')))
623 	    continue;	/* skip "." and ".." */
624 	/*
625 	 * Check if there's enough space left in the current packet.
626 	 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
627 	 * one is a string, so we use strlen() + 1 (terminating zero).
628 	 * The remaining ones are numbers; we assume sizeof(int64_t) so
629 	 * we're on the safe side.
630 	 */
631 	if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
632 		(STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
633 		strlen(den->d_name) + 1)) {
634 	    closedir(dir);
635 	    return (-1);
636 	}
637 	fpath = mprintf("%s/%s", path, den->d_name);
638 	if (lstat(fpath, &st) == 0)
639 	    rc_encode_stat(trans, &st);
640 	/* The name must be the last item! */
641 	hcc_leaf_string(trans, LC_PATH1, den->d_name);
642 	free(fpath);
643     }
644     return (closedir(dir));
645 }
646 
647 /*
648  * OPEN
649  */
650 int
651 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
652 {
653     hctransaction_t trans;
654     struct HCHead *head;
655     struct HCLeaf *item;
656     int *fdp;
657     int desc = 0;
658     int nflags;
659 
660     if (NotForRealOpt && (flags & O_CREAT))
661 	return(0x7FFFFFFF);
662 
663     if (hc == NULL || hc->host == NULL) {
664 #ifdef O_LARGEFILE
665 	flags |= O_LARGEFILE;
666 #endif
667 	return(open(path, flags, mode));
668     }
669 
670     if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
671 	trans = hcc_start_command(hc, HC_READFILE);
672 	hcc_leaf_string(trans, LC_PATH1, path);
673 	if ((head = hcc_finish_command(trans)) == NULL || head->error)
674 	    return (-1);
675 	head->magic = 0; /* used to indicate offset within buffer */
676 	return (1); /* dummy */
677     }
678 
679     nflags = flags & XO_NATIVEMASK;
680     if (flags & O_CREAT)
681 	nflags |= XO_CREAT;
682     if (flags & O_EXCL)
683 	nflags |= XO_EXCL;
684     if (flags & O_TRUNC)
685 	nflags |= XO_TRUNC;
686 
687     trans = hcc_start_command(hc, HC_OPEN);
688     hcc_leaf_string(trans, LC_PATH1, path);
689     hcc_leaf_int32(trans, LC_OFLAGS, nflags);
690     hcc_leaf_int32(trans, LC_MODE, mode);
691 
692     if ((head = hcc_finish_command(trans)) == NULL)
693 	return(-1);
694     if (head->error)
695 	return(-1);
696     FOR_EACH_ITEM(item, trans, head) {
697 	if (item->leafid == LC_DESCRIPTOR)
698 	    desc = HCC_INT32(item);
699     }
700     if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
701 	fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
702 		desc);
703 	return(-1);
704     }
705     fdp = malloc(sizeof(int));
706     *fdp = desc;	/* really just a dummy */
707     hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
708     return(desc);
709 }
710 
711 static int
712 rc_open(hctransaction_t trans, struct HCHead *head)
713 {
714     struct HCLeaf *item;
715     const char *path = NULL;
716     int nflags = 0;
717     int flags;
718     mode_t mode = 0666;
719     int desc;
720     int *fdp;
721     int fd;
722 
723     FOR_EACH_ITEM(item, trans, head) {
724 	switch(item->leafid) {
725 	case LC_PATH1:
726 	    path = HCC_STRING(item);
727 	    break;
728 	case LC_OFLAGS:
729 	    nflags = HCC_INT32(item);
730 	    break;
731 	case LC_MODE:
732 	    mode = HCC_INT32(item);
733 	    break;
734 	}
735     }
736     if (path == NULL)
737 	return(-2);
738 
739     flags = nflags & XO_NATIVEMASK;
740     if (nflags & XO_CREAT)
741 	flags |= O_CREAT;
742     if (nflags & XO_EXCL)
743 	flags |= O_EXCL;
744     if (nflags & XO_TRUNC)
745 	flags |= O_TRUNC;
746 
747     if (ReadOnlyOpt) {
748 	if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
749 	    head->error = EACCES;
750 	    return (0);
751 	}
752 	flags |= O_RDONLY;
753     }
754 
755 #ifdef O_LARGEFILE
756     flags |= O_LARGEFILE;
757 #endif
758     if ((fd = open(path, flags, mode)) < 0)
759 	return(-1);
760     fdp = malloc(sizeof(int));
761     *fdp = fd;
762     desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
763     hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
764     return(0);
765 }
766 
767 /*
768  * CLOSE
769  */
770 int
771 hc_close(struct HostConf *hc, int fd)
772 {
773     hctransaction_t trans;
774     struct HCHead *head;
775     int *fdp;
776 
777     if (NotForRealOpt && fd == 0x7FFFFFFF)
778 	return(0);
779     if (hc == NULL || hc->host == NULL)
780 	return(close(fd));
781 
782     if (fd == 1 && hc->version >= 4) {	/* using HC_READFILE */
783 	head = (void *)hc->trans.rbuf;
784 	/* skip any remaining items if the file is closed prematurely */
785 	while (hcc_nextchaineditem(hc, head) != NULL)
786 	    /*nothing*/ ;
787 	if (hc->trans.state == HCT_FAIL || head->error)
788 	    return (-1);
789 	return (0);
790     }
791 
792     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
793     if (fdp) {
794 	free(fdp);
795 	hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
796 
797 	trans = hcc_start_command(hc, HC_CLOSE);
798 	hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
799 	if ((head = hcc_finish_command(trans)) == NULL)
800 	    return(-1);
801 	if (head->error)
802 	    return(-1);
803 	return(0);
804     } else {
805 	return(-1);
806     }
807 }
808 
809 static int
810 rc_close(hctransaction_t trans, struct HCHead *head)
811 {
812     struct HCLeaf *item;
813     int *fdp = NULL;
814     int fd;
815     int desc = -1;
816 
817     FOR_EACH_ITEM(item, trans, head) {
818 	if (item->leafid == LC_DESCRIPTOR)
819 	    desc = HCC_INT32(item);
820     }
821     if (desc < 0)
822 	return(-2);
823     if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
824 	return(-2);
825     fd = *fdp;
826     free(fdp);
827     hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
828     return(close(fd));
829 }
830 
831 static int
832 getiolimit(void)
833 {
834     return(32768);
835 }
836 
837 /*
838  * READ
839  */
840 ssize_t
841 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
842 {
843     hctransaction_t trans;
844     struct HCHead *head;
845     struct HCLeaf *item;
846     int *fdp;
847     int offset;
848     int r = 0;
849     int x = 0;
850 
851     if (hc == NULL || hc->host == NULL)
852 	return(read(fd, buf, bytes));
853 
854     if (fd == 1 && hc->version >= 4) {	/* using HC_READFILE */
855 	head = (void *)hc->trans.rbuf;
856 	while (bytes) {
857 	    if ((offset = head->magic) != 0) {
858 		item = hcc_currentchaineditem(hc, head);
859 	    } else {
860 		item = hcc_nextchaineditem(hc, head);
861 	    }
862 	    if (item == NULL) {
863 		if (hc->trans.state == HCT_FAIL)
864 			r = -1;
865 		return (r);
866 	    }
867 	    if (item->leafid != LC_DATA)
868 		return (-1);
869 	    x = item->bytes - sizeof(*item) - offset;
870 	    if (x > (int)bytes) {
871 		x = (int)bytes;
872 		head->magic += x;  /* leave bytes in the buffer */
873 	    }
874 	    else
875 		head->magic = 0;  /* all bytes used up */
876 	    bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
877 	    buf = (char *)buf + x;
878 	    bytes -= (size_t)x;
879 	    r += x;
880 	}
881 	return (r);
882     }
883 
884     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
885     if (fdp) {
886 	while (bytes) {
887 	    size_t limit = getiolimit();
888 	    int n = (bytes > limit) ? limit : bytes;
889 
890 	    trans = hcc_start_command(hc, HC_READ);
891 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
892 	    hcc_leaf_int32(trans, LC_BYTES, n);
893 	    if ((head = hcc_finish_command(trans)) == NULL)
894 		return(-1);
895 	    if (head->error)
896 		return(-1);
897 	    FOR_EACH_ITEM(item, trans, head) {
898 		if (item->leafid == LC_DATA) {
899 		    x = item->bytes - sizeof(*item);
900 		    if (x > (int)bytes)
901 			x = (int)bytes;
902 		    bcopy(HCC_BINARYDATA(item), buf, x);
903 		    buf = (char *)buf + x;
904 		    bytes -= (size_t)x;
905 		    r += x;
906 		}
907 	    }
908 	    if (x < n)
909 		break;
910 	}
911 	return(r);
912     } else {
913 	return(-1);
914     }
915 }
916 
917 static int
918 rc_read(hctransaction_t trans, struct HCHead *head)
919 {
920     struct HCLeaf *item;
921     int *fdp = NULL;
922     char buf[32768];
923     int bytes = -1;
924     int n;
925 
926     FOR_EACH_ITEM(item, trans, head) {
927 	switch(item->leafid) {
928 	case LC_DESCRIPTOR:
929 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
930 	    break;
931 	case LC_BYTES:
932 	    bytes = HCC_INT32(item);
933 	    break;
934 	}
935     }
936     if (fdp == NULL)
937 	return(-2);
938     if (bytes < 0 || bytes > 32768)
939 	return(-2);
940     n = read(*fdp, buf, bytes);
941     if (n < 0)
942 	return(-1);
943     hcc_leaf_data(trans, LC_DATA, buf, n);
944     return(0);
945 }
946 
947 /*
948  * READFILE
949  */
950 static int
951 rc_readfile(hctransaction_t trans, struct HCHead *head)
952 {
953     struct HCLeaf *item;
954     const char *path = NULL;
955     char buf[32768];
956     int n;
957     int fd;
958 
959     FOR_EACH_ITEM(item, trans, head) {
960 	if (item->leafid == LC_PATH1)
961 	    path = HCC_STRING(item);
962     }
963     if (path == NULL)
964 	return (-2);
965     if ((fd = open(path, O_RDONLY)) < 0)
966 	return(-1);
967     while ((n = read(fd, buf, 32768)) >= 0) {
968 	if (!hcc_check_space(trans, head, 1, n)) {
969 	    close(fd);
970 	    return (-1);
971 	}
972 	hcc_leaf_data(trans, LC_DATA, buf, n);
973 	if (n == 0)
974 		break;
975     }
976     if (n < 0) {
977 	close(fd);
978 	return (-1);
979     }
980     return (close(fd));
981 }
982 
983 /*
984  * WRITE
985  */
986 ssize_t
987 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
988 {
989     hctransaction_t trans;
990     struct HCHead *head;
991     struct HCLeaf *item;
992     int *fdp;
993     int r;
994 
995     if (NotForRealOpt)
996 	return(bytes);
997 
998     if (hc == NULL || hc->host == NULL)
999 	return(write(fd, buf, bytes));
1000 
1001     fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1002     if (fdp) {
1003 	r = 0;
1004 	while (bytes) {
1005 	    size_t limit = getiolimit();
1006 	    int n = (bytes > limit) ? limit : bytes;
1007 	    int x = 0;
1008 
1009 	    trans = hcc_start_command(hc, HC_WRITE);
1010 	    hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1011 	    hcc_leaf_data(trans, LC_DATA, buf, n);
1012 	    if ((head = hcc_finish_command(trans)) == NULL)
1013 		return(-1);
1014 	    if (head->error)
1015 		return(-1);
1016 	    FOR_EACH_ITEM(item, trans, head) {
1017 		if (item->leafid == LC_BYTES)
1018 		    x = HCC_INT32(item);
1019 	    }
1020 	    if (x < 0 || x > n)
1021 		return(-1);
1022 	    r += x;
1023 	    buf = (const char *)buf + x;
1024 	    bytes -= x;
1025 	    if (x < n)
1026 		break;
1027 	}
1028 	return(r);
1029     } else {
1030 	return(-1);
1031     }
1032 }
1033 
1034 static int
1035 rc_write(hctransaction_t trans, struct HCHead *head)
1036 {
1037     struct HCLeaf *item;
1038     int *fdp = NULL;
1039     void *buf = NULL;
1040     int n = -1;
1041 
1042     FOR_EACH_ITEM(item, trans, head) {
1043 	switch(item->leafid) {
1044 	case LC_DESCRIPTOR:
1045 	    fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1046 	    break;
1047 	case LC_DATA:
1048 	    buf = HCC_BINARYDATA(item);
1049 	    n = item->bytes - sizeof(*item);
1050 	    break;
1051 	}
1052     }
1053     if (ReadOnlyOpt) {
1054 	head->error = EACCES;
1055 	return (0);
1056     }
1057     if (fdp == NULL)
1058 	return(-2);
1059     if (n < 0 || n > 32768)
1060 	return(-2);
1061     n = write(*fdp, buf, n);
1062     if (n < 0)
1063 	return (-1);
1064     hcc_leaf_int32(trans, LC_BYTES, n);
1065     return(0);
1066 }
1067 
1068 /*
1069  * REMOVE
1070  *
1071  * NOTE: This function returns -errno if an error occured.
1072  */
1073 int
1074 hc_remove(struct HostConf *hc, const char *path)
1075 {
1076     hctransaction_t trans;
1077     struct HCHead *head;
1078     int res;
1079 
1080     if (NotForRealOpt)
1081 	return(0);
1082     if (hc == NULL || hc->host == NULL) {
1083 	res = remove(path);
1084 	if (res < 0)
1085 		res = -errno;
1086 	return(res);
1087     }
1088 
1089     trans = hcc_start_command(hc, HC_REMOVE);
1090     hcc_leaf_string(trans, LC_PATH1, path);
1091     if ((head = hcc_finish_command(trans)) == NULL)
1092 	return(-EIO);
1093     if (head->error)
1094 	return(-(int)head->error);
1095     return(0);
1096 }
1097 
1098 static int
1099 rc_remove(hctransaction_t trans, struct HCHead *head)
1100 {
1101     struct HCLeaf *item;
1102     const char *path = NULL;
1103 
1104     FOR_EACH_ITEM(item, trans, head) {
1105 	if (item->leafid == LC_PATH1)
1106 	    path = HCC_STRING(item);
1107     }
1108     if (path == NULL)
1109 	return(-2);
1110     if (ReadOnlyOpt) {
1111 	head->error = EACCES;
1112 	return (0);
1113     }
1114     return(remove(path));
1115 }
1116 
1117 /*
1118  * MKDIR
1119  */
1120 int
1121 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1122 {
1123     hctransaction_t trans;
1124     struct HCHead *head;
1125 
1126     if (NotForRealOpt)
1127 	return(0);
1128     if (hc == NULL || hc->host == NULL)
1129 	return(mkdir(path, mode));
1130 
1131     trans = hcc_start_command(hc, HC_MKDIR);
1132     hcc_leaf_string(trans, LC_PATH1, path);
1133     hcc_leaf_int32(trans, LC_MODE, mode);
1134     if ((head = hcc_finish_command(trans)) == NULL)
1135 	return(-1);
1136     if (head->error)
1137 	return(-1);
1138     return(0);
1139 }
1140 
1141 static int
1142 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1143 {
1144     struct HCLeaf *item;
1145     const char *path = NULL;
1146     mode_t mode = 0777;
1147 
1148     FOR_EACH_ITEM(item, trans, head) {
1149 	switch(item->leafid) {
1150 	case LC_PATH1:
1151 	    path = HCC_STRING(item);
1152 	    break;
1153 	case LC_MODE:
1154 	    mode = HCC_INT32(item);
1155 	    break;
1156 	}
1157     }
1158     if (ReadOnlyOpt) {
1159 	head->error = EACCES;
1160 	return (0);
1161     }
1162     if (path == NULL)
1163 	return(-2);
1164     return(mkdir(path, mode));
1165 }
1166 
1167 /*
1168  * RMDIR
1169  */
1170 int
1171 hc_rmdir(struct HostConf *hc, const char *path)
1172 {
1173     hctransaction_t trans;
1174     struct HCHead *head;
1175 
1176     if (NotForRealOpt)
1177 	return(0);
1178     if (hc == NULL || hc->host == NULL)
1179 	return(rmdir(path));
1180 
1181     trans = hcc_start_command(hc, HC_RMDIR);
1182     hcc_leaf_string(trans, LC_PATH1, path);
1183     if ((head = hcc_finish_command(trans)) == NULL)
1184 	return(-1);
1185     if (head->error)
1186 	return(-1);
1187     return(0);
1188 }
1189 
1190 static int
1191 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1192 {
1193     struct HCLeaf *item;
1194     const char *path = NULL;
1195 
1196     FOR_EACH_ITEM(item, trans, head) {
1197 	if (item->leafid == LC_PATH1)
1198 	    path = HCC_STRING(item);
1199     }
1200     if (ReadOnlyOpt) {
1201 	head->error = EACCES;
1202 	return (0);
1203     }
1204     if (path == NULL)
1205 	return(-2);
1206     return(rmdir(path));
1207 }
1208 
1209 /*
1210  * CHOWN
1211  *
1212  * Almost silently ignore chowns that fail if we are not root.
1213  */
1214 int
1215 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1216 {
1217     hctransaction_t trans;
1218     struct HCHead *head;
1219     int rc;
1220 
1221     if (NotForRealOpt)
1222 	return(0);
1223     if (!DstRootPrivs)
1224 	owner = -1;
1225 
1226     if (hc == NULL || hc->host == NULL) {
1227 	rc = chown(path, owner, group);
1228 	if (rc < 0)
1229 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1230 	return(rc);
1231     }
1232 
1233     trans = hcc_start_command(hc, HC_CHOWN);
1234     hcc_leaf_string(trans, LC_PATH1, path);
1235     hcc_leaf_int32(trans, LC_UID, owner);
1236     hcc_leaf_int32(trans, LC_GID, group);
1237     if ((head = hcc_finish_command(trans)) == NULL)
1238 	return(-1);
1239     if (head->error)
1240 	return(-1);
1241     return(0);
1242 }
1243 
1244 static int
1245 rc_chown(hctransaction_t trans, struct HCHead *head)
1246 {
1247     struct HCLeaf *item;
1248     const char *path = NULL;
1249     uid_t uid = (uid_t)-1;
1250     gid_t gid = (gid_t)-1;
1251     int rc;
1252 
1253     FOR_EACH_ITEM(item, trans, head) {
1254 	switch(item->leafid) {
1255 	case LC_PATH1:
1256 	    path = HCC_STRING(item);
1257 	    break;
1258 	case LC_UID:
1259 	    uid = HCC_INT32(item);
1260 	    break;
1261 	case LC_GID:
1262 	    gid = HCC_INT32(item);
1263 	    break;
1264 	}
1265     }
1266     if (ReadOnlyOpt) {
1267 	head->error = EACCES;
1268 	return (0);
1269     }
1270     if (path == NULL)
1271 	return(-2);
1272     rc = chown(path, uid, gid);
1273     if (rc < 0)
1274 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1275     return(rc);
1276 }
1277 
1278 /*
1279  * LCHOWN
1280  */
1281 int
1282 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1283 {
1284     hctransaction_t trans;
1285     struct HCHead *head;
1286     int rc;
1287 
1288     if (NotForRealOpt)
1289 	return(0);
1290     if (!DstRootPrivs)
1291 	owner = -1;
1292 
1293     if (hc == NULL || hc->host == NULL) {
1294 	rc = lchown(path, owner, group);
1295 	if (rc < 0)
1296 	    rc = silentwarning(&chown_warning, "file ownership may differ\n");
1297 	return(rc);
1298     }
1299 
1300     trans = hcc_start_command(hc, HC_LCHOWN);
1301     hcc_leaf_string(trans, LC_PATH1, path);
1302     hcc_leaf_int32(trans, LC_UID, owner);
1303     hcc_leaf_int32(trans, LC_GID, group);
1304     if ((head = hcc_finish_command(trans)) == NULL)
1305 	return(-1);
1306     if (head->error)
1307 	return(-1);
1308     return(0);
1309 }
1310 
1311 static int
1312 rc_lchown(hctransaction_t trans, struct HCHead *head)
1313 {
1314     struct HCLeaf *item;
1315     const char *path = NULL;
1316     uid_t uid = (uid_t)-1;
1317     gid_t gid = (gid_t)-1;
1318     int rc;
1319 
1320     FOR_EACH_ITEM(item, trans, head) {
1321 	switch(item->leafid) {
1322 	case LC_PATH1:
1323 	    path = HCC_STRING(item);
1324 	    break;
1325 	case LC_UID:
1326 	    uid = HCC_INT32(item);
1327 	    break;
1328 	case LC_GID:
1329 	    gid = HCC_INT32(item);
1330 	    break;
1331 	}
1332     }
1333     if (ReadOnlyOpt) {
1334 	head->error = EACCES;
1335 	return (0);
1336     }
1337     if (path == NULL)
1338 	return(-2);
1339     rc = lchown(path, uid, gid);
1340     if (rc < 0)
1341 	rc = silentwarning(&chown_warning, "file ownership may differ\n");
1342     return(rc);
1343 }
1344 
1345 /*
1346  * CHMOD
1347  */
1348 int
1349 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1350 {
1351     hctransaction_t trans;
1352     struct HCHead *head;
1353 
1354     if (NotForRealOpt)
1355 	return(0);
1356     if (hc == NULL || hc->host == NULL)
1357 	return(chmod(path, mode));
1358 
1359     trans = hcc_start_command(hc, HC_CHMOD);
1360     hcc_leaf_string(trans, LC_PATH1, path);
1361     hcc_leaf_int32(trans, LC_MODE, mode);
1362     if ((head = hcc_finish_command(trans)) == NULL)
1363 	return(-1);
1364     if (head->error)
1365 	return(-1);
1366     return(0);
1367 }
1368 
1369 static int
1370 rc_chmod(hctransaction_t trans, struct HCHead *head)
1371 {
1372     struct HCLeaf *item;
1373     const char *path = NULL;
1374     mode_t mode = 0666;
1375 
1376     FOR_EACH_ITEM(item, trans, head) {
1377 	switch(item->leafid) {
1378 	case LC_PATH1:
1379 	    path = HCC_STRING(item);
1380 	    break;
1381 	case LC_MODE:
1382 	    mode = HCC_INT32(item);
1383 	    break;
1384 	}
1385     }
1386     if (ReadOnlyOpt) {
1387 	head->error = EACCES;
1388 	return (0);
1389     }
1390     if (path == NULL)
1391 	return(-2);
1392     return(chmod(path, mode));
1393 }
1394 
1395 /*
1396  * MKNOD
1397  */
1398 int
1399 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1400 {
1401     hctransaction_t trans;
1402     struct HCHead *head;
1403 
1404     if (NotForRealOpt)
1405 	return(0);
1406     if (!DstRootPrivs) {
1407 	/* mknod() requires root privs, so don't bother. */
1408 	errno = EPERM;
1409 	return (-1);
1410     }
1411 
1412     if (hc == NULL || hc->host == NULL)
1413 	return(mknod(path, mode, rdev));
1414 
1415     trans = hcc_start_command(hc, HC_MKNOD);
1416     hcc_leaf_string(trans, LC_PATH1, path);
1417     hcc_leaf_int32(trans, LC_MODE, mode);
1418     hcc_leaf_int32(trans, LC_RDEV, rdev);
1419     if ((head = hcc_finish_command(trans)) == NULL)
1420 	return(-1);
1421     if (head->error)
1422 	return(-1);
1423     return(0);
1424 }
1425 
1426 static int
1427 rc_mknod(hctransaction_t trans, struct HCHead *head)
1428 {
1429     struct HCLeaf *item;
1430     const char *path = NULL;
1431     mode_t mode = 0666;
1432     dev_t rdev = 0;
1433 
1434     FOR_EACH_ITEM(item, trans, head) {
1435 	switch(item->leafid) {
1436 	case LC_PATH1:
1437 	    path = HCC_STRING(item);
1438 	    break;
1439 	case LC_MODE:
1440 	    mode = HCC_INT32(item);
1441 	    break;
1442 	case LC_RDEV:
1443 	    rdev = HCC_INT32(item);
1444 	    break;
1445 	}
1446     }
1447     if (ReadOnlyOpt) {
1448 	head->error = EACCES;
1449 	return (0);
1450     }
1451     if (path == NULL)
1452 	return(-2);
1453     return(mknod(path, mode, rdev));
1454 }
1455 
1456 /*
1457  * LINK
1458  */
1459 int
1460 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1461 {
1462     hctransaction_t trans;
1463     struct HCHead *head;
1464 
1465     if (NotForRealOpt)
1466 	return(0);
1467     if (hc == NULL || hc->host == NULL)
1468 	return(link(name1, name2));
1469 
1470     trans = hcc_start_command(hc, HC_LINK);
1471     hcc_leaf_string(trans, LC_PATH1, name1);
1472     hcc_leaf_string(trans, LC_PATH2, name2);
1473     if ((head = hcc_finish_command(trans)) == NULL)
1474 	return(-1);
1475     if (head->error)
1476 	return(-1);
1477     return(0);
1478 }
1479 
1480 static int
1481 rc_link(hctransaction_t trans, struct HCHead *head)
1482 {
1483     struct HCLeaf *item;
1484     const char *name1 = NULL;
1485     const char *name2 = NULL;
1486 
1487     FOR_EACH_ITEM(item, trans, head) {
1488 	switch(item->leafid) {
1489 	case LC_PATH1:
1490 	    name1 = HCC_STRING(item);
1491 	    break;
1492 	case LC_PATH2:
1493 	    name2 = HCC_STRING(item);
1494 	    break;
1495 	}
1496     }
1497     if (ReadOnlyOpt) {
1498 	head->error = EACCES;
1499 	return (-0);
1500     }
1501     if (name1 == NULL || name2 == NULL)
1502 	return(-2);
1503     return(link(name1, name2));
1504 }
1505 
1506 #ifdef _ST_FLAGS_PRESENT_
1507 /*
1508  * CHFLAGS
1509  */
1510 int
1511 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1512 {
1513     hctransaction_t trans;
1514     struct HCHead *head;
1515     int rc;
1516 
1517     if (NotForRealOpt)
1518 	return(0);
1519     if (!DstRootPrivs)
1520 	flags &= UF_SETTABLE;
1521 
1522     if (hc == NULL || hc->host == NULL) {
1523 	if ((rc = chflags(path, flags)) < 0)
1524 	    rc = silentwarning(&chflags_warning, "file flags may differ\n");
1525 	return (rc);
1526     }
1527 
1528     trans = hcc_start_command(hc, HC_CHFLAGS);
1529     hcc_leaf_string(trans, LC_PATH1, path);
1530     hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1531     if ((head = hcc_finish_command(trans)) == NULL)
1532 	return(-1);
1533     if (head->error)
1534 	return(-1);
1535     return(0);
1536 }
1537 
1538 static int
1539 rc_chflags(hctransaction_t trans, struct HCHead *head)
1540 {
1541     struct HCLeaf *item;
1542     const char *path = NULL;
1543     u_long flags = 0;
1544     int rc;
1545 
1546     FOR_EACH_ITEM(item, trans, head) {
1547 	switch(item->leafid) {
1548 	case LC_PATH1:
1549 	    path = HCC_STRING(item);
1550 	    break;
1551 	case LC_FILEFLAGS:
1552 	    flags = (u_long)HCC_INT64(item);
1553 	    break;
1554 	}
1555     }
1556     if (ReadOnlyOpt) {
1557 	head->error = EACCES;
1558 	return (0);
1559     }
1560     if (path == NULL)
1561 	return(-2);
1562     if ((rc = chflags(path, flags)) < 0)
1563 	rc = silentwarning(&chflags_warning, "file flags may differ\n");
1564     return(rc);
1565 }
1566 
1567 #endif
1568 
1569 /*
1570  * READLINK
1571  */
1572 int
1573 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1574 {
1575     hctransaction_t trans;
1576     struct HCHead *head;
1577     struct HCLeaf *item;
1578     int r;
1579 
1580     if (hc == NULL || hc->host == NULL)
1581 	return(readlink(path, buf, bufsiz));
1582 
1583     trans = hcc_start_command(hc, HC_READLINK);
1584     hcc_leaf_string(trans, LC_PATH1, path);
1585     if ((head = hcc_finish_command(trans)) == NULL)
1586 	return(-1);
1587     if (head->error)
1588 	return(-1);
1589 
1590     r = 0;
1591     FOR_EACH_ITEM(item, trans, head) {
1592 	if (item->leafid == LC_DATA) {
1593 	    r = item->bytes - sizeof(*item);
1594 	    if (r < 0)
1595 		r = 0;
1596 	    if (r > bufsiz)
1597 		r = bufsiz;
1598 	    bcopy(HCC_BINARYDATA(item), buf, r);
1599 	}
1600     }
1601     return(r);
1602 }
1603 
1604 static int
1605 rc_readlink(hctransaction_t trans, struct HCHead *head)
1606 {
1607     struct HCLeaf *item;
1608     const char *path = NULL;
1609     char buf[1024];
1610     int r;
1611 
1612     FOR_EACH_ITEM(item, trans, head) {
1613 	if (item->leafid == LC_PATH1)
1614 	    path = HCC_STRING(item);
1615     }
1616     if (path == NULL)
1617 	return(-2);
1618     r = readlink(path, buf, sizeof(buf));
1619     if (r < 0)
1620 	return(-1);
1621     hcc_leaf_data(trans, LC_DATA, buf, r);
1622     return(0);
1623 }
1624 
1625 /*
1626  * UMASK
1627  */
1628 mode_t
1629 hc_umask(struct HostConf *hc, mode_t numask)
1630 {
1631     hctransaction_t trans;
1632     struct HCHead *head;
1633     struct HCLeaf *item;
1634 
1635     if (NotForRealOpt)
1636 	return(umask(numask));
1637     if (hc == NULL || hc->host == NULL)
1638 	return(umask(numask));
1639 
1640     trans = hcc_start_command(hc, HC_UMASK);
1641     hcc_leaf_int32(trans, LC_MODE, numask);
1642     if ((head = hcc_finish_command(trans)) == NULL)
1643 	return((mode_t)-1);
1644     if (head->error)
1645 	return((mode_t)-1);
1646 
1647     numask = (mode_t) ~0666U;
1648     FOR_EACH_ITEM(item, trans, head) {
1649 	if (item->leafid == LC_MODE)
1650 	    numask = HCC_INT32(item);
1651     }
1652     return(numask);
1653 }
1654 
1655 static int
1656 rc_umask(hctransaction_t trans, struct HCHead *head)
1657 {
1658     struct HCLeaf *item;
1659     mode_t numask = (mode_t) ~0666U;
1660 
1661     FOR_EACH_ITEM(item, trans, head) {
1662 	if (item->leafid == LC_MODE)
1663 	    numask = HCC_INT32(item);
1664     }
1665     numask = umask(numask);
1666     hcc_leaf_int32(trans, LC_MODE, numask);
1667     return(0);
1668 }
1669 
1670 /*
1671  * SYMLINK
1672  */
1673 int
1674 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1675 {
1676     hctransaction_t trans;
1677     struct HCHead *head;
1678 
1679     if (NotForRealOpt)
1680 	return(0);
1681     if (hc == NULL || hc->host == NULL)
1682 	return(symlink(name1, name2));
1683 
1684     trans = hcc_start_command(hc, HC_SYMLINK);
1685     hcc_leaf_string(trans, LC_PATH1, name1);
1686     hcc_leaf_string(trans, LC_PATH2, name2);
1687     if ((head = hcc_finish_command(trans)) == NULL)
1688 	return(-1);
1689     if (head->error)
1690 	return(-1);
1691     return(0);
1692 }
1693 
1694 static int
1695 rc_symlink(hctransaction_t trans, struct HCHead *head)
1696 {
1697     struct HCLeaf *item;
1698     const char *name1 = NULL;
1699     const char *name2 = NULL;
1700 
1701     FOR_EACH_ITEM(item, trans, head) {
1702 	switch(item->leafid) {
1703 	case LC_PATH1:
1704 	    name1 = HCC_STRING(item);
1705 	    break;
1706 	case LC_PATH2:
1707 	    name2 = HCC_STRING(item);
1708 	    break;
1709 	}
1710     }
1711     if (ReadOnlyOpt) {
1712 	head->error = EACCES;
1713 	return (0);
1714     }
1715     if (name1 == NULL || name2 == NULL)
1716 	return(-2);
1717     return(symlink(name1, name2));
1718 }
1719 
1720 /*
1721  * RENAME
1722  */
1723 int
1724 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1725 {
1726     hctransaction_t trans;
1727     struct HCHead *head;
1728 
1729     if (NotForRealOpt)
1730 	return(0);
1731     if (hc == NULL || hc->host == NULL)
1732 	return(rename(name1, name2));
1733 
1734     trans = hcc_start_command(hc, HC_RENAME);
1735     hcc_leaf_string(trans, LC_PATH1, name1);
1736     hcc_leaf_string(trans, LC_PATH2, name2);
1737     if ((head = hcc_finish_command(trans)) == NULL)
1738 	return(-1);
1739     if (head->error)
1740 	return(-1);
1741     return(0);
1742 }
1743 
1744 static int
1745 rc_rename(hctransaction_t trans, struct HCHead *head)
1746 {
1747     struct HCLeaf *item;
1748     const char *name1 = NULL;
1749     const char *name2 = NULL;
1750 
1751     FOR_EACH_ITEM(item, trans, head) {
1752 	switch(item->leafid) {
1753 	case LC_PATH1:
1754 	    name1 = HCC_STRING(item);
1755 	    break;
1756 	case LC_PATH2:
1757 	    name2 = HCC_STRING(item);
1758 	    break;
1759 	}
1760     }
1761     if (ReadOnlyOpt) {
1762 	head->error = EACCES;
1763 	return (0);
1764     }
1765     if (name1 == NULL || name2 == NULL)
1766 	return(-2);
1767     return(rename(name1, name2));
1768 }
1769 
1770 /*
1771  * UTIMES
1772  */
1773 int
1774 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1775 {
1776     hctransaction_t trans;
1777     struct HCHead *head;
1778 
1779     if (NotForRealOpt)
1780 	return(0);
1781     if (hc == NULL || hc->host == NULL)
1782 	return(utimes(path, times));
1783 
1784     trans = hcc_start_command(hc, HC_UTIMES);
1785     hcc_leaf_string(trans, LC_PATH1, path);
1786     hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1787     hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1788     if ((head = hcc_finish_command(trans)) == NULL)
1789 	return(-1);
1790     if (head->error)
1791 	return(-1);
1792     return(0);
1793 }
1794 
1795 static int
1796 rc_utimes(hctransaction_t trans, struct HCHead *head)
1797 {
1798     struct HCLeaf *item;
1799     struct timeval times[2];
1800     const char *path;
1801 
1802     bzero(times, sizeof(times));
1803     path = NULL;
1804 
1805     FOR_EACH_ITEM(item, trans, head) {
1806 	switch(item->leafid) {
1807 	case LC_PATH1:
1808 	    path = HCC_STRING(item);
1809 	    break;
1810 	case LC_ATIME:
1811 	    times[0].tv_sec = HCC_INT64(item);
1812 	    break;
1813 	case LC_MTIME:
1814 	    times[1].tv_sec = HCC_INT64(item);
1815 	    break;
1816 	}
1817     }
1818     if (ReadOnlyOpt) {
1819 	head->error = EACCES;
1820 	return (0);
1821     }
1822     if (path == NULL)
1823 	return(-2);
1824     return(utimes(path, times));
1825 }
1826 
1827 uid_t
1828 hc_geteuid(struct HostConf *hc)
1829 {
1830     hctransaction_t trans;
1831     struct HCHead *head;
1832     struct HCLeaf *item;
1833 
1834     if (hc == NULL || hc->host == NULL)
1835 	return (geteuid());
1836 
1837     if (hc->version < 3) {
1838 	fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1839 	/* Return 0 on error, so the caller assumes root privileges. */
1840 	return (0);
1841     }
1842 
1843     trans = hcc_start_command(hc, HC_GETEUID);
1844     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1845 	return(0);
1846     FOR_EACH_ITEM(item, trans, head) {
1847 	if (item->leafid == LC_UID)
1848 	    return (HCC_INT32(item));
1849     }
1850     return(0); /* shouldn't happen */
1851 }
1852 
1853 static int
1854 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1855 {
1856     hcc_leaf_int32(trans, LC_UID, geteuid());
1857     return (0);
1858 }
1859 
1860 static int
1861 getmygroups(gid_t **gidlist)
1862 {
1863     int count;
1864 
1865     if ((count = getgroups(0, *gidlist)) > 0) {
1866 	if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1867 	    if ((count = getgroups(count, *gidlist)) <= 0)
1868 		free(*gidlist);
1869 	}
1870 	else
1871 	    count = -1;
1872     }
1873     else
1874 	*gidlist = NULL;
1875     return (count);
1876 }
1877 
1878 int
1879 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1880 {
1881     int count, i;
1882     hctransaction_t trans;
1883     struct HCHead *head;
1884     struct HCLeaf *item;
1885 
1886     if (hc == NULL || hc->host == NULL)
1887 	return (getmygroups(gidlist));
1888 
1889     i = 0;
1890     count = 0;
1891     *gidlist = NULL;
1892 
1893     if (hc->version < 3) {
1894 	fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1895 	return (-1);
1896     }
1897 
1898     trans = hcc_start_command(hc, HC_GETGROUPS);
1899     if ((head = hcc_finish_command(trans)) == NULL || head->error)
1900 	return(-1);
1901     FOR_EACH_ITEM(item, trans, head) {
1902 	switch(item->leafid) {
1903 	case LC_COUNT:
1904 	    count = HCC_INT32(item);
1905 	    if (*gidlist != NULL) { /* protocol error */
1906 		free(*gidlist);
1907 		*gidlist = NULL;
1908 		return (-1);
1909 	    }
1910 	    if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1911 		return (-1);
1912 	    break;
1913 	case LC_GID:
1914 	    if (*gidlist == NULL || i >= count) { /* protocol error */
1915 		if (*gidlist != NULL)
1916 		    free(*gidlist);
1917 		*gidlist = NULL;
1918 		return (-1);
1919 	    }
1920 	    (*gidlist)[i++] = HCC_INT32(item);
1921 	    break;
1922 	}
1923     }
1924     return (count);
1925 }
1926 
1927 static int
1928 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1929 {
1930     int count, i;
1931     gid_t *gidlist;
1932 
1933     if ((count = getmygroups(&gidlist)) < 0)
1934 	return (-1);
1935     hcc_leaf_int32(trans, LC_COUNT, count);
1936     for (i = 0; i < count; i++)
1937 	hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1938     if (gidlist != NULL)
1939 	free(gidlist);
1940     return (0);
1941 }
1942