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