Merge branch 'vendor/OPENRESOLV' with the following changes:
[dragonfly.git] / bin / cpdup / hcproto.c
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 }