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 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 (NotForRealOpt && (flags & O_CREAT)) 660 return(0x7FFFFFFF); 661 662 if (hc == NULL || hc->host == NULL) { 663 #ifdef O_LARGEFILE 664 flags |= O_LARGEFILE; 665 #endif 666 return(open(path, flags, mode)); 667 } 668 669 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) { 670 trans = hcc_start_command(hc, HC_READFILE); 671 hcc_leaf_string(trans, LC_PATH1, path); 672 if ((head = hcc_finish_command(trans)) == NULL || head->error) 673 return (-1); 674 head->magic = 0; /* used to indicate offset within buffer */ 675 return (1); /* dummy */ 676 } 677 678 nflags = flags & XO_NATIVEMASK; 679 if (flags & O_CREAT) 680 nflags |= XO_CREAT; 681 if (flags & O_EXCL) 682 nflags |= XO_EXCL; 683 if (flags & O_TRUNC) 684 nflags |= XO_TRUNC; 685 686 trans = hcc_start_command(hc, HC_OPEN); 687 hcc_leaf_string(trans, LC_PATH1, path); 688 hcc_leaf_int32(trans, LC_OFLAGS, nflags); 689 hcc_leaf_int32(trans, LC_MODE, mode); 690 691 if ((head = hcc_finish_command(trans)) == NULL) 692 return(-1); 693 if (head->error) 694 return(-1); 695 FOR_EACH_ITEM(item, trans, head) { 696 if (item->leafid == LC_DESCRIPTOR) 697 desc = HCC_INT32(item); 698 } 699 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) { 700 fprintf(stderr, "hc_open: remote reused active descriptor %d\n", 701 desc); 702 return(-1); 703 } 704 fdp = malloc(sizeof(int)); 705 *fdp = desc; /* really just a dummy */ 706 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD); 707 return(desc); 708 } 709 710 static int 711 rc_open(hctransaction_t trans, struct HCHead *head) 712 { 713 struct HCLeaf *item; 714 const char *path = NULL; 715 int nflags = 0; 716 int flags; 717 mode_t mode = 0666; 718 int desc; 719 int *fdp; 720 int fd; 721 722 FOR_EACH_ITEM(item, trans, head) { 723 switch(item->leafid) { 724 case LC_PATH1: 725 path = HCC_STRING(item); 726 break; 727 case LC_OFLAGS: 728 nflags = HCC_INT32(item); 729 break; 730 case LC_MODE: 731 mode = HCC_INT32(item); 732 break; 733 } 734 } 735 if (path == NULL) 736 return(-2); 737 738 flags = nflags & XO_NATIVEMASK; 739 if (nflags & XO_CREAT) 740 flags |= O_CREAT; 741 if (nflags & XO_EXCL) 742 flags |= O_EXCL; 743 if (nflags & XO_TRUNC) 744 flags |= O_TRUNC; 745 746 if (ReadOnlyOpt) { 747 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) { 748 head->error = EACCES; 749 return (0); 750 } 751 flags |= O_RDONLY; 752 } 753 754 #ifdef O_LARGEFILE 755 flags |= O_LARGEFILE; 756 #endif 757 if ((fd = open(path, flags, mode)) < 0) 758 return(-1); 759 fdp = malloc(sizeof(int)); 760 *fdp = fd; 761 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD); 762 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc); 763 return(0); 764 } 765 766 /* 767 * CLOSE 768 */ 769 int 770 hc_close(struct HostConf *hc, int fd) 771 { 772 hctransaction_t trans; 773 struct HCHead *head; 774 int *fdp; 775 776 if (NotForRealOpt && fd == 0x7FFFFFFF) 777 return(0); 778 if (hc == NULL || hc->host == NULL) 779 return(close(fd)); 780 781 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */ 782 head = (void *)hc->trans.rbuf; 783 /* skip any remaining items if the file is closed prematurely */ 784 while (hcc_nextchaineditem(hc, head) != NULL) 785 /*nothing*/ ; 786 if (head->error) 787 return (-1); 788 return (0); 789 } 790 791 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD); 792 if (fdp) { 793 free(fdp); 794 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD); 795 796 trans = hcc_start_command(hc, HC_CLOSE); 797 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd); 798 if ((head = hcc_finish_command(trans)) == NULL) 799 return(-1); 800 if (head->error) 801 return(-1); 802 return(0); 803 } else { 804 return(-1); 805 } 806 } 807 808 static int 809 rc_close(hctransaction_t trans, struct HCHead *head) 810 { 811 struct HCLeaf *item; 812 int *fdp = NULL; 813 int fd; 814 int desc = -1; 815 816 FOR_EACH_ITEM(item, trans, head) { 817 if (item->leafid == LC_DESCRIPTOR) 818 desc = HCC_INT32(item); 819 } 820 if (desc < 0) 821 return(-2); 822 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL) 823 return(-2); 824 fd = *fdp; 825 free(fdp); 826 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD); 827 return(close(fd)); 828 } 829 830 static int 831 getiolimit(void) 832 { 833 return(32768); 834 } 835 836 /* 837 * READ 838 */ 839 ssize_t 840 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes) 841 { 842 hctransaction_t trans; 843 struct HCHead *head; 844 struct HCLeaf *item; 845 int *fdp; 846 int offset; 847 int r = 0; 848 int x = 0; 849 850 if (hc == NULL || hc->host == NULL) 851 return(read(fd, buf, bytes)); 852 853 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */ 854 head = (void *)hc->trans.rbuf; 855 while (bytes) { 856 if ((offset = head->magic) != 0) 857 item = hcc_currentchaineditem(hc, head); 858 else 859 item = hcc_nextchaineditem(hc, head); 860 if (item == NULL) 861 return (r); 862 if (item->leafid != LC_DATA) 863 return (-1); 864 x = item->bytes - sizeof(*item) - offset; 865 if (x > (int)bytes) { 866 x = (int)bytes; 867 head->magic += x; /* leave bytes in the buffer */ 868 } 869 else 870 head->magic = 0; /* all bytes used up */ 871 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x); 872 buf = (char *)buf + x; 873 bytes -= (size_t)x; 874 r += x; 875 } 876 return (r); 877 } 878 879 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD); 880 if (fdp) { 881 while (bytes) { 882 size_t limit = getiolimit(); 883 int n = (bytes > limit) ? limit : bytes; 884 885 trans = hcc_start_command(hc, HC_READ); 886 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd); 887 hcc_leaf_int32(trans, LC_BYTES, n); 888 if ((head = hcc_finish_command(trans)) == NULL) 889 return(-1); 890 if (head->error) 891 return(-1); 892 FOR_EACH_ITEM(item, trans, head) { 893 if (item->leafid == LC_DATA) { 894 x = item->bytes - sizeof(*item); 895 if (x > (int)bytes) 896 x = (int)bytes; 897 bcopy(HCC_BINARYDATA(item), buf, x); 898 buf = (char *)buf + x; 899 bytes -= (size_t)x; 900 r += x; 901 } 902 } 903 if (x < n) 904 break; 905 } 906 return(r); 907 } else { 908 return(-1); 909 } 910 } 911 912 static int 913 rc_read(hctransaction_t trans, struct HCHead *head) 914 { 915 struct HCLeaf *item; 916 int *fdp = NULL; 917 char buf[32768]; 918 int bytes = -1; 919 int n; 920 921 FOR_EACH_ITEM(item, trans, head) { 922 switch(item->leafid) { 923 case LC_DESCRIPTOR: 924 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD); 925 break; 926 case LC_BYTES: 927 bytes = HCC_INT32(item); 928 break; 929 } 930 } 931 if (fdp == NULL) 932 return(-2); 933 if (bytes < 0 || bytes > 32768) 934 return(-2); 935 n = read(*fdp, buf, bytes); 936 if (n < 0) 937 return(-1); 938 hcc_leaf_data(trans, LC_DATA, buf, n); 939 return(0); 940 } 941 942 /* 943 * READFILE 944 */ 945 static int 946 rc_readfile(hctransaction_t trans, struct HCHead *head) 947 { 948 struct HCLeaf *item; 949 const char *path = NULL; 950 char buf[32768]; 951 int n; 952 int fd; 953 954 FOR_EACH_ITEM(item, trans, head) { 955 if (item->leafid == LC_PATH1) 956 path = HCC_STRING(item); 957 } 958 if (path == NULL) 959 return (-2); 960 if ((fd = open(path, O_RDONLY)) < 0) 961 return(-1); 962 while ((n = read(fd, buf, 32768)) >= 0) { 963 if (!hcc_check_space(trans, head, 1, n)) { 964 close(fd); 965 return (-1); 966 } 967 hcc_leaf_data(trans, LC_DATA, buf, n); 968 if (n == 0) 969 break; 970 } 971 if (n < 0) { 972 close(fd); 973 return (-1); 974 } 975 return (close(fd)); 976 } 977 978 /* 979 * WRITE 980 */ 981 ssize_t 982 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes) 983 { 984 hctransaction_t trans; 985 struct HCHead *head; 986 struct HCLeaf *item; 987 int *fdp; 988 int r; 989 990 if (NotForRealOpt) 991 return(bytes); 992 993 if (hc == NULL || hc->host == NULL) 994 return(write(fd, buf, bytes)); 995 996 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD); 997 if (fdp) { 998 r = 0; 999 while (bytes) { 1000 size_t limit = getiolimit(); 1001 int n = (bytes > limit) ? limit : bytes; 1002 int x = 0; 1003 1004 trans = hcc_start_command(hc, HC_WRITE); 1005 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd); 1006 hcc_leaf_data(trans, LC_DATA, buf, n); 1007 if ((head = hcc_finish_command(trans)) == NULL) 1008 return(-1); 1009 if (head->error) 1010 return(-1); 1011 FOR_EACH_ITEM(item, trans, head) { 1012 if (item->leafid == LC_BYTES) 1013 x = HCC_INT32(item); 1014 } 1015 if (x < 0 || x > n) 1016 return(-1); 1017 r += x; 1018 buf = (const char *)buf + x; 1019 bytes -= x; 1020 if (x < n) 1021 break; 1022 } 1023 return(r); 1024 } else { 1025 return(-1); 1026 } 1027 } 1028 1029 static int 1030 rc_write(hctransaction_t trans, struct HCHead *head) 1031 { 1032 struct HCLeaf *item; 1033 int *fdp = NULL; 1034 void *buf = NULL; 1035 int n = -1; 1036 1037 FOR_EACH_ITEM(item, trans, head) { 1038 switch(item->leafid) { 1039 case LC_DESCRIPTOR: 1040 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD); 1041 break; 1042 case LC_DATA: 1043 buf = HCC_BINARYDATA(item); 1044 n = item->bytes - sizeof(*item); 1045 break; 1046 } 1047 } 1048 if (ReadOnlyOpt) { 1049 head->error = EACCES; 1050 return (0); 1051 } 1052 if (fdp == NULL) 1053 return(-2); 1054 if (n < 0 || n > 32768) 1055 return(-2); 1056 n = write(*fdp, buf, n); 1057 if (n < 0) 1058 return (-1); 1059 hcc_leaf_int32(trans, LC_BYTES, n); 1060 return(0); 1061 } 1062 1063 /* 1064 * REMOVE 1065 * 1066 * NOTE: This function returns -errno if an error occured. 1067 */ 1068 int 1069 hc_remove(struct HostConf *hc, const char *path) 1070 { 1071 hctransaction_t trans; 1072 struct HCHead *head; 1073 int res; 1074 1075 if (NotForRealOpt) 1076 return(0); 1077 if (hc == NULL || hc->host == NULL) { 1078 res = remove(path); 1079 if (res < 0) 1080 res = -errno; 1081 return(res); 1082 } 1083 1084 trans = hcc_start_command(hc, HC_REMOVE); 1085 hcc_leaf_string(trans, LC_PATH1, path); 1086 if ((head = hcc_finish_command(trans)) == NULL) 1087 return(-EIO); 1088 if (head->error) 1089 return(-(int)head->error); 1090 return(0); 1091 } 1092 1093 static int 1094 rc_remove(hctransaction_t trans, struct HCHead *head) 1095 { 1096 struct HCLeaf *item; 1097 const char *path = NULL; 1098 1099 FOR_EACH_ITEM(item, trans, head) { 1100 if (item->leafid == LC_PATH1) 1101 path = HCC_STRING(item); 1102 } 1103 if (path == NULL) 1104 return(-2); 1105 if (ReadOnlyOpt) { 1106 head->error = EACCES; 1107 return (0); 1108 } 1109 return(remove(path)); 1110 } 1111 1112 /* 1113 * MKDIR 1114 */ 1115 int 1116 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode) 1117 { 1118 hctransaction_t trans; 1119 struct HCHead *head; 1120 1121 if (NotForRealOpt) 1122 return(0); 1123 if (hc == NULL || hc->host == NULL) 1124 return(mkdir(path, mode)); 1125 1126 trans = hcc_start_command(hc, HC_MKDIR); 1127 hcc_leaf_string(trans, LC_PATH1, path); 1128 hcc_leaf_int32(trans, LC_MODE, mode); 1129 if ((head = hcc_finish_command(trans)) == NULL) 1130 return(-1); 1131 if (head->error) 1132 return(-1); 1133 return(0); 1134 } 1135 1136 static int 1137 rc_mkdir(hctransaction_t trans, struct HCHead *head) 1138 { 1139 struct HCLeaf *item; 1140 const char *path = NULL; 1141 mode_t mode = 0777; 1142 1143 FOR_EACH_ITEM(item, trans, head) { 1144 switch(item->leafid) { 1145 case LC_PATH1: 1146 path = HCC_STRING(item); 1147 break; 1148 case LC_MODE: 1149 mode = HCC_INT32(item); 1150 break; 1151 } 1152 } 1153 if (ReadOnlyOpt) { 1154 head->error = EACCES; 1155 return (0); 1156 } 1157 if (path == NULL) 1158 return(-2); 1159 return(mkdir(path, mode)); 1160 } 1161 1162 /* 1163 * RMDIR 1164 */ 1165 int 1166 hc_rmdir(struct HostConf *hc, const char *path) 1167 { 1168 hctransaction_t trans; 1169 struct HCHead *head; 1170 1171 if (NotForRealOpt) 1172 return(0); 1173 if (hc == NULL || hc->host == NULL) 1174 return(rmdir(path)); 1175 1176 trans = hcc_start_command(hc, HC_RMDIR); 1177 hcc_leaf_string(trans, LC_PATH1, path); 1178 if ((head = hcc_finish_command(trans)) == NULL) 1179 return(-1); 1180 if (head->error) 1181 return(-1); 1182 return(0); 1183 } 1184 1185 static int 1186 rc_rmdir(hctransaction_t trans, struct HCHead *head) 1187 { 1188 struct HCLeaf *item; 1189 const char *path = NULL; 1190 1191 FOR_EACH_ITEM(item, trans, head) { 1192 if (item->leafid == LC_PATH1) 1193 path = HCC_STRING(item); 1194 } 1195 if (ReadOnlyOpt) { 1196 head->error = EACCES; 1197 return (0); 1198 } 1199 if (path == NULL) 1200 return(-2); 1201 return(rmdir(path)); 1202 } 1203 1204 /* 1205 * CHOWN 1206 * 1207 * Almost silently ignore chowns that fail if we are not root. 1208 */ 1209 int 1210 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group) 1211 { 1212 hctransaction_t trans; 1213 struct HCHead *head; 1214 int rc; 1215 1216 if (NotForRealOpt) 1217 return(0); 1218 if (!DstRootPrivs) 1219 owner = -1; 1220 1221 if (hc == NULL || hc->host == NULL) { 1222 rc = chown(path, owner, group); 1223 if (rc < 0) 1224 rc = silentwarning(&chown_warning, "file ownership may differ\n"); 1225 return(rc); 1226 } 1227 1228 trans = hcc_start_command(hc, HC_CHOWN); 1229 hcc_leaf_string(trans, LC_PATH1, path); 1230 hcc_leaf_int32(trans, LC_UID, owner); 1231 hcc_leaf_int32(trans, LC_GID, group); 1232 if ((head = hcc_finish_command(trans)) == NULL) 1233 return(-1); 1234 if (head->error) 1235 return(-1); 1236 return(0); 1237 } 1238 1239 static int 1240 rc_chown(hctransaction_t trans, struct HCHead *head) 1241 { 1242 struct HCLeaf *item; 1243 const char *path = NULL; 1244 uid_t uid = (uid_t)-1; 1245 gid_t gid = (gid_t)-1; 1246 int rc; 1247 1248 FOR_EACH_ITEM(item, trans, head) { 1249 switch(item->leafid) { 1250 case LC_PATH1: 1251 path = HCC_STRING(item); 1252 break; 1253 case LC_UID: 1254 uid = HCC_INT32(item); 1255 break; 1256 case LC_GID: 1257 gid = HCC_INT32(item); 1258 break; 1259 } 1260 } 1261 if (ReadOnlyOpt) { 1262 head->error = EACCES; 1263 return (0); 1264 } 1265 if (path == NULL) 1266 return(-2); 1267 rc = chown(path, uid, gid); 1268 if (rc < 0) 1269 rc = silentwarning(&chown_warning, "file ownership may differ\n"); 1270 return(rc); 1271 } 1272 1273 /* 1274 * LCHOWN 1275 */ 1276 int 1277 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group) 1278 { 1279 hctransaction_t trans; 1280 struct HCHead *head; 1281 int rc; 1282 1283 if (NotForRealOpt) 1284 return(0); 1285 if (!DstRootPrivs) 1286 owner = -1; 1287 1288 if (hc == NULL || hc->host == NULL) { 1289 rc = lchown(path, owner, group); 1290 if (rc < 0) 1291 rc = silentwarning(&chown_warning, "file ownership may differ\n"); 1292 return(rc); 1293 } 1294 1295 trans = hcc_start_command(hc, HC_LCHOWN); 1296 hcc_leaf_string(trans, LC_PATH1, path); 1297 hcc_leaf_int32(trans, LC_UID, owner); 1298 hcc_leaf_int32(trans, LC_GID, group); 1299 if ((head = hcc_finish_command(trans)) == NULL) 1300 return(-1); 1301 if (head->error) 1302 return(-1); 1303 return(0); 1304 } 1305 1306 static int 1307 rc_lchown(hctransaction_t trans, struct HCHead *head) 1308 { 1309 struct HCLeaf *item; 1310 const char *path = NULL; 1311 uid_t uid = (uid_t)-1; 1312 gid_t gid = (gid_t)-1; 1313 int rc; 1314 1315 FOR_EACH_ITEM(item, trans, head) { 1316 switch(item->leafid) { 1317 case LC_PATH1: 1318 path = HCC_STRING(item); 1319 break; 1320 case LC_UID: 1321 uid = HCC_INT32(item); 1322 break; 1323 case LC_GID: 1324 gid = HCC_INT32(item); 1325 break; 1326 } 1327 } 1328 if (ReadOnlyOpt) { 1329 head->error = EACCES; 1330 return (0); 1331 } 1332 if (path == NULL) 1333 return(-2); 1334 rc = lchown(path, uid, gid); 1335 if (rc < 0) 1336 rc = silentwarning(&chown_warning, "file ownership may differ\n"); 1337 return(rc); 1338 } 1339 1340 /* 1341 * CHMOD 1342 */ 1343 int 1344 hc_chmod(struct HostConf *hc, const char *path, mode_t mode) 1345 { 1346 hctransaction_t trans; 1347 struct HCHead *head; 1348 1349 if (NotForRealOpt) 1350 return(0); 1351 if (hc == NULL || hc->host == NULL) 1352 return(chmod(path, mode)); 1353 1354 trans = hcc_start_command(hc, HC_CHMOD); 1355 hcc_leaf_string(trans, LC_PATH1, path); 1356 hcc_leaf_int32(trans, LC_MODE, mode); 1357 if ((head = hcc_finish_command(trans)) == NULL) 1358 return(-1); 1359 if (head->error) 1360 return(-1); 1361 return(0); 1362 } 1363 1364 static int 1365 rc_chmod(hctransaction_t trans, struct HCHead *head) 1366 { 1367 struct HCLeaf *item; 1368 const char *path = NULL; 1369 mode_t mode = 0666; 1370 1371 FOR_EACH_ITEM(item, trans, head) { 1372 switch(item->leafid) { 1373 case LC_PATH1: 1374 path = HCC_STRING(item); 1375 break; 1376 case LC_MODE: 1377 mode = HCC_INT32(item); 1378 break; 1379 } 1380 } 1381 if (ReadOnlyOpt) { 1382 head->error = EACCES; 1383 return (0); 1384 } 1385 if (path == NULL) 1386 return(-2); 1387 return(chmod(path, mode)); 1388 } 1389 1390 /* 1391 * MKNOD 1392 */ 1393 int 1394 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev) 1395 { 1396 hctransaction_t trans; 1397 struct HCHead *head; 1398 1399 if (NotForRealOpt) 1400 return(0); 1401 if (!DstRootPrivs) { 1402 /* mknod() requires root privs, so don't bother. */ 1403 errno = EPERM; 1404 return (-1); 1405 } 1406 1407 if (hc == NULL || hc->host == NULL) 1408 return(mknod(path, mode, rdev)); 1409 1410 trans = hcc_start_command(hc, HC_MKNOD); 1411 hcc_leaf_string(trans, LC_PATH1, path); 1412 hcc_leaf_int32(trans, LC_MODE, mode); 1413 hcc_leaf_int32(trans, LC_RDEV, rdev); 1414 if ((head = hcc_finish_command(trans)) == NULL) 1415 return(-1); 1416 if (head->error) 1417 return(-1); 1418 return(0); 1419 } 1420 1421 static int 1422 rc_mknod(hctransaction_t trans, struct HCHead *head) 1423 { 1424 struct HCLeaf *item; 1425 const char *path = NULL; 1426 mode_t mode = 0666; 1427 dev_t rdev = 0; 1428 1429 FOR_EACH_ITEM(item, trans, head) { 1430 switch(item->leafid) { 1431 case LC_PATH1: 1432 path = HCC_STRING(item); 1433 break; 1434 case LC_MODE: 1435 mode = HCC_INT32(item); 1436 break; 1437 case LC_RDEV: 1438 rdev = HCC_INT32(item); 1439 break; 1440 } 1441 } 1442 if (ReadOnlyOpt) { 1443 head->error = EACCES; 1444 return (0); 1445 } 1446 if (path == NULL) 1447 return(-2); 1448 return(mknod(path, mode, rdev)); 1449 } 1450 1451 /* 1452 * LINK 1453 */ 1454 int 1455 hc_link(struct HostConf *hc, const char *name1, const char *name2) 1456 { 1457 hctransaction_t trans; 1458 struct HCHead *head; 1459 1460 if (NotForRealOpt) 1461 return(0); 1462 if (hc == NULL || hc->host == NULL) 1463 return(link(name1, name2)); 1464 1465 trans = hcc_start_command(hc, HC_LINK); 1466 hcc_leaf_string(trans, LC_PATH1, name1); 1467 hcc_leaf_string(trans, LC_PATH2, name2); 1468 if ((head = hcc_finish_command(trans)) == NULL) 1469 return(-1); 1470 if (head->error) 1471 return(-1); 1472 return(0); 1473 } 1474 1475 static int 1476 rc_link(hctransaction_t trans, struct HCHead *head) 1477 { 1478 struct HCLeaf *item; 1479 const char *name1 = NULL; 1480 const char *name2 = NULL; 1481 1482 FOR_EACH_ITEM(item, trans, head) { 1483 switch(item->leafid) { 1484 case LC_PATH1: 1485 name1 = HCC_STRING(item); 1486 break; 1487 case LC_PATH2: 1488 name2 = HCC_STRING(item); 1489 break; 1490 } 1491 } 1492 if (ReadOnlyOpt) { 1493 head->error = EACCES; 1494 return (-0); 1495 } 1496 if (name1 == NULL || name2 == NULL) 1497 return(-2); 1498 return(link(name1, name2)); 1499 } 1500 1501 #ifdef _ST_FLAGS_PRESENT_ 1502 /* 1503 * CHFLAGS 1504 */ 1505 int 1506 hc_chflags(struct HostConf *hc, const char *path, u_long flags) 1507 { 1508 hctransaction_t trans; 1509 struct HCHead *head; 1510 int rc; 1511 1512 if (NotForRealOpt) 1513 return(0); 1514 if (!DstRootPrivs) 1515 flags &= UF_SETTABLE; 1516 1517 if (hc == NULL || hc->host == NULL) { 1518 if ((rc = chflags(path, flags)) < 0) 1519 rc = silentwarning(&chflags_warning, "file flags may differ\n"); 1520 return (rc); 1521 } 1522 1523 trans = hcc_start_command(hc, HC_CHFLAGS); 1524 hcc_leaf_string(trans, LC_PATH1, path); 1525 hcc_leaf_int64(trans, LC_FILEFLAGS, flags); 1526 if ((head = hcc_finish_command(trans)) == NULL) 1527 return(-1); 1528 if (head->error) 1529 return(-1); 1530 return(0); 1531 } 1532 1533 static int 1534 rc_chflags(hctransaction_t trans, struct HCHead *head) 1535 { 1536 struct HCLeaf *item; 1537 const char *path = NULL; 1538 u_long flags = 0; 1539 int rc; 1540 1541 FOR_EACH_ITEM(item, trans, head) { 1542 switch(item->leafid) { 1543 case LC_PATH1: 1544 path = HCC_STRING(item); 1545 break; 1546 case LC_FILEFLAGS: 1547 flags = (u_long)HCC_INT64(item); 1548 break; 1549 } 1550 } 1551 if (ReadOnlyOpt) { 1552 head->error = EACCES; 1553 return (0); 1554 } 1555 if (path == NULL) 1556 return(-2); 1557 if ((rc = chflags(path, flags)) < 0) 1558 rc = silentwarning(&chflags_warning, "file flags may differ\n"); 1559 return(rc); 1560 } 1561 1562 #endif 1563 1564 /* 1565 * READLINK 1566 */ 1567 int 1568 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz) 1569 { 1570 hctransaction_t trans; 1571 struct HCHead *head; 1572 struct HCLeaf *item; 1573 int r; 1574 1575 if (hc == NULL || hc->host == NULL) 1576 return(readlink(path, buf, bufsiz)); 1577 1578 trans = hcc_start_command(hc, HC_READLINK); 1579 hcc_leaf_string(trans, LC_PATH1, path); 1580 if ((head = hcc_finish_command(trans)) == NULL) 1581 return(-1); 1582 if (head->error) 1583 return(-1); 1584 1585 r = 0; 1586 FOR_EACH_ITEM(item, trans, head) { 1587 if (item->leafid == LC_DATA) { 1588 r = item->bytes - sizeof(*item); 1589 if (r < 0) 1590 r = 0; 1591 if (r > bufsiz) 1592 r = bufsiz; 1593 bcopy(HCC_BINARYDATA(item), buf, r); 1594 } 1595 } 1596 return(r); 1597 } 1598 1599 static int 1600 rc_readlink(hctransaction_t trans, struct HCHead *head) 1601 { 1602 struct HCLeaf *item; 1603 const char *path = NULL; 1604 char buf[1024]; 1605 int r; 1606 1607 FOR_EACH_ITEM(item, trans, head) { 1608 if (item->leafid == LC_PATH1) 1609 path = HCC_STRING(item); 1610 } 1611 if (path == NULL) 1612 return(-2); 1613 r = readlink(path, buf, sizeof(buf)); 1614 if (r < 0) 1615 return(-1); 1616 hcc_leaf_data(trans, LC_DATA, buf, r); 1617 return(0); 1618 } 1619 1620 /* 1621 * UMASK 1622 */ 1623 mode_t 1624 hc_umask(struct HostConf *hc, mode_t numask) 1625 { 1626 hctransaction_t trans; 1627 struct HCHead *head; 1628 struct HCLeaf *item; 1629 1630 if (NotForRealOpt) 1631 return(umask(numask)); 1632 if (hc == NULL || hc->host == NULL) 1633 return(umask(numask)); 1634 1635 trans = hcc_start_command(hc, HC_UMASK); 1636 hcc_leaf_int32(trans, LC_MODE, numask); 1637 if ((head = hcc_finish_command(trans)) == NULL) 1638 return((mode_t)-1); 1639 if (head->error) 1640 return((mode_t)-1); 1641 1642 numask = (mode_t) ~0666U; 1643 FOR_EACH_ITEM(item, trans, head) { 1644 if (item->leafid == LC_MODE) 1645 numask = HCC_INT32(item); 1646 } 1647 return(numask); 1648 } 1649 1650 static int 1651 rc_umask(hctransaction_t trans, struct HCHead *head) 1652 { 1653 struct HCLeaf *item; 1654 mode_t numask = (mode_t) ~0666U; 1655 1656 FOR_EACH_ITEM(item, trans, head) { 1657 if (item->leafid == LC_MODE) 1658 numask = HCC_INT32(item); 1659 } 1660 numask = umask(numask); 1661 hcc_leaf_int32(trans, LC_MODE, numask); 1662 return(0); 1663 } 1664 1665 /* 1666 * SYMLINK 1667 */ 1668 int 1669 hc_symlink(struct HostConf *hc, const char *name1, const char *name2) 1670 { 1671 hctransaction_t trans; 1672 struct HCHead *head; 1673 1674 if (NotForRealOpt) 1675 return(0); 1676 if (hc == NULL || hc->host == NULL) 1677 return(symlink(name1, name2)); 1678 1679 trans = hcc_start_command(hc, HC_SYMLINK); 1680 hcc_leaf_string(trans, LC_PATH1, name1); 1681 hcc_leaf_string(trans, LC_PATH2, name2); 1682 if ((head = hcc_finish_command(trans)) == NULL) 1683 return(-1); 1684 if (head->error) 1685 return(-1); 1686 return(0); 1687 } 1688 1689 static int 1690 rc_symlink(hctransaction_t trans, struct HCHead *head) 1691 { 1692 struct HCLeaf *item; 1693 const char *name1 = NULL; 1694 const char *name2 = NULL; 1695 1696 FOR_EACH_ITEM(item, trans, head) { 1697 switch(item->leafid) { 1698 case LC_PATH1: 1699 name1 = HCC_STRING(item); 1700 break; 1701 case LC_PATH2: 1702 name2 = HCC_STRING(item); 1703 break; 1704 } 1705 } 1706 if (ReadOnlyOpt) { 1707 head->error = EACCES; 1708 return (0); 1709 } 1710 if (name1 == NULL || name2 == NULL) 1711 return(-2); 1712 return(symlink(name1, name2)); 1713 } 1714 1715 /* 1716 * RENAME 1717 */ 1718 int 1719 hc_rename(struct HostConf *hc, const char *name1, const char *name2) 1720 { 1721 hctransaction_t trans; 1722 struct HCHead *head; 1723 1724 if (NotForRealOpt) 1725 return(0); 1726 if (hc == NULL || hc->host == NULL) 1727 return(rename(name1, name2)); 1728 1729 trans = hcc_start_command(hc, HC_RENAME); 1730 hcc_leaf_string(trans, LC_PATH1, name1); 1731 hcc_leaf_string(trans, LC_PATH2, name2); 1732 if ((head = hcc_finish_command(trans)) == NULL) 1733 return(-1); 1734 if (head->error) 1735 return(-1); 1736 return(0); 1737 } 1738 1739 static int 1740 rc_rename(hctransaction_t trans, struct HCHead *head) 1741 { 1742 struct HCLeaf *item; 1743 const char *name1 = NULL; 1744 const char *name2 = NULL; 1745 1746 FOR_EACH_ITEM(item, trans, head) { 1747 switch(item->leafid) { 1748 case LC_PATH1: 1749 name1 = HCC_STRING(item); 1750 break; 1751 case LC_PATH2: 1752 name2 = HCC_STRING(item); 1753 break; 1754 } 1755 } 1756 if (ReadOnlyOpt) { 1757 head->error = EACCES; 1758 return (0); 1759 } 1760 if (name1 == NULL || name2 == NULL) 1761 return(-2); 1762 return(rename(name1, name2)); 1763 } 1764 1765 /* 1766 * UTIMES 1767 */ 1768 int 1769 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times) 1770 { 1771 hctransaction_t trans; 1772 struct HCHead *head; 1773 1774 if (NotForRealOpt) 1775 return(0); 1776 if (hc == NULL || hc->host == NULL) 1777 return(utimes(path, times)); 1778 1779 trans = hcc_start_command(hc, HC_UTIMES); 1780 hcc_leaf_string(trans, LC_PATH1, path); 1781 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec); 1782 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec); 1783 if ((head = hcc_finish_command(trans)) == NULL) 1784 return(-1); 1785 if (head->error) 1786 return(-1); 1787 return(0); 1788 } 1789 1790 static int 1791 rc_utimes(hctransaction_t trans, struct HCHead *head) 1792 { 1793 struct HCLeaf *item; 1794 struct timeval times[2]; 1795 const char *path; 1796 1797 bzero(times, sizeof(times)); 1798 path = NULL; 1799 1800 FOR_EACH_ITEM(item, trans, head) { 1801 switch(item->leafid) { 1802 case LC_PATH1: 1803 path = HCC_STRING(item); 1804 break; 1805 case LC_ATIME: 1806 times[0].tv_sec = HCC_INT64(item); 1807 break; 1808 case LC_MTIME: 1809 times[1].tv_sec = HCC_INT64(item); 1810 break; 1811 } 1812 } 1813 if (ReadOnlyOpt) { 1814 head->error = EACCES; 1815 return (0); 1816 } 1817 if (path == NULL) 1818 return(-2); 1819 return(utimes(path, times)); 1820 } 1821 1822 uid_t 1823 hc_geteuid(struct HostConf *hc) 1824 { 1825 hctransaction_t trans; 1826 struct HCHead *head; 1827 struct HCLeaf *item; 1828 1829 if (hc == NULL || hc->host == NULL) 1830 return (geteuid()); 1831 1832 if (hc->version < 3) { 1833 fprintf(stderr, "WARNING: Remote client uses old protocol version\n"); 1834 /* Return 0 on error, so the caller assumes root privileges. */ 1835 return (0); 1836 } 1837 1838 trans = hcc_start_command(hc, HC_GETEUID); 1839 if ((head = hcc_finish_command(trans)) == NULL || head->error) 1840 return(0); 1841 FOR_EACH_ITEM(item, trans, head) { 1842 if (item->leafid == LC_UID) 1843 return (HCC_INT32(item)); 1844 } 1845 return(0); /* shouldn't happen */ 1846 } 1847 1848 static int 1849 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused) 1850 { 1851 hcc_leaf_int32(trans, LC_UID, geteuid()); 1852 return (0); 1853 } 1854 1855 static int 1856 getmygroups(gid_t **gidlist) 1857 { 1858 int count; 1859 1860 if ((count = getgroups(0, *gidlist)) > 0) { 1861 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) { 1862 if ((count = getgroups(count, *gidlist)) <= 0) 1863 free(*gidlist); 1864 } 1865 else 1866 count = -1; 1867 } 1868 else 1869 *gidlist = NULL; 1870 return (count); 1871 } 1872 1873 int 1874 hc_getgroups(struct HostConf *hc, gid_t **gidlist) 1875 { 1876 int count, i; 1877 hctransaction_t trans; 1878 struct HCHead *head; 1879 struct HCLeaf *item; 1880 1881 if (hc == NULL || hc->host == NULL) 1882 return (getmygroups(gidlist)); 1883 1884 i = 0; 1885 count = 0; 1886 *gidlist = NULL; 1887 1888 if (hc->version < 3) { 1889 fprintf(stderr, "WARNING: Remote client uses old protocol version\n"); 1890 return (-1); 1891 } 1892 1893 trans = hcc_start_command(hc, HC_GETGROUPS); 1894 if ((head = hcc_finish_command(trans)) == NULL || head->error) 1895 return(-1); 1896 FOR_EACH_ITEM(item, trans, head) { 1897 switch(item->leafid) { 1898 case LC_COUNT: 1899 count = HCC_INT32(item); 1900 if (*gidlist != NULL) { /* protocol error */ 1901 free(*gidlist); 1902 *gidlist = NULL; 1903 return (-1); 1904 } 1905 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL) 1906 return (-1); 1907 break; 1908 case LC_GID: 1909 if (*gidlist == NULL || i >= count) { /* protocol error */ 1910 if (*gidlist != NULL) 1911 free(*gidlist); 1912 *gidlist = NULL; 1913 return (-1); 1914 } 1915 (*gidlist)[i++] = HCC_INT32(item); 1916 break; 1917 } 1918 } 1919 return (count); 1920 } 1921 1922 static int 1923 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused) 1924 { 1925 int count, i; 1926 gid_t *gidlist; 1927 1928 if ((count = getmygroups(&gidlist)) < 0) 1929 return (-1); 1930 hcc_leaf_int32(trans, LC_COUNT, count); 1931 for (i = 0; i < count; i++) 1932 hcc_leaf_int32(trans, LC_GID, gidlist[i]); 1933 if (gidlist != NULL) 1934 free(gidlist); 1935 return (0); 1936 } 1937