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