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