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