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