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