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