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