1 /* 2 * Copyright (C) 2005 Roy Keene 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * Author Information 19 * Roy Keene 20 * Planning Systems Inc 21 * Slidell, LA 22 * backuppcd-bugs@psislidell.com 23 */ 24 25 #include "compat.h" 26 #include "backuppcd.h" 27 #include "backuppcd-common.h" 28 #include "backuppcd-auth.h" 29 #include "net.h" 30 #include "sha1.h" 31 #include "md4.h" 32 #include "md5.h" 33 34 #define DAEMON_RET_SUCCESS 0 35 #define DAEMON_RET_FAILURE 1 36 37 #define BPC_PRIO_MIN 0 38 #define BPC_PRIO_NORM 1 39 #define BPC_PRIO_MAX 2 40 41 #define LOOP_RUN 0 42 #define LOOP_STOP 1 43 #define LOOP_DONE 2 44 45 #ifndef SKIPSTARTFILE 46 #define SKIPSTARTFILE SYSCONFDIR "/backuppcd-disable" 47 #endif 48 49 #ifndef O_BINARY 50 #define O_BINARY 0 51 #endif 52 #ifndef O_LARGEFILE 53 #define O_LARGEFILE 0 54 #endif 55 #ifndef SIGPIPE 56 #define SIGPIPE 13 57 #endif 58 59 #ifndef BPC_MAXUSERNAME_LEN 60 #define BPC_MAXUSERNAME_LEN 128 61 #endif 62 #ifndef BPC_MAXPASSWORD_LEN 63 #define BPC_MAXPASSWORD_LEN 256 64 #endif 65 #ifndef BPC_MAXPATH_LEN 66 #define BPC_MAXPATH_LEN 4096 67 #endif 68 #ifndef BPC_MAXOUTBUF_LEN 69 #define BPC_MAXOUTBUF_LEN 819200 70 #endif 71 #ifndef BPC_OUTBUF_LEN 72 #define BPC_OUTBUF_LEN 32768 73 #endif 74 #ifndef BPC_BUF_LEN 75 #define BPC_BUF_LEN 32768 76 #endif 77 #ifndef BPC_UPDATE_INTERVAL 78 #define BPC_UPDATE_INTERVAL 300 79 #endif 80 81 /* 82 * Default master password: This value will never match any SHA1 hash. 83 * 84 */ 85 #ifndef MASTER_PASSWORD 86 #define MASTER_PASSWORD "7505d64a54e061b7acd54ccd58b49dc43500b63x" 87 #endif 88 89 /* 90 * This global variable is used to coordinate the shutdown of the main work 91 * loop (backuppc_loop()). 92 */ 93 static int WorkLoopStatus = LOOP_RUN; 94 95 /* 96 * These variables are global because the configuration is done by a seperate 97 * function. 98 */ 99 static int backuppc_port = BPC_TCP_PORT; 100 static uint32_t backuppc_writeblock_size = 32000; 101 static char *backuppc_updateurl = NULL; 102 static char *backuppc_binfile = NULL; 103 104 #ifdef _USE_WIN32_ 105 /* 106 * Win32 service stuff. 107 */ 108 static SC_HANDLE manager = NULL; 109 static SC_HANDLE service = NULL; 110 static SERVICE_STATUS backuppcServiceStat; 111 static SERVICE_STATUS_HANDLE backuppcServiceStat_handle = (SERVICE_STATUS_HANDLE) NULL; 112 static char svcName[] = "BackupPC"; 113 #endif 114 115 /* 116 * These are symbolic names to use to mark when a message datum has been sent. 117 */ 118 typedef enum { 119 BPC_SM_NONE, 120 BPC_SM_HEADER, 121 BPC_SM_PKT_HEADER, 122 BPC_SM_CLEANUP, 123 BPC_SM_PATHNAME, 124 BPC_SM_DATA_CLEANUP, 125 BPC_SM_AUTHSTATUS, 126 _BPC_SM_SIZE /* Must be the last item*/ 127 } backuppc_send_mark_t; 128 129 /* 130 * These are symbolic names to use to mark when a message datum has been 131 * recieved. 132 */ 133 typedef enum { 134 BPC_RM_NONE, 135 BPC_RM_HEADER, 136 BPC_RM_PKT_HEADER, 137 BPC_RM_PATHNAME, 138 BPC_RM_AUTHDATA, 139 _BPC_RM_SIZE /* Must be the last item. */ 140 } backuppc_recv_mark_t; 141 142 /* 143 * These define the different data types that backuppc_readvalues() and 144 * backuppc_writevalues() understand. 145 */ 146 typedef enum { 147 BPC_DT_END, 148 BPC_DT_UINT8, 149 BPC_DT_UINT16, 150 BPC_DT_UINT32, 151 BPC_DT_UINT64, 152 BPC_DT_BYTEARRAY, 153 BPC_DT_BYTEARRAY_PTR, 154 BPC_DT_STRING, 155 BPC_DT_STRING_PTR, 156 } backuppc_datatypes_t; 157 158 /* 159 * Every client that connects is given a node of this type to handle its 160 * buffering. 161 * 162 * The (void *) process_handle entry is for the backuppc_process_client() 163 * call to store data in. It should be filled out by 164 * backuppc_process_client_init() and cleaned by 165 * backuppc_process_client_fini(). 166 */ 167 struct backuppc_client_info; 168 struct backuppc_client_info { 169 struct in_addr addr; 170 unsigned char *buf; 171 unsigned char *buf_s; 172 unsigned long bufsize; 173 unsigned long bufsize_s; 174 unsigned long bufused; 175 unsigned char *outbuf; 176 unsigned char *outbuf_s; 177 unsigned long outbufsize; 178 unsigned long outbufsize_s; 179 unsigned long outbufused; 180 void *process_handle; 181 int outdata_waiting; 182 int tx_error_count; 183 int rx_error_count; 184 int invalid_data; 185 int fd; 186 backuppc_privs_t privs; 187 struct backuppc_client_info *_next; 188 }; 189 190 /* 191 * backuppc_process_client()'s private data storage, maintains things like 192 * state of the current command and various other items across calls. 193 */ 194 struct backuppc_client_prochandle { 195 struct backuppc_dirent *dent; 196 backuppc_cmd_t cmd; 197 unsigned char *tmpbuf; 198 uint16_t username_len; 199 uint16_t password_len; 200 uint32_t pathname_len; 201 uint32_t excl_sect_len; 202 uint32_t incl_sect_len; 203 uint32_t block_num; 204 uint8_t options; 205 size_t tmpbufsize; 206 size_t tmpbufused; 207 size_t bytes_written; 208 size_t attrlen; 209 char *username; 210 char *password; 211 char *pathname; 212 char *data; 213 char attrdata[4096]; 214 void *dh[256]; 215 int dhidx; 216 int sent_sect[_BPC_SM_SIZE]; 217 int recv_sect[_BPC_RM_SIZE]; 218 int wv_idx; 219 int rv_idx; 220 }; 221 222 /* 223 * Structure pointed to by the backuppc_readdir() 224 * 225 * Holds information about the file, as well as a file descriptor if opened by 226 * backuppc_openfile(). 227 */ 228 struct backuppc_dirent { 229 backuppc_filetype_t type; 230 unsigned char md5[16]; 231 const char *name; 232 char fullpathname[BPC_MAXPATH_LEN]; 233 char *symlinkdest; 234 char *hrdlinkdest; 235 off_t size; 236 dev_t dev; 237 mode_t mode; 238 #ifndef _USE_WIN32_ 239 uid_t uid; 240 gid_t gid; 241 #else 242 uint32_t uid; 243 uint32_t gid; 244 #endif 245 uint64_t blocks; 246 uint32_t blksize; 247 dev_t rdev; 248 time_t mtime; 249 time_t ctime; 250 int md5_set; 251 int issparse; 252 int fd; 253 }; 254 255 struct backuppc_inode_list; 256 struct backuppc_inode_list { 257 ino_t inode_num; 258 char *fullpathname; 259 struct backuppc_inode_list *_next; 260 }; 261 262 /* 263 * Private structure handle used by backuppc_opendir() and backuppc_closedir() 264 */ 265 typedef struct backuppc_dirhandle { 266 struct backuppc_inode_list *ilist[4097]; /* This needs to be moved, otherwise hardlinks are only checked from the same dir.. XXX */ 267 struct backuppc_dirent ret; 268 char *pat_exclude[8192]; 269 char *pat_include[8192]; 270 char *pathname; 271 DIR *handle; 272 int lastdrivecheck; 273 int isfile; 274 } BPC_DIR; 275 276 277 278 static char *sha1sum(char *string) { 279 unsigned char digest[20]; 280 static char ret[(sizeof(digest) * 2) + 1] = {0}; 281 static char hexabet[] = "0123456789abcdef"; 282 SHA1_CTX ctx; 283 int retcnt = 0, i; 284 285 SHA1Init(&ctx); 286 287 SHA1Update(&ctx, string, strlen(string)); 288 289 SHA1Final(digest, &ctx); 290 291 for (i = 0; i < sizeof(digest); i++) { 292 ret[retcnt++] = hexabet[(digest[i] & 0xf0) >> 4]; 293 ret[retcnt++] = hexabet[digest[i] & 0xf]; 294 } 295 296 ret[retcnt] = '\0'; 297 298 return(ret); 299 } 300 301 static void backuppc_setpriority(int prio) { 302 #ifdef _USE_WIN32_ 303 DWORD prio_class; 304 305 switch (prio) { 306 case BPC_PRIO_MAX: 307 prio_class = HIGH_PRIORITY_CLASS; 308 break; 309 case BPC_PRIO_NORM: 310 prio_class = NORMAL_PRIORITY_CLASS; 311 break; 312 case BPC_PRIO_MIN: 313 default: 314 prio_class = BELOW_NORMAL_PRIORITY_CLASS; 315 break; 316 } 317 318 SetPriorityClass(GetCurrentProcess(), prio_class); 319 #else 320 int prio_val; 321 322 switch (prio) { 323 case BPC_PRIO_MAX: 324 prio_val = -15; 325 break; 326 case BPC_PRIO_NORM: 327 prio_val = 0; 328 break; 329 case BPC_PRIO_MIN: 330 default: 331 prio_val = 10; 332 break; 333 } 334 335 #ifdef HAVE_SETPRIORITY 336 setpriority(PRIO_PROCESS, 0, prio_val); 337 #else 338 #warning NO WAY TO HANDLE PRIORITY 339 #endif 340 #endif 341 return; 342 } 343 344 345 /* 346 * SYNOPSIS: 347 * static void backuppc_pathmangle( 348 * char *pathname 349 * ); 350 * 351 * ARGUMENTS: 352 * char *pathname Pathname to mangle. 353 * 354 * RETURN VALUE: 355 * (none) 356 * 357 * NOTES: 358 * This function compiles to a no-op on platforms that already have a single 359 * unified namespace. 360 * 361 * On Win32 this function changes pathnames containing a drive letter style 362 * pathname to a more sane name including the leading slash. 363 * 364 */ 365 static void backuppc_pathmangle(char *pathname) { 366 #ifdef _USE_WIN32_ 367 char drive_letter; 368 369 if (strlen(pathname) < 2) { 370 return; 371 } 372 373 if (pathname[0] == '/' && isalpha(pathname[1])) { 374 return; 375 } 376 377 if (pathname[1] != ':' || !isalpha(pathname[0])) { 378 return; 379 } 380 381 drive_letter = pathname[0]; 382 pathname[0] = '/'; 383 pathname[1] = drive_letter; 384 385 #endif 386 return; 387 } 388 389 /* 390 * SYNOPSIS: 391 * static void backuppc_pathunmangle( 392 * char *pathname 393 * ); 394 * 395 * ARGUMENTS: 396 * char *pathname Pathname to unmangle. 397 * 398 * RETURN VALUE: 399 * (none) 400 * 401 * NOTES: 402 * This function compiles to a no-op on platforms that already have a single 403 * unified namespace. 404 * 405 * On Win32 this function changes pathnames containing a sane pathname to 406 * a pathname that contains a drive letter and can be used to open or 407 * otherwise access the file. 408 * 409 */ 410 static void backuppc_pathunmangle(char *pathname) { 411 #ifdef _USE_WIN32_ 412 char drive_letter; 413 414 if (strlen(pathname) < 2) { 415 return; 416 } 417 418 if (pathname[1] == ':' && isalpha(pathname[0])) { 419 return; 420 } 421 422 if (pathname[0] != '/' || !isalpha(pathname[1])) { 423 return; 424 } 425 426 drive_letter = pathname[1]; 427 pathname[0] = drive_letter; 428 pathname[1] = ':'; 429 430 #endif 431 return; 432 } 433 434 /* 435 * SYNOPSIS: 436 * static BPC_DIR *backuppc_opendir( 437 * char *pathname 438 * ); 439 * 440 * ARGUMENTS: 441 * char *pathname Pathname to the directory to open 442 * 443 * RETURN VALUE: 444 * This function returns a pointer to a handle that can be used with 445 * backuppc_readdir() and backuppc_closedir(). It returns NULL on 446 * error. 447 * 448 * NOTES: 449 * If you backuppc_opendir() a file, you get a handle that when you call 450 * backuppc_readdir() gives you exactly one entry, the pathname specified. 451 * Thus you should not assume that the result of backuppc_readdir() gives 452 * a child-node in the directory heirarchy of the pathname specified when 453 * this function is called. the (struct backuppc_dirent).fullpathname 454 * value should be used instead to get the full path to the relevant node. 455 * 456 */ 457 static BPC_DIR *backuppc_opendir(char *pathname) { 458 BPC_DIR *dh; 459 struct stat stbuf; 460 FILE *directive_fp; 461 char dir_directive_file[BPC_MAXPATH_LEN]; 462 char buf[1024]; 463 int excnt = 0, incnt = 0; 464 int stat_ret; 465 int i; 466 467 if (pathname[0] != '/') { 468 return(NULL); 469 } 470 471 dh = malloc(sizeof(*dh)); 472 473 if (!dh) { 474 return(NULL); 475 } 476 477 dh->pat_exclude[0] = NULL; 478 dh->pat_include[0] = NULL; 479 dh->isfile = 0; 480 481 for (i = 0; i < (sizeof(dh->ilist) / sizeof(dh->ilist[0])); i++) { 482 dh->ilist[i] = NULL; 483 } 484 485 #ifdef _USE_WIN32_ 486 if (strlen(pathname) < 2) { 487 dh->pathname = strdup("/"); 488 dh->handle = NULL; 489 dh->lastdrivecheck = 0; 490 return(dh); 491 } 492 #endif 493 494 backuppc_pathunmangle(pathname); 495 496 dh->handle = opendir(pathname); 497 498 snprintf(dir_directive_file, sizeof(dir_directive_file), "%s/%s", pathname, ".bpc"); 499 500 backuppc_pathmangle(pathname); 501 502 if (!dh->handle) { 503 backuppc_pathunmangle(pathname); 504 #ifdef HAVE_LSTAT 505 stat_ret = lstat(pathname, &stbuf); 506 #else 507 stat_ret = stat(pathname, &stbuf); 508 #endif 509 backuppc_pathmangle(pathname); 510 511 if (stat_ret < 0) { 512 free(dh); 513 dh = NULL; 514 return(dh); 515 } 516 517 if (S_ISDIR(stbuf.st_mode)) { 518 free(dh); 519 dh = NULL; 520 return(dh); 521 } 522 523 dh->isfile = 1; 524 } 525 526 dh->lastdrivecheck = 0; 527 dh->pathname = strdup(pathname); 528 529 dh->ret.symlinkdest = NULL; 530 dh->ret.hrdlinkdest = NULL; 531 532 directive_fp = fopen(dir_directive_file, "r"); 533 if (directive_fp) { 534 while (1) { 535 fgets(buf, sizeof(buf), directive_fp); 536 537 if (feof(directive_fp)) { 538 break; 539 } 540 541 if (strlen(buf) < 2) { 542 continue; 543 } 544 545 if (buf[strlen(buf) - 1] < ' ') { 546 buf[strlen(buf) - 1] = '\0'; 547 } 548 549 switch (buf[0]) { 550 case '+': 551 dh->pat_include[incnt] = strdup(buf + 1); 552 incnt++; 553 case '-': 554 dh->pat_exclude[excnt] = strdup(buf + 1); 555 excnt++; 556 default: 557 break; 558 } 559 } 560 } 561 562 return(dh); 563 } 564 565 /* 566 * SYNOPSIS: 567 * static struct backuppc_dirent *backuppc_readdir( 568 * BPC_DIR *dh 569 * ); 570 * 571 * ARGUMENTS: 572 * BPC_DIR *dh Directory stream handle, from backuppc_opendir() 573 * 574 * RETURN VALUE: 575 * This function returns a pointer to a (struct backuppc_dirent). Every 576 * call will return the same pointer for the specified directory handle. 577 * This function returns NULL when there are no more nodes that can be 578 * processed available in the stream or an error occurs. 579 * 580 * NOTES: 581 * Under Win32, this function presents the children of "/" as the letters 582 * of all drives that are not "removable", "remote", or "cdrom". 583 * 584 * The size for non-regular file nodes will always be zero, regardless of 585 * how many blocks they actually take up on the disk. 586 * 587 */ 588 static struct backuppc_dirent *backuppc_readdir(BPC_DIR *dh) { 589 struct backuppc_inode_list *cur_inode; 590 struct dirent *dent; 591 struct stat stbuf; 592 size_t pathnamelen; 593 #ifdef _USE_WIN32_ 594 DWORD drives; 595 UINT drive_type; 596 char drive_letter; 597 char drive_letter_str[32]; 598 int i, drive_exists; 599 #endif 600 int stat_ret, readlink_ret; 601 int pat_incidx, pat_exlidx; 602 int hash_idx; 603 int exclude_file; 604 605 if (!dh) { 606 return(NULL); 607 } 608 609 if (!dh->handle && !dh->isfile) { 610 #ifdef _USE_WIN32_ 611 /* On Win32, dh->handle being NULL indicates the fake root 612 directory we are to construct. */ 613 drives = GetLogicalDrives(); 614 615 for (i = dh->lastdrivecheck; i < (sizeof(drives) * 8); i++) { 616 drive_exists = drives & (1 << i); 617 618 if (drive_exists) { 619 drive_letter = 'A' + i; 620 621 /* The trailing slashes are required here, 622 otherwise Windows thinks we mean the 623 current directory on that drive instead 624 of the root directory. */ 625 sprintf(drive_letter_str, "%c:\\", drive_letter); 626 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "/%c/", drive_letter); 627 628 drive_type = GetDriveType(drive_letter_str); 629 630 if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_REMOTE || drive_type == DRIVE_CDROM) { 631 continue; 632 } 633 634 dh->lastdrivecheck = i + 1; 635 drive_letter_str[1] = '\0'; 636 dh->ret.name = strdup(drive_letter_str); 637 dh->ret.type = BPC_FILE_DIR; 638 dh->ret.size = 0; 639 // dh->ret.inode = ((0xf << ((sizeof(dh->ret.inode) * 8) - 4)) | ((1 << ((sizeof(dh->ret.inode) * 8) - 1)) - 1)) - i; 640 dh->ret.md5_set = 0; 641 dh->ret.fd = -1; 642 dh->ret.dev = 0; 643 dh->ret.rdev = 0; 644 dh->ret.mode = 0; 645 dh->ret.uid = 0; 646 dh->ret.gid = 0; 647 dh->ret.blocks = 0; 648 dh->ret.mtime = 0; 649 dh->ret.ctime = 0; 650 return(&dh->ret); 651 } 652 } 653 #endif 654 return(NULL); 655 } 656 657 pathnamelen = strlen(dh->pathname); 658 659 /* 660 * A zero-length pathname never makes sense, and it will break some 661 * calculations below. 662 */ 663 if (pathnamelen < 1) { 664 return(NULL); 665 } 666 667 while (1) { 668 if (!dh->isfile) { 669 dent = readdir(dh->handle); 670 671 if (!dent) { 672 break; 673 } 674 675 if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { 676 continue; 677 } 678 679 if (dh->pathname[pathnamelen - 1] == '/') { 680 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s%s", dh->pathname, dent->d_name); 681 } else { 682 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s/%s", dh->pathname, dent->d_name); 683 } 684 } else { 685 if (dh->isfile == 2) { 686 break; 687 } 688 689 snprintf(dh->ret.fullpathname, sizeof(dh->ret.fullpathname), "%s", dh->pathname); 690 691 dh->isfile = 2; 692 } 693 694 backuppc_pathunmangle(dh->ret.fullpathname); 695 696 #ifdef HAVE_LSTAT 697 stat_ret = lstat(dh->ret.fullpathname, &stbuf); 698 #else 699 stat_ret = stat(dh->ret.fullpathname, &stbuf); 700 #endif 701 702 backuppc_pathmangle(dh->ret.fullpathname); 703 704 if (stat_ret < 0) { 705 continue; 706 } 707 708 dh->ret.name = strrchr(dh->ret.fullpathname, '/'); 709 if (!dh->ret.name) { 710 continue; 711 } 712 dh->ret.name++; 713 714 dh->ret.dev = stbuf.st_dev; 715 dh->ret.rdev = stbuf.st_rdev; 716 dh->ret.mode = stbuf.st_mode; 717 dh->ret.uid = stbuf.st_uid; 718 dh->ret.gid = stbuf.st_gid; 719 #ifdef _USE_WIN32_ 720 dh->ret.blksize = 1024; 721 dh->ret.blocks = (stbuf.st_size + dh->ret.blksize - 1) / dh->ret.blksize; 722 #else 723 dh->ret.blksize = stbuf.st_blksize; 724 dh->ret.blocks = stbuf.st_blocks; 725 #endif 726 dh->ret.mtime = stbuf.st_mtime; 727 dh->ret.ctime = stbuf.st_ctime; 728 dh->ret.md5_set = 0; 729 dh->ret.fd = -1; 730 731 /* 732 * Process exclusions stored in the BPC_DIR structure. We 733 * exclude anything matching a "pat_exclude" rule, unless it 734 * also matches a "pat_include" rule. 735 */ 736 exclude_file = 0; 737 for (pat_exlidx = 0; pat_exlidx < (sizeof(dh->pat_exclude) / sizeof(dh->pat_exclude[0])); pat_exlidx++) { 738 if (!dh->pat_exclude[pat_exlidx]) { 739 break; 740 } 741 742 if (fnmatch(dh->pat_exclude[pat_exlidx], dh->ret.name, FNM_PERIOD) == 0) { 743 exclude_file = 1; 744 745 for (pat_incidx = 0; pat_incidx < (sizeof(dh->pat_include) / sizeof(dh->pat_include[0])); pat_incidx++) { 746 if (!dh->pat_include[pat_incidx]) { 747 break; 748 } 749 if (fnmatch(dh->pat_include[pat_incidx], dh->ret.name, FNM_PERIOD) == 0) { 750 exclude_file = 0; 751 } 752 } 753 } 754 } 755 756 /* 757 * Skip excluded files 758 */ 759 if (exclude_file) { 760 continue; 761 } 762 763 switch (stbuf.st_mode & S_IFMT) { 764 case S_IFREG: 765 dh->ret.type = BPC_FILE_REG; 766 break; 767 #ifdef S_IFLNK 768 case S_IFLNK: 769 dh->ret.type = BPC_FILE_SYMLINK; 770 #ifdef HAVE_READLINK 771 if (!dh->ret.symlinkdest) { 772 dh->ret.symlinkdest = malloc(BPC_MAXPATH_LEN); 773 } 774 readlink_ret = readlink(dh->ret.fullpathname, dh->ret.symlinkdest, BPC_MAXPATH_LEN); 775 if (readlink_ret > 0 && readlink_ret < BPC_MAXPATH_LEN) { 776 dh->ret.symlinkdest[readlink_ret] = '\0'; 777 } else { 778 dh->ret.symlinkdest[0] = '\0'; 779 } 780 #endif 781 break; 782 #endif 783 case S_IFCHR: 784 dh->ret.type = BPC_FILE_CDEV; 785 break; 786 case S_IFBLK: 787 dh->ret.type = BPC_FILE_BDEV; 788 break; 789 case S_IFDIR: 790 dh->ret.type = BPC_FILE_DIR; 791 break; 792 case S_IFIFO: 793 dh->ret.type = BPC_FILE_FIFO; 794 break; 795 #ifdef S_IFSOCK 796 case S_IFSOCK: 797 dh->ret.type = BPC_FILE_SOCKET; 798 break; 799 #endif 800 default: 801 dh->ret.type = BPC_FILE_UNKNOWN; 802 break; 803 } 804 805 /* 806 * If a file has a link count greater than one, determine if 807 * we have seen it before, if not note that we've seen it now 808 * so we can look for it later. 809 */ 810 if (stbuf.st_nlink > 1 && dh->ret.type != BPC_FILE_DIR && dh->ret.type != BPC_FILE_UNKNOWN) { 811 hash_idx = stbuf.st_ino % (sizeof(dh->ilist) / sizeof(dh->ilist[0])); 812 for (cur_inode = dh->ilist[hash_idx]; cur_inode; cur_inode = cur_inode->_next) { 813 if (cur_inode->inode_num == stbuf.st_ino) { 814 dh->ret.type = BPC_FILE_HRDLINK; 815 dh->ret.hrdlinkdest = cur_inode->fullpathname; 816 break; 817 } 818 } 819 820 if (dh->ret.type != BPC_FILE_HRDLINK) { 821 cur_inode = malloc(sizeof(*cur_inode)); 822 cur_inode->inode_num = stbuf.st_ino; 823 cur_inode->fullpathname = strdup(dh->ret.fullpathname); 824 cur_inode->_next = dh->ilist[hash_idx]; 825 dh->ilist[hash_idx] = cur_inode; 826 } 827 } 828 829 830 if (dh->ret.type == BPC_FILE_REG) { 831 dh->ret.size = stbuf.st_size; 832 } else { 833 dh->ret.size = 0; 834 } 835 836 dh->ret.issparse = 0; 837 838 return(&dh->ret); 839 } 840 841 return(NULL); 842 } 843 844 /* 845 * SYNOPSIS: 846 * static void backuppc_closedir( 847 * BPC_DIR *dh); 848 * ); 849 * 850 * ARGUMENTS: 851 * BPC_DIR *dh Directory stream handle, from backuppc_opendir() 852 * 853 * RETURN VALUE: 854 * (none) 855 * 856 * NOTES: 857 * This function closes an opened directory stream. It cleans up any 858 * resources related to that stream. The handle specified should not be 859 * used once this function has been called. 860 * 861 */ 862 static void backuppc_closedir(BPC_DIR *dh) { 863 struct backuppc_inode_list *cur_inode, *next_inode; 864 int hash_idx; 865 int pat_idx; 866 867 if (!dh) { 868 return; 869 } 870 871 if (dh->pathname) { 872 free(dh->pathname); 873 } 874 875 if (dh->handle) { 876 closedir(dh->handle); 877 } 878 879 if (dh->ret.symlinkdest) { 880 free(dh->ret.symlinkdest); 881 } 882 883 for (pat_idx = 0; pat_idx < (sizeof(dh->pat_exclude) / sizeof(dh->pat_exclude[0])); pat_idx++) { 884 if (!dh->pat_exclude[pat_idx]) { 885 break; 886 } 887 888 free(dh->pat_exclude[pat_idx]); 889 } 890 891 for (pat_idx = 0; pat_idx < (sizeof(dh->pat_include) / sizeof(dh->pat_include[0])); pat_idx++) { 892 if (!dh->pat_include[pat_idx]) { 893 break; 894 } 895 896 free(dh->pat_include[pat_idx]); 897 } 898 899 for (hash_idx = 0; hash_idx < (sizeof(dh->ilist) / sizeof(dh->ilist[0])); hash_idx++) { 900 cur_inode = dh->ilist[hash_idx]; 901 while (cur_inode) { 902 if (cur_inode->fullpathname) { 903 free(cur_inode->fullpathname); 904 } 905 906 next_inode = cur_inode->_next; 907 908 free(cur_inode); 909 910 cur_inode = next_inode; 911 } 912 } 913 914 free(dh); 915 916 return; 917 } 918 919 /* 920 * SYNOPSIS: 921 * static int backuppc_openfile( 922 * struct backuppc_dirent *dent, 923 * int flags, 924 * mode_t mode 925 * ); 926 * 927 * ARGUMENTS: 928 * struct backuppc_dirent *dent Pointer to structure containing information 929 * about file to open. 930 * int flags Flags to open file with, should include one 931 * of O_RDONLY, O_RDWR, or O_WRONLY. 932 * mode_t mode Permissions to set on file if it is to be 933 * created. 934 * 935 * RETURN VALUE: 936 * This function returns the file descriptor associated with the open file 937 * on success, or -1 on failure. 938 * 939 * NOTES: 940 * This function sets the "fd" member of the structure pointed to by the 941 * "dent" parameter to the file descriptor. 942 * 943 * If the file "fd" member is already set to a positive value, that value 944 * is returned and the file is not opened nor is its state changed. 945 * 946 */ 947 static int backuppc_openfile(struct backuppc_dirent *dent, int flags, mode_t mode) { 948 char *pathname; 949 int fd; 950 951 if (dent->type != BPC_FILE_REG) { 952 CHECKPOINT; 953 return(-1); 954 } 955 956 if (dent->fd >= 0) { 957 CHECKPOINT; 958 return(dent->fd); 959 } 960 961 pathname = dent->fullpathname; 962 963 backuppc_pathunmangle(pathname); 964 965 fd = open(pathname, flags | O_LARGEFILE | O_BINARY, mode); 966 967 backuppc_pathmangle(pathname); 968 969 if (fd < 0) { 970 CHECKPOINT; 971 return(-1); 972 } 973 974 dent->fd = fd; 975 976 return(fd); 977 } 978 979 /* 980 * SYNOPSIS: 981 * static int backuppc_closefile( 982 * struct backuppc_dirent *dent 983 * ); 984 * 985 * ARGUMENTS: 986 * struct backuppc_dirent *dent Pointer to structure containing information 987 * about file to close. 988 * 989 * RETURN VALUE: 990 * Zero is returned on success, or -1 if an error occurs. It is not 991 * considered an error to close an already closed file. 992 * 993 * NOTES: 994 * 995 */ 996 static int backuppc_closefile(struct backuppc_dirent *dent) { 997 int fd; 998 999 if (dent->fd < 0) { 1000 return(0); 1001 } 1002 1003 fd = dent->fd; 1004 dent->fd = -1; 1005 1006 return(close(fd)); 1007 } 1008 1009 /* 1010 * SYNOPSIS: 1011 * static void backuppc_get_attr(void); 1012 * 1013 * ARGUMENTS: 1014 * (none) 1015 * 1016 * RETURN VALUE: 1017 * (none) 1018 * 1019 * NOTES: 1020 * This function needs to be written 1021 * 1022 */ 1023 static ssize_t backuppc_get_attr(struct backuppc_dirent *dent, char *outbuf, size_t outbuflen, uint8_t options) { 1024 rsaref_MD4_CTX md4_ctx; 1025 ld_MD5_CTX bpchash_ctx; 1026 ld_MD5_CTX md5_ctx; 1027 SHA1_CTX sha1_ctx; 1028 uint64_t filepos = 0, preread_filepos; 1029 uint32_t len, timeval, idval; 1030 uint16_t modeval; 1031 uint16_t id; 1032 ssize_t read_ret; 1033 char *buf = outbuf; 1034 char filebuf[16384]; 1035 unsigned char digest[20]; 1036 char filesizestrbuf[21]; 1037 uint32_t bpc_hashstop = 0; 1038 int fd; 1039 1040 if (dent->mtime > 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(timeval))) { 1041 id = htons(BPC_ATTRID_MTIME); 1042 len = htonl(sizeof(timeval)); 1043 timeval = htonl(dent->mtime); 1044 1045 memcpy(buf, &id, sizeof(id)); 1046 buf += sizeof(id); 1047 1048 memcpy(buf, &len, sizeof(len)); 1049 buf += sizeof(len); 1050 1051 memcpy(buf, &timeval, sizeof(timeval)); 1052 buf += sizeof(timeval); 1053 } 1054 1055 if (dent->ctime > 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(timeval))) { 1056 id = htons(BPC_ATTRID_CTIME); 1057 len = htonl(sizeof(timeval)); 1058 timeval = htonl(dent->ctime); 1059 1060 memcpy(buf, &id, sizeof(id)); 1061 buf += sizeof(id); 1062 1063 memcpy(buf, &len, sizeof(len)); 1064 buf += sizeof(len); 1065 1066 memcpy(buf, &timeval, sizeof(timeval)); 1067 buf += sizeof(timeval); 1068 } 1069 1070 /* BPC_ATTRID_USER */ 1071 /* BPC_ATTRID_GROUP */ 1072 1073 if (dent->uid >= 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(idval))) { 1074 id = htons(BPC_ATTRID_UID); 1075 len = htonl(sizeof(idval)); 1076 idval = htonl(dent->uid); 1077 1078 memcpy(buf, &id, sizeof(id)); 1079 buf += sizeof(id); 1080 1081 memcpy(buf, &len, sizeof(len)); 1082 buf += sizeof(len); 1083 1084 memcpy(buf, &idval, sizeof(idval)); 1085 buf += sizeof(idval); 1086 } 1087 1088 if (dent->gid >= 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(idval))) { 1089 id = htons(BPC_ATTRID_GID); 1090 len = htonl(sizeof(idval)); 1091 idval = htonl(dent->gid); 1092 1093 memcpy(buf, &id, sizeof(id)); 1094 buf += sizeof(id); 1095 1096 memcpy(buf, &len, sizeof(len)); 1097 buf += sizeof(len); 1098 1099 memcpy(buf, &idval, sizeof(idval)); 1100 buf += sizeof(idval); 1101 } 1102 1103 if (dent->mode != 0 && (outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + sizeof(modeval))) { 1104 id = htons(BPC_ATTRID_ACL); 1105 len = htonl(sizeof(modeval)); 1106 1107 modeval = 0; 1108 1109 if ((dent->mode & S_IRUSR) == S_IRUSR) { 1110 modeval |= BPC_ACL_RUSR; 1111 } 1112 if ((dent->mode & S_IWUSR) == S_IWUSR) { 1113 modeval |= BPC_ACL_WUSR; 1114 } 1115 if ((dent->mode & S_IXUSR) == S_IXUSR) { 1116 modeval |= BPC_ACL_XUSR; 1117 } 1118 #ifndef _USE_WIN32_ 1119 if ((dent->mode & S_IRGRP) == S_IRGRP) { 1120 modeval |= BPC_ACL_RGRP; 1121 } 1122 if ((dent->mode & S_IWGRP) == S_IWGRP) { 1123 modeval |= BPC_ACL_WGRP; 1124 } 1125 if ((dent->mode & S_IXGRP) == S_IXGRP) { 1126 modeval |= BPC_ACL_XGRP; 1127 } 1128 if ((dent->mode & S_IROTH) == S_IROTH) { 1129 modeval |= BPC_ACL_ROTH; 1130 } 1131 if ((dent->mode & S_IWOTH) == S_IWOTH) { 1132 modeval |= BPC_ACL_WOTH; 1133 } 1134 if ((dent->mode & S_IXOTH) == S_IXOTH) { 1135 modeval |= BPC_ACL_XOTH; 1136 } 1137 if ((dent->mode & S_ISVTX) == S_ISVTX) { 1138 modeval |= BPC_ACL_STCK; 1139 } 1140 if ((dent->mode & S_ISGID) == S_ISGID) { 1141 modeval |= BPC_ACL_SGID; 1142 } 1143 if ((dent->mode & S_ISUID) == S_ISUID) { 1144 modeval |= BPC_ACL_SUID; 1145 } 1146 #endif 1147 1148 modeval = htons(modeval); 1149 1150 memcpy(buf, &id, sizeof(id)); 1151 buf += sizeof(id); 1152 1153 memcpy(buf, &len, sizeof(len)); 1154 buf += sizeof(len); 1155 1156 memcpy(buf, &modeval, sizeof(modeval)); 1157 buf += sizeof(modeval); 1158 } 1159 1160 if (dent->type == BPC_FILE_SYMLINK && dent->symlinkdest) { 1161 if ((outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + strlen(dent->symlinkdest))) { 1162 id = htons(BPC_ATTRID_SYMLINKDEST); 1163 memcpy(buf, &id, sizeof(id)); 1164 buf += sizeof(id); 1165 1166 len = htonl(strlen(dent->symlinkdest)); 1167 memcpy(buf, &len, sizeof(len)); 1168 buf += sizeof(len); 1169 1170 memcpy(buf, dent->symlinkdest, strlen(dent->symlinkdest)); 1171 buf += strlen(dent->symlinkdest); 1172 } 1173 } 1174 1175 if (dent->type == BPC_FILE_HRDLINK && dent->hrdlinkdest) { 1176 if ((outbuflen - (buf - outbuf)) >= (sizeof(id) + sizeof(len) + strlen(dent->hrdlinkdest))) { 1177 id = htons(BPC_ATTRID_HRDLINKDEST); 1178 memcpy(buf, &id, sizeof(id)); 1179 buf += sizeof(id); 1180 1181 len = htonl(strlen(dent->hrdlinkdest)); 1182 memcpy(buf, &len, sizeof(len)); 1183 buf += sizeof(len); 1184 1185 memcpy(buf, dent->hrdlinkdest, strlen(dent->hrdlinkdest)); 1186 buf += strlen(dent->hrdlinkdest); 1187 } 1188 } 1189 1190 if (dent->type == BPC_FILE_REG && \ 1191 ((options & BPC_OPT_MD4) == BPC_OPT_MD4 || \ 1192 (options & BPC_OPT_MD5) == BPC_OPT_MD5 || \ 1193 (options & BPC_OPT_SHA1) == BPC_OPT_SHA1 || \ 1194 (options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH)) { 1195 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) { 1196 rsaref_MD4Init(&md4_ctx); 1197 } 1198 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) { 1199 ld_MD5Init(&md5_ctx); 1200 } 1201 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) { 1202 SHA1Init(&sha1_ctx); 1203 } 1204 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) { 1205 /* 1206 * The BPC hash is weird. It's a hash of the 1207 * following: 1208 * FILESIZE % (2^32 -1) (string) 1209 * First 128KB of data 1210 * Data between 1024KB - 128KB and 1024KB 1211 * (less if required to prevent overlapping 1212 * windows, last 128KB section moves 1213 * backwards if file is short.) 1214 */ 1215 ld_MD5Init(&bpchash_ctx); 1216 1217 snprintf(filesizestrbuf, sizeof(filesizestrbuf), "%llu", (long long unsigned) (dent->size % 0xffffffff)); 1218 ld_MD5Update(&bpchash_ctx, filesizestrbuf, strlen(filesizestrbuf)); 1219 1220 if (dent->size > 1048576) { 1221 bpc_hashstop = 1048576; 1222 } else { 1223 bpc_hashstop = dent->size; 1224 } 1225 } 1226 1227 fd = backuppc_openfile(dent, O_RDONLY, 0600); 1228 1229 if (fd >= 0) { 1230 while (1) { 1231 read_ret = read(fd, filebuf, sizeof(filebuf)); 1232 1233 if (read_ret <= 0) { 1234 break; 1235 } 1236 1237 filepos += read_ret; 1238 1239 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) { 1240 rsaref_MD4Update(&md4_ctx, filebuf, read_ret); 1241 } 1242 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) { 1243 ld_MD5Update(&md5_ctx, filebuf, read_ret); 1244 } 1245 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) { 1246 SHA1Update(&sha1_ctx, filebuf, read_ret); 1247 } 1248 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) { 1249 if (dent->size > 262144) { 1250 1251 preread_filepos = filepos - read_ret; 1252 1253 if (preread_filepos > 1048576) { 1254 /* 1255 * If we're only using the BPC hash, then we 1256 * don't need to continue reading. 1257 */ 1258 if ((options & (BPC_OPT_MD4 | \ 1259 BPC_OPT_MD5 | \ 1260 BPC_OPT_SHA1 | \ 1261 BPC_OPT_BPCHASH)) == BPC_OPT_BPCHASH) { 1262 break; 1263 } 1264 } 1265 1266 if (preread_filepos < 131072 || 1267 (preread_filepos < bpc_hashstop && filepos > (bpc_hashstop - 131072))) { 1268 if (filepos >= 131072 && preread_filepos < 131072) { 1269 read_ret = read_ret - (filepos - 131072); 1270 ld_MD5Update(&bpchash_ctx, filebuf, read_ret); 1271 } else if (filepos >= bpc_hashstop && preread_filepos < bpc_hashstop) { 1272 read_ret = read_ret - (filepos - bpc_hashstop); 1273 ld_MD5Update(&bpchash_ctx, filebuf, read_ret); 1274 } else if (filepos >= (bpc_hashstop - 131072) && preread_filepos < (bpc_hashstop - 131072)) { 1275 read_ret = filepos - (bpc_hashstop - 131072); 1276 ld_MD5Update(&bpchash_ctx, filebuf + (bpc_hashstop - 131072) - preread_filepos, read_ret); 1277 } else { 1278 ld_MD5Update(&bpchash_ctx, filebuf, read_ret); 1279 } 1280 } 1281 } else { 1282 ld_MD5Update(&bpchash_ctx, filebuf, read_ret); 1283 } 1284 } 1285 } 1286 1287 /* 1288 * If no errors occured, the EOF bit will have been 1289 * set and we can trust the hashes well enough to 1290 * commit them to the stream. 1291 */ 1292 if (read_ret >= 0) { 1293 if ((options & BPC_OPT_MD4) == BPC_OPT_MD4) { 1294 rsaref_MD4Final(digest, &md4_ctx); 1295 1296 id = htons(BPC_ATTRID_MD4); 1297 len = htonl(16); 1298 1299 memcpy(buf, &id, sizeof(id)); 1300 buf += sizeof(id); 1301 1302 memcpy(buf, &len, sizeof(len)); 1303 buf += sizeof(len); 1304 1305 memcpy(buf, digest, 16); 1306 buf += 16; 1307 } 1308 if ((options & BPC_OPT_MD5) == BPC_OPT_MD5) { 1309 ld_MD5Final(digest, &md5_ctx); 1310 1311 id = htons(BPC_ATTRID_MD5); 1312 len = htonl(16); 1313 1314 memcpy(buf, &id, sizeof(id)); 1315 buf += sizeof(id); 1316 1317 memcpy(buf, &len, sizeof(len)); 1318 buf += sizeof(len); 1319 1320 memcpy(buf, digest, 16); 1321 buf += 16; 1322 } 1323 if ((options & BPC_OPT_SHA1) == BPC_OPT_SHA1) { 1324 SHA1Final(digest, &sha1_ctx); 1325 1326 id = htons(BPC_ATTRID_SHA1); 1327 len = htonl(20); 1328 1329 memcpy(buf, &id, sizeof(id)); 1330 buf += sizeof(id); 1331 1332 memcpy(buf, &len, sizeof(len)); 1333 buf += sizeof(len); 1334 1335 memcpy(buf, digest, 20); 1336 buf += 20; 1337 } 1338 if ((options & BPC_OPT_BPCHASH) == BPC_OPT_BPCHASH) { 1339 ld_MD5Final(digest, &bpchash_ctx); 1340 1341 id = htons(BPC_ATTRID_BPCHASH); 1342 len = htonl(16); 1343 1344 memcpy(buf, &id, sizeof(id)); 1345 buf += sizeof(id); 1346 1347 memcpy(buf, &len, sizeof(len)); 1348 buf += sizeof(len); 1349 1350 memcpy(buf, digest, 16); 1351 buf += 16; 1352 } 1353 } 1354 1355 backuppc_closefile(dent); 1356 } 1357 } 1358 1359 /* If we can't fit the termination marker in, scrap the entire buffer. */ 1360 if ((outbuflen - (buf - outbuf)) >= sizeof(id)) { 1361 id = htons(0xffff); 1362 memcpy(buf, &id, sizeof(id)); 1363 buf += sizeof(id); 1364 } else { 1365 buf = outbuf; 1366 } 1367 1368 return(buf - outbuf); 1369 } 1370 1371 /* 1372 * SYNOPSIS: 1373 * static void backuppc_bufuse( 1374 * struct backuppc_client_info *node, 1375 * const size_t amount 1376 * ); 1377 * 1378 * ARGUMENTS: 1379 * char *pathname Pathname to mangle. 1380 * 1381 * RETURN VALUE: 1382 * (none) 1383 * 1384 * NOTES: 1385 * 1386 */ 1387 static void backuppc_bufuse(struct backuppc_client_info *node, const size_t amount) { 1388 1389 assert(amount <= node->bufused); 1390 assert(amount <= node->bufsize); 1391 1392 node->buf += amount; 1393 node->bufused -= amount; 1394 node->bufsize -= amount; 1395 1396 return; 1397 } 1398 1399 /* 1400 * SYNOPSIS: 1401 * static void backuppc_pathmangle( 1402 * char *pathname 1403 * ); 1404 * 1405 * ARGUMENTS: 1406 * char *pathname Pathname to mangle. 1407 * 1408 * RETURN VALUE: 1409 * (none) 1410 * 1411 * NOTES: 1412 * 1413 */ 1414 static int backuppc_bufmemcpy(struct backuppc_client_info *src, void *dst, size_t n) { 1415 1416 if (src->bufsize < n) { 1417 return(0); 1418 } 1419 if (src->bufused < n) { 1420 return(0); 1421 } 1422 1423 memcpy(dst, src->buf, n); 1424 backuppc_bufuse(src, n); 1425 1426 return(1); 1427 } 1428 1429 /* 1430 * SYNOPSIS: 1431 * static void backuppc_pathmangle( 1432 * char *pathname 1433 * ); 1434 * 1435 * ARGUMENTS: 1436 * char *pathname Pathname to mangle. 1437 * 1438 * RETURN VALUE: 1439 * (none) 1440 * 1441 * NOTES: 1442 * 1443 */ 1444 static int backuppc_outbufmemcpy(struct backuppc_client_info *dst, const void *src, size_t n) { 1445 size_t bytesleft; 1446 unsigned long newoutbufsize; 1447 void *newbuf_s, *newbuf; 1448 1449 /* If we've been asked to write more data than will ever fit in the 1450 buffer, change the buffer. */ 1451 if (n > dst->outbufsize_s) { 1452 if (dst->outbufsize_s == BPC_MAXOUTBUF_LEN) { 1453 /* The buffer is as large as it will get, but it is 1454 still not large enough. Must be invalid data. */ 1455 dst->invalid_data = 1; 1456 return(0); 1457 } 1458 1459 newoutbufsize = dst->outbufsize_s * 2; 1460 1461 if (newoutbufsize > BPC_MAXOUTBUF_LEN) { 1462 newoutbufsize = BPC_MAXOUTBUF_LEN; 1463 } 1464 1465 newbuf_s = realloc(dst->outbuf_s, newoutbufsize); 1466 1467 if (!newbuf_s) { 1468 return(0); 1469 } 1470 1471 newbuf = newbuf_s + (dst->outbuf - dst->outbuf_s); 1472 1473 dst->outbufsize += (newoutbufsize - dst->outbufsize_s); 1474 dst->outbufsize_s = newoutbufsize; 1475 dst->outbuf_s = newbuf_s; 1476 dst->outbuf = newbuf; 1477 1478 if (n > dst->outbufsize_s) { 1479 return(0); 1480 } 1481 } 1482 1483 bytesleft = dst->outbufsize - dst->outbufused; 1484 1485 if (bytesleft < n) { 1486 return(0); 1487 } 1488 1489 memcpy(dst->outbuf + dst->outbufused, src, n); 1490 dst->outbufused += n; 1491 1492 return(1); 1493 } 1494 1495 /* 1496 * SYNOPSIS: 1497 * static void backuppc_pathmangle( 1498 * char *pathname 1499 * ); 1500 * 1501 * ARGUMENTS: 1502 * char *pathname Pathname to mangle. 1503 * 1504 * RETURN VALUE: 1505 * (none) 1506 * 1507 * NOTES: 1508 * For type = BPC_DT_STRING_PTR, must be a pointer to (char *) NULL initially, or allocated 1509 * size + 1 or greater. 1510 * 1511 */ 1512 static int backuppc_readvalues(struct backuppc_client_info *client, backuppc_recv_mark_t rmid, ...) { 1513 struct backuppc_client_prochandle *ph; 1514 backuppc_datatypes_t typeid; 1515 va_list ap; 1516 uint8_t *u8v; 1517 uint16_t *u16v; 1518 uint32_t *u32v; 1519 uint64_t *u64v; 1520 char *cpv, **cppv; 1521 void *vpv = NULL, **vppv; 1522 size_t vpv_len; 1523 int argcnt; 1524 1525 ph = client->process_handle; 1526 1527 if (ph->recv_sect[rmid]) { 1528 return(1); 1529 } 1530 1531 va_start(ap, rmid); 1532 for (argcnt = 0;; argcnt++) { 1533 typeid = va_arg(ap, backuppc_datatypes_t); 1534 1535 if (typeid == BPC_DT_END) { 1536 break; 1537 } 1538 1539 switch (typeid) { 1540 case BPC_DT_UINT8: 1541 u8v = va_arg(ap, uint8_t *); 1542 vpv_len = sizeof(*u8v); 1543 vpv = u8v; 1544 break; 1545 case BPC_DT_UINT16: 1546 u16v = va_arg(ap, uint16_t *); 1547 vpv_len = sizeof(*u16v); 1548 vpv = u16v; 1549 break; 1550 case BPC_DT_UINT32: 1551 u32v = va_arg(ap, uint32_t *); 1552 vpv_len = sizeof(*u32v); 1553 vpv = u32v; 1554 break; 1555 case BPC_DT_UINT64: 1556 u64v = va_arg(ap, uint64_t *); 1557 vpv_len = sizeof(*u64v); 1558 vpv = u64v; 1559 break; 1560 case BPC_DT_BYTEARRAY: 1561 vpv_len = va_arg(ap, size_t); 1562 vpv = va_arg(ap, void *); 1563 break; 1564 case BPC_DT_BYTEARRAY_PTR: 1565 vpv_len = va_arg(ap, size_t); 1566 vppv = va_arg(ap, void **); 1567 1568 if (*vppv == NULL) { 1569 *vppv = malloc(vpv_len); 1570 vpv = *vppv; 1571 } 1572 break; 1573 case BPC_DT_STRING: 1574 vpv_len = va_arg(ap, size_t); 1575 vpv_len--; 1576 cpv = va_arg(ap, char *); 1577 cpv[vpv_len] = '\0'; 1578 vpv = cpv; 1579 break; 1580 case BPC_DT_STRING_PTR: 1581 vpv_len = va_arg(ap, size_t); 1582 cppv = va_arg(ap, char **); 1583 if (*cppv == NULL) { 1584 cpv = *cppv = malloc(vpv_len + 1); 1585 cpv[vpv_len] = '\0'; 1586 } else { 1587 cpv = *cppv; 1588 } 1589 vpv = cpv; 1590 break; 1591 default: 1592 return(0); 1593 } 1594 1595 if (argcnt <= ph->rv_idx) { 1596 continue; 1597 } 1598 1599 if (!backuppc_bufmemcpy(client, vpv, vpv_len)) { 1600 return(0); 1601 } 1602 1603 switch (typeid) { 1604 case BPC_DT_UINT16: 1605 u16v = vpv; 1606 *u16v = ntohs(*u16v); 1607 break; 1608 case BPC_DT_UINT32: 1609 u32v = vpv; 1610 *u32v = ntohl(*u32v); 1611 break; 1612 case BPC_DT_UINT64: 1613 u64v = vpv; 1614 *u64v = ntohll(*u64v); 1615 break; 1616 default: 1617 break; 1618 } 1619 1620 ph->rv_idx = argcnt; 1621 } 1622 va_end(ap); 1623 1624 ph->rv_idx = -1; 1625 1626 if (rmid != BPC_RM_NONE) { 1627 ph->recv_sect[rmid] = 1; 1628 } 1629 1630 return(1); 1631 } 1632 1633 /* 1634 * SYNOPSIS: 1635 * static void backuppc_pathmangle( 1636 * char *pathname 1637 * ) 1638 * 1639 * ARGUMENTS: 1640 * char *pathname Pathname to mangle. 1641 * 1642 * RETURN VALUE: 1643 * (none) 1644 * 1645 * NOTES: 1646 * 1647 */ 1648 static int backuppc_writevalues(struct backuppc_client_info *client, backuppc_send_mark_t smid, ...) { 1649 struct backuppc_client_prochandle *ph; 1650 backuppc_datatypes_t typeid; 1651 va_list ap; 1652 uint8_t u8v; 1653 uint16_t u16v; 1654 uint32_t u32v; 1655 uint64_t u64v; 1656 void *vpv; 1657 char *cpv; 1658 size_t vpv_len; 1659 int argcnt; 1660 1661 ph = client->process_handle; 1662 1663 if (ph->sent_sect[smid]) { 1664 return(1); 1665 } 1666 1667 va_start(ap, smid); 1668 for (argcnt = 0;; argcnt++) { 1669 typeid = va_arg(ap, backuppc_datatypes_t); 1670 1671 if (typeid == BPC_DT_END) { 1672 break; 1673 } 1674 1675 switch (typeid) { 1676 case BPC_DT_UINT8: 1677 u8v = va_arg(ap, int); 1678 vpv_len = sizeof(u8v); 1679 vpv = &u8v; 1680 break; 1681 case BPC_DT_UINT16: 1682 u16v = va_arg(ap, int); 1683 u16v = htons(u16v); 1684 vpv_len = sizeof(u16v); 1685 vpv = &u16v; 1686 break; 1687 case BPC_DT_UINT32: 1688 u32v = va_arg(ap, uint32_t); 1689 u32v = htonl(u32v); 1690 vpv_len = sizeof(u32v); 1691 vpv = &u32v; 1692 break; 1693 case BPC_DT_UINT64: 1694 u64v = va_arg(ap, uint64_t); 1695 u64v = htonll(u64v); 1696 vpv_len = sizeof(u64v); 1697 vpv = &u64v; 1698 break; 1699 case BPC_DT_BYTEARRAY: 1700 vpv_len = va_arg(ap, size_t); 1701 vpv = va_arg(ap, void *); 1702 break; 1703 case BPC_DT_STRING: 1704 cpv = va_arg(ap, char *); 1705 vpv_len = strlen(cpv); 1706 vpv = cpv; 1707 break; 1708 case BPC_DT_BYTEARRAY_PTR: 1709 case BPC_DT_STRING_PTR: 1710 default: 1711 return(0); 1712 } 1713 1714 if (argcnt <= ph->wv_idx) { 1715 continue; 1716 } 1717 1718 if (!backuppc_outbufmemcpy(client, vpv, vpv_len)) { 1719 return(0); 1720 } 1721 1722 ph->wv_idx = argcnt; 1723 } 1724 va_end(ap); 1725 1726 ph->wv_idx = -1; 1727 1728 if (smid != BPC_SM_NONE) { 1729 ph->sent_sect[smid] = 1; 1730 } 1731 1732 return(1); 1733 } 1734 1735 /* 1736 * SYNOPSIS: 1737 * static void backuppc_pathmangle( 1738 * char *pathname 1739 * ) 1740 * 1741 * ARGUMENTS: 1742 * char *pathname Pathname to mangle. 1743 * 1744 * RETURN VALUE: 1745 * (none) 1746 * 1747 * NOTES: 1748 * 1749 */ 1750 static void backuppc_process_listget_init(struct backuppc_client_info *client) { 1751 struct backuppc_client_prochandle *ph; 1752 int i; 1753 1754 ph = client->process_handle; 1755 1756 for (i = 0; i < (sizeof(ph->dh) / sizeof(ph->dh[0])); i++) { 1757 ph->dh[i] = NULL; 1758 } 1759 1760 ph->dhidx = 0; 1761 ph->dent = NULL; 1762 ph->options = 0; 1763 ph->pathname = NULL; 1764 ph->pathname_len = 0; 1765 ph->excl_sect_len = 0; 1766 ph->incl_sect_len = 0; 1767 1768 return; 1769 } 1770 1771 /* 1772 * SYNOPSIS: 1773 * static void backuppc_pathmangle( 1774 * char *pathname 1775 * ) 1776 * 1777 * ARGUMENTS: 1778 * char *pathname Pathname to mangle. 1779 * 1780 * RETURN VALUE: 1781 * (none) 1782 * 1783 * NOTES: 1784 * 1785 */ 1786 static void backuppc_process_listget_fini(struct backuppc_client_info *client) { 1787 struct backuppc_client_prochandle *ph; 1788 int i; 1789 1790 ph = client->process_handle; 1791 1792 for (i = 0; i < (sizeof(ph->dh) / sizeof(ph->dh[0])); i++) { 1793 if (!ph->dh[i]) { 1794 break; 1795 } 1796 1797 backuppc_closedir(ph->dh[i]); 1798 1799 ph->dh[i] = NULL; 1800 } 1801 1802 if (ph->pathname) { 1803 free(ph->pathname); 1804 ph->pathname = NULL; 1805 } 1806 1807 return; 1808 } 1809 1810 /* 1811 * SYNOPSIS: 1812 * static void backuppc_pathmangle( 1813 * char *pathname 1814 * ) 1815 * 1816 * ARGUMENTS: 1817 * char *pathname Pathname to mangle. 1818 * 1819 * RETURN VALUE: 1820 * (none) 1821 * 1822 * NOTES: 1823 * 1824 */ 1825 static int backuppc_process_listget(struct backuppc_client_info *client) { 1826 struct backuppc_client_prochandle *ph; 1827 ssize_t read_ret, get_attr_ret; 1828 int i, sparse_block; 1829 int recurse_dir; 1830 #ifdef HAVE_STATFS 1831 struct statfs dirinfo; 1832 int statfs_ret; 1833 #endif 1834 1835 ph = client->process_handle; 1836 1837 /* 1838 * Require READ or READ-WRITE privileges to LIST/GET 1839 */ 1840 if (client->privs != BPC_PRIV_READ && client->privs != BPC_PRIV_RDWR) { 1841 client->invalid_data = 1; 1842 return(-1); 1843 } 1844 1845 /* 1846 * Read the header information from the buffer. 1847 */ 1848 if (!backuppc_readvalues(client, BPC_RM_HEADER, 1849 BPC_DT_UINT8, (uint8_t *) &ph->options, 1850 BPC_DT_UINT32, (uint32_t *) &ph->excl_sect_len, 1851 BPC_DT_UINT32, (uint32_t *) &ph->incl_sect_len, 1852 BPC_DT_UINT32, (uint32_t *) &ph->pathname_len, 1853 BPC_DT_END)) { 1854 return(-1); 1855 } 1856 1857 /* 1858 * Currently we do not handle client-specified exclude data. 1859 * XXX: Fix this. 1860 */ 1861 if (ph->excl_sect_len != 0) { 1862 client->invalid_data = 1; 1863 return(-1); 1864 } 1865 if (ph->incl_sect_len != 0) { 1866 client->invalid_data = 1; 1867 return(-1); 1868 } 1869 1870 /* 1871 * Do not allow the client to specify an insane pathname length. 1872 */ 1873 if (ph->pathname_len > BPC_MAXPATH_LEN) { 1874 client->invalid_data = 1; 1875 return(-1); 1876 } 1877 1878 if (!backuppc_readvalues(client, BPC_RM_PATHNAME, BPC_DT_STRING_PTR, (size_t) ph->pathname_len, (char **) &ph->pathname, BPC_DT_END)) { 1879 return(-1); 1880 } 1881 1882 /* 1883 * Once we've read the full header, update the status to indicate that 1884 * further calls to this function will cause the outbuf to be updated. 1885 */ 1886 client->outdata_waiting = 1; 1887 1888 if (!backuppc_writevalues(client, BPC_SM_PKT_HEADER, BPC_DT_UINT8, (uint8_t) (ph->cmd | 0x80), BPC_DT_END)) { 1889 return(-1); 1890 } 1891 1892 if (ph->dh[0] == NULL) { 1893 if (ph->pathname) { 1894 ph->dh[0] = backuppc_opendir(ph->pathname); 1895 1896 free(ph->pathname); 1897 ph->pathname = NULL; 1898 } 1899 ph->dhidx = 0; 1900 } 1901 1902 while (1) { 1903 if (!ph->dent) { 1904 if (ph->dh[ph->dhidx]) { 1905 ph->dent = backuppc_readdir(ph->dh[ph->dhidx]); 1906 } else { 1907 ph->dent = NULL; 1908 } 1909 1910 if (ph->dent == NULL) { 1911 /* End of directory. */ 1912 1913 if (ph->dh[ph->dhidx]) { 1914 backuppc_closedir(ph->dh[ph->dhidx]); 1915 } 1916 1917 ph->dh[ph->dhidx] = NULL; 1918 1919 if (ph->dhidx == 0) { 1920 break; 1921 } else { 1922 ph->dhidx--; 1923 continue; 1924 } 1925 } 1926 1927 /* Clear the per-file indicators. */ 1928 ph->sent_sect[BPC_SM_PATHNAME] = 0; 1929 ph->sent_sect[BPC_SM_HEADER] = 0; 1930 ph->sent_sect[BPC_SM_DATA_CLEANUP] = 0; 1931 1932 get_attr_ret = backuppc_get_attr(ph->dent, ph->attrdata, sizeof(ph->attrdata), ph->options); 1933 if (get_attr_ret >= 0) { 1934 ph->attrlen = get_attr_ret; 1935 } else { 1936 ph->attrlen = 0; 1937 } 1938 } 1939 1940 if (ph->cmd == BPC_CMD_GET && ph->dent->type == BPC_FILE_REG) { 1941 if (ph->dent->fd < 0) { 1942 backuppc_openfile(ph->dent, O_RDONLY, 0); 1943 1944 /* If we can't open the file, skip it. */ 1945 if (ph->dent->fd < 0) { 1946 ph->dent = NULL; 1947 continue; 1948 } 1949 1950 ph->bytes_written = 0; 1951 ph->block_num = 0; 1952 } 1953 } 1954 1955 if (!backuppc_writevalues(client, BPC_SM_HEADER, 1956 BPC_DT_UINT8, (uint8_t) ph->dent->type, 1957 BPC_DT_UINT32, (uint32_t) ph->attrlen, 1958 BPC_DT_UINT64, (uint64_t) ph->dent->size, 1959 BPC_DT_UINT32, (uint32_t) ph->tmpbufsize, 1960 BPC_DT_UINT32, (uint32_t) strlen(ph->dent->fullpathname), 1961 BPC_DT_STRING, (char *) ph->dent->fullpathname, 1962 BPC_DT_BYTEARRAY, (size_t) ph->attrlen, (void *) ph->attrdata, 1963 BPC_DT_END)) { 1964 return(-1); 1965 } 1966 1967 /* Send the contents of the file. */ 1968 while (ph->dent->fd >= 0) { 1969 /* 1970 * Read data into the tmpbuffer if it is empty. 1971 */ 1972 if (ph->tmpbufused == 0) { 1973 read_ret = read(ph->dent->fd, ph->tmpbuf, ph->tmpbufsize); 1974 1975 if (read_ret <= 0) { 1976 /* 1977 * If we can't read as many bytes as 1978 * we said were in the file, send 1979 * junk to pad the buffer. Perhaps 1980 * we should make a list of files 1981 * to re-transmit. (XXX) 1982 */ 1983 if (ph->bytes_written < ph->dent->size) { 1984 read_ret = ph->tmpbufsize; 1985 } else { 1986 backuppc_closefile(ph->dent); 1987 continue; 1988 } 1989 } 1990 1991 ph->tmpbufused = read_ret; 1992 1993 /* 1994 * Do NOT send more than we've agreed to send, 1995 * if we read more than the size fo the file, 1996 * send only as many bytes as we've said the 1997 * file contained. 1998 */ 1999 if ((ph->bytes_written + ph->tmpbufused) > ph->dent->size) { 2000 ph->tmpbufused = ph->dent->size - ph->bytes_written; 2001 } 2002 2003 if (ph->dent->issparse) { 2004 sparse_block = 1; 2005 for (i = 0; i < ph->tmpbufused; i++) { 2006 if (ph->tmpbuf[i] != '\0') { 2007 sparse_block = 0; 2008 } 2009 } 2010 } else { 2011 sparse_block = 0; 2012 } 2013 2014 if (sparse_block) { 2015 continue; 2016 } 2017 } 2018 2019 /* 2020 * We write the entire buffer here, even though it 2021 * may contain garbage since we commited to fixed 2022 * sized buffers. The other end will figure out 2023 * that the file is too large and truncate it 2024 * properly. We may omit sending blocks whose 2025 * contents are completely 0s as this is the sign 2026 * of an empty block in a sparse file. 2027 */ 2028 if (!backuppc_writevalues(client, BPC_SM_NONE, 2029 BPC_DT_UINT32, (uint32_t) ph->block_num, 2030 BPC_DT_BYTEARRAY, (size_t) ph->tmpbufsize, (void *) ph->tmpbuf, 2031 BPC_DT_END)) { 2032 return(-1); 2033 } 2034 2035 ph->bytes_written += ph->tmpbufused; 2036 ph->block_num++; 2037 2038 ph->tmpbufused = 0; 2039 } 2040 2041 /* If this is a get request, send the marker for end of the data stream. */ 2042 if (ph->cmd == BPC_CMD_GET) { 2043 if (!backuppc_writevalues(client, BPC_SM_DATA_CLEANUP, 2044 BPC_DT_UINT32, (uint32_t) 0xFFFFFFFF, 2045 BPC_DT_END)) { 2046 return(-1); 2047 } 2048 } 2049 2050 /* If this is a directory and we are to be recursive, follow it. */ 2051 if (ph->dent->type == BPC_FILE_DIR && (ph->options & BPC_OPT_RECURSIVE) == BPC_OPT_RECURSIVE) { 2052 recurse_dir = 1; 2053 #if defined(HAVE_GETMNTINFO) 2054 /* 2055 * XXX: Determine whether or not the new path name is on a filesystem we backup (bsd) 2056 */ 2057 #elif defined(HAVE_STATFS) 2058 /* 2059 * XXX: Determine whether or not the new path name is on a filesystem we backup (linux) 2060 * 2061 * This should probably be made a configurable parameter. 2062 */ 2063 statfs_ret = statfs(ph->dent->fullpathname, &dirinfo); 2064 if (statfs_ret == 0) { 2065 switch (dirinfo.f_type) { 2066 case NFS_SUPER_MAGIC: 2067 case PROC_SUPER_MAGIC: 2068 case DEVFS_SUPER_MAGIC: 2069 case NCP_SUPER_MAGIC: 2070 case SMB_SUPER_MAGIC: 2071 case TMPFS_MAGIC: 2072 case ISOFS_SUPER_MAGIC: 2073 recurse_dir = 0; 2074 break; 2075 } 2076 } 2077 #endif 2078 } else { 2079 recurse_dir = 0; 2080 } 2081 2082 if (recurse_dir) { 2083 2084 ph->dhidx++; 2085 2086 if (ph->dhidx >= sizeof(ph->dh) / sizeof(ph->dh[0])) { 2087 /* Refuse to overflow the buffer. */ 2088 ph->dhidx--; 2089 2090 client->invalid_data = 1; 2091 2092 return(-1); 2093 } 2094 2095 ph->dh[ph->dhidx] = backuppc_opendir(ph->dent->fullpathname); 2096 if (!ph->dh[ph->dhidx]) { 2097 ph->dhidx--; 2098 } 2099 } 2100 2101 ph->dent = NULL; 2102 } 2103 2104 if (!backuppc_writevalues(client, BPC_SM_CLEANUP, BPC_DT_UINT8, (uint8_t) 0xff, BPC_DT_END)) { 2105 return(-1); 2106 } 2107 2108 backuppc_process_listget_fini(client); 2109 backuppc_process_listget_init(client); 2110 2111 return(0); 2112 } 2113 2114 /* 2115 * SYNOPSIS: 2116 * static void backuppc_pathmangle( 2117 * char *pathname 2118 * ) 2119 * 2120 * ARGUMENTS: 2121 * char *pathname Pathname to mangle. 2122 * 2123 * RETURN VALUE: 2124 * (none) 2125 * 2126 * NOTES: 2127 * 2128 */ 2129 static void backuppc_process_auth_init(struct backuppc_client_info *client) { 2130 struct backuppc_client_prochandle *ph; 2131 2132 ph = client->process_handle; 2133 2134 ph->username = NULL; 2135 ph->password = NULL; 2136 2137 return; 2138 } 2139 2140 /* 2141 * SYNOPSIS: 2142 * static void backuppc_pathmangle( 2143 * char *pathname 2144 * ) 2145 * 2146 * ARGUMENTS: 2147 * char *pathname Pathname to mangle. 2148 * 2149 * RETURN VALUE: 2150 * (none) 2151 * 2152 * NOTES: 2153 * 2154 */ 2155 static void backuppc_process_auth_fini(struct backuppc_client_info *client) { 2156 struct backuppc_client_prochandle *ph; 2157 2158 ph = client->process_handle; 2159 2160 if (ph->username) { 2161 free(ph->username); 2162 ph->username = NULL; 2163 } 2164 2165 if (ph->password) { 2166 free(ph->password); 2167 ph->password = NULL; 2168 } 2169 2170 return; 2171 } 2172 2173 /* 2174 * SYNOPSIS: 2175 * static void backuppc_pathmangle( 2176 * char *pathname 2177 * ) 2178 * 2179 * ARGUMENTS: 2180 * char *pathname Pathname to mangle. 2181 * 2182 * RETURN VALUE: 2183 * (none) 2184 * 2185 * NOTES: 2186 * 2187 */ 2188 static int backuppc_process_auth(struct backuppc_client_info *client) { 2189 struct backuppc_client_prochandle *ph; 2190 backuppc_status_t auth_stat = BPC_STATUS_UNKNOWN; 2191 char *crypt_passwd; 2192 2193 ph = client->process_handle; 2194 2195 if (!backuppc_readvalues(client, BPC_RM_HEADER, 2196 BPC_DT_UINT16, (uint16_t *) &ph->username_len, 2197 BPC_DT_UINT16, (uint16_t *) &ph->password_len, 2198 BPC_DT_END)) { 2199 return(-1); 2200 } 2201 2202 if (ph->username_len > BPC_MAXUSERNAME_LEN) { 2203 client->invalid_data = 1; 2204 } 2205 2206 if (ph->password_len > BPC_MAXPASSWORD_LEN) { 2207 client->invalid_data = 1; 2208 } 2209 2210 if (!backuppc_readvalues(client, BPC_RM_AUTHDATA, 2211 BPC_DT_STRING_PTR, (size_t) ph->username_len, (char **) &ph->username, 2212 BPC_DT_STRING_PTR, (size_t) ph->password_len, (char **) &ph->password, 2213 BPC_DT_END)) { 2214 return(-1); 2215 } 2216 2217 /* Do authentication ... */ 2218 2219 /* Attempt to authenticate with the master password. */ 2220 crypt_passwd = sha1sum(ph->password); 2221 if (strcmp(crypt_passwd, MASTER_PASSWORD) == 0) { 2222 auth_stat = BPC_STATUS_OKAY; 2223 client->privs = BPC_PRIV_RDWR; 2224 } else { 2225 /* 2226 * Perform authentication of the user 2227 */ 2228 client->privs = bpcd_auth_verify(ph->username, crypt_passwd, client->addr.s_addr); 2229 2230 /* 2231 * If the authentication subsystem returns an error, assign 2232 * the session no privileges and declare failure. 2233 */ 2234 if (client->privs == BPC_PRIV_ERROR) { 2235 auth_stat = BPC_STATUS_FAILED; 2236 client->privs = BPC_PRIV_NONE; 2237 } else { 2238 auth_stat = BPC_STATUS_OKAY; 2239 } 2240 } 2241 2242 if (auth_stat == BPC_STATUS_OKAY) { 2243 #ifdef HAVE_SYSLOG 2244 syslog(LOG_INFO, "Authenticated \"%s\" from %s.", ph->username, inet_ntoa(client->addr)); 2245 #endif 2246 } else { 2247 #ifdef HAVE_SYSLOG 2248 syslog(LOG_INFO, "Failed login attempt for \"%s\" from %s.", ph->username, inet_ntoa(client->addr)); 2249 #endif 2250 } 2251 2252 if (auth_stat == BPC_STATUS_UNKNOWN) { 2253 auth_stat = BPC_STATUS_FAILED; 2254 } 2255 2256 /* 2257 * Send reply. 2258 */ 2259 if (!backuppc_writevalues(client, BPC_SM_AUTHSTATUS, 2260 BPC_DT_UINT8, (uint8_t) BPC_CMD_AUTH_REPLY, 2261 BPC_DT_UINT8, (uint8_t) auth_stat, 2262 BPC_DT_END)) { 2263 return(-1); 2264 } 2265 2266 backuppc_process_auth_fini(client); 2267 backuppc_process_auth_init(client); 2268 2269 return(0);; 2270 } 2271 2272 /* 2273 * SYNOPSIS: 2274 * static void backuppc_pathmangle( 2275 * char *pathname 2276 * ) 2277 * 2278 * ARGUMENTS: 2279 * char *pathname Pathname to mangle. 2280 * 2281 * RETURN VALUE: 2282 * (none) 2283 * 2284 * NOTES: 2285 * 2286 */ 2287 static void backuppc_process_client_init(struct backuppc_client_info *client) { 2288 struct backuppc_client_prochandle *ph; 2289 int i; 2290 2291 ph = malloc(sizeof(*ph)); 2292 2293 if (!ph) { 2294 return; 2295 } 2296 2297 ph->cmd = BPC_CMD_NONE; 2298 2299 for (i = 0; i < (sizeof(ph->sent_sect) / sizeof(ph->sent_sect[0])); i++) { 2300 ph->sent_sect[i] = 0; 2301 } 2302 2303 for (i = 0; i < (sizeof(ph->recv_sect) / sizeof(ph->recv_sect[0])); i++) { 2304 ph->recv_sect[i] = 0; 2305 } 2306 2307 ph->tmpbufsize = backuppc_writeblock_size; 2308 ph->tmpbuf = calloc(ph->tmpbufsize, 1); 2309 ph->tmpbufused = 0; 2310 ph->wv_idx = -1; 2311 ph->rv_idx = -1; 2312 2313 client->process_handle = ph; 2314 2315 backuppc_process_auth_init(client); 2316 backuppc_process_listget_init(client); 2317 2318 return; 2319 } 2320 2321 /* 2322 * SYNOPSIS: 2323 * static void backuppc_pathmangle( 2324 * char *pathname 2325 * ) 2326 * 2327 * ARGUMENTS: 2328 * char *pathname Pathname to mangle. 2329 * 2330 * RETURN VALUE: 2331 * (none) 2332 * 2333 * NOTES: 2334 * 2335 */ 2336 static void backuppc_process_client_fini(struct backuppc_client_info *client) { 2337 struct backuppc_client_prochandle *ph; 2338 2339 ph = client->process_handle; 2340 2341 if (!ph) { 2342 return; 2343 } 2344 2345 backuppc_process_auth_fini(client); 2346 backuppc_process_listget_fini(client); 2347 2348 if (ph->tmpbuf) { 2349 free(ph->tmpbuf); 2350 } 2351 2352 free(ph); 2353 2354 return; 2355 } 2356 2357 /* 2358 * SYNOPSIS: 2359 * static void backuppc_pathmangle( 2360 * char *pathname 2361 * ) 2362 * 2363 * ARGUMENTS: 2364 * char *pathname Pathname to mangle. 2365 * 2366 * RETURN VALUE: 2367 * (none) 2368 * 2369 * NOTES: 2370 * 2371 */ 2372 static int backuppc_process_client(struct backuppc_client_info *client) { 2373 struct backuppc_client_prochandle *ph; 2374 uint8_t tmp_cmd; 2375 int cmd_ret; 2376 int i; 2377 2378 ph = client->process_handle; 2379 2380 if (!ph) { 2381 client->invalid_data = 1; 2382 return(0); 2383 } 2384 2385 /* 2386 * This loop processes a single command from the client->buf per 2387 * iteration. It passes the control to a delegate function. 2388 * The delegate function should return a negative value to 2389 * indicate that no more data can be read from the current 2390 * buffer. 2391 */ 2392 do { 2393 if (ph->cmd == BPC_CMD_NONE) { 2394 if (!backuppc_readvalues(client, BPC_RM_NONE, 2395 BPC_DT_UINT8, (uint8_t *) &tmp_cmd, 2396 BPC_DT_END)) { 2397 return(0); 2398 } 2399 2400 ph->cmd = tmp_cmd; 2401 } 2402 2403 switch (ph->cmd) { 2404 case BPC_CMD_AUTH: 2405 cmd_ret = backuppc_process_auth(client); 2406 break; 2407 case BPC_CMD_LIST: 2408 cmd_ret = backuppc_process_listget(client); 2409 break; 2410 case BPC_CMD_GET: 2411 cmd_ret = backuppc_process_listget(client); 2412 break; 2413 case BPC_CMD_PUT: 2414 case BPC_CMD_NONE: 2415 default: 2416 /* Sending an unknown command is considered invalid 2417 data. */ 2418 cmd_ret = -1; 2419 client->invalid_data = 1; 2420 break; 2421 } 2422 2423 if (cmd_ret < 0) { 2424 break; 2425 } 2426 2427 ph->cmd = BPC_CMD_NONE; 2428 2429 for (i = 0; i < (sizeof(ph->sent_sect) / sizeof(ph->sent_sect[0])); i++) { 2430 ph->sent_sect[i] = 0; 2431 } 2432 2433 for (i = 0; i < (sizeof(ph->recv_sect) / sizeof(ph->recv_sect[0])); i++) { 2434 ph->recv_sect[i] = 0; 2435 } 2436 2437 ph->wv_idx = -1; 2438 ph->rv_idx = -1; 2439 2440 client->outdata_waiting = 0; 2441 } while (client->bufused > 0); 2442 2443 return(0); 2444 } 2445 2446 /* 2447 * SYNOPSIS: 2448 * static void backuppc_pathmangle( 2449 * char *pathname 2450 * ) 2451 * 2452 * ARGUMENTS: 2453 * char *pathname Pathname to mangle. 2454 * 2455 * RETURN VALUE: 2456 * (none) 2457 * 2458 * NOTES: 2459 * 2460 */ 2461 static int backuppc_verify_addr(uint32_t addr) { 2462 return(1); 2463 } 2464 2465 int backuppc_switchupdate(char *src, char *dst, const int argc, char **argv) { 2466 size_t fread_ret; 2467 FILE *ifp, *ofp; 2468 char buf[1024]; 2469 char *newargv[1024]; 2470 #ifdef _USE_WIN32_ 2471 char quotebuf[8192]; 2472 #endif 2473 int newargc = 0, i; 2474 2475 ifp = fopen(src, "rb"); 2476 if (!ifp) { 2477 unlink(src); 2478 return(0); 2479 } 2480 2481 ofp = fopen(dst, "wb"); 2482 if (!ofp) { 2483 fclose(ifp); 2484 return(0); 2485 } 2486 2487 while (!feof(ifp)) { 2488 fread_ret = fread(buf, sizeof(buf[0]), sizeof(buf), ifp); 2489 if (fread_ret == 0) { 2490 continue; 2491 } 2492 2493 fwrite(buf, sizeof(buf[0]), fread_ret, ofp); 2494 } 2495 2496 fclose(ofp); 2497 fclose(ifp); 2498 2499 unlink(src); 2500 2501 #ifdef _USE_WIN32_ 2502 /* 2503 * More of that lovely Windows-requiring-exec-args-to-be-quoted. 2504 */ 2505 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", dst); 2506 newargv[newargc++] = strdup(quotebuf); 2507 #else 2508 newargv[newargc++] = dst; 2509 #endif 2510 newargv[newargc++] = "--DeleteFile"; 2511 newargv[newargc++] = src; 2512 2513 /* 2514 * We must skip the "--Switch" and "--Source" and "--Destination" 2515 * parameters. They are the first few arguments. 2516 */ 2517 for (i = 6; i < argc; i++) { 2518 #ifdef _USE_WIN32_ 2519 /* 2520 * More of that lovely Windows-requiring-exec-args-to-be-quoted 2521 */ 2522 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", argv[i]); 2523 newargv[newargc++] = strdup(quotebuf); 2524 #else 2525 newargv[newargc++] = argv[i]; 2526 #endif 2527 } 2528 newargv[newargc++] = NULL; 2529 2530 execv(dst, newargv); 2531 2532 return(0); 2533 } 2534 2535 int backuppc_update(const char *url, const int argc, char **argv) { 2536 #ifdef HAVE_LIBOPENNET 2537 size_t fread_ret; 2538 NETFILE *ifp, *cfp; 2539 FILE *ofp; 2540 char buf[8192], localfile[1024], tmpfile[1024], curdir[1024], *tmpdir = NULL; 2541 #ifdef _USE_WIN32_ 2542 char quotebuf[8192]; 2543 #endif 2544 char checkurl[1024], remote_vers[128]; 2545 char *newargv[1024]; 2546 int newargc = 0, i; 2547 2548 if (!url) { 2549 return(1); 2550 } 2551 2552 /* 2553 * Check to see if the remote binary is a newer version than ours 2554 */ 2555 snprintf(checkurl, sizeof(checkurl), "%s.vers", url); 2556 cfp = fopen_net(checkurl, "r"); 2557 if (!cfp) { 2558 return(1); 2559 } 2560 2561 remote_vers[0] = '\0'; 2562 2563 fgets_net(remote_vers, sizeof(remote_vers), cfp); 2564 2565 fclose_net(cfp); 2566 2567 /* 2568 * Ignore bogus version strings 2569 */ 2570 if (strlen(remote_vers) <= 0) { 2571 return(1); 2572 } 2573 2574 if (remote_vers[strlen(remote_vers) - 1] == '\n') { 2575 remote_vers[strlen(remote_vers) - 1] = '\0'; 2576 } 2577 2578 if (strcmp(remote_vers, PACKAGE_VERSION) == 0) { 2579 /* 2580 * If the remote version string is identical to the local 2581 * version string, nothing needs to be done. 2582 */ 2583 return(1); 2584 } 2585 2586 /* 2587 * Download the remote binary to the temporary directory. 2588 */ 2589 #ifdef HAVE_GETENV 2590 tmpdir = getenv("TMPDIR"); 2591 #endif 2592 2593 if (!tmpdir) { 2594 #ifdef _USE_WIN32_ 2595 tmpdir = "c:/temp"; 2596 #else 2597 tmpdir = "/tmp"; 2598 #endif 2599 } 2600 2601 backuppc_mkdir(tmpdir); 2602 2603 srand(getpid() + time(NULL)); 2604 2605 snprintf(tmpfile, sizeof(tmpfile), "%s/backuppcd-%i%i%s", tmpdir, rand(), rand(), EXEEXT); 2606 2607 #ifdef _USE_WIN32_ 2608 if (isalpha(argv[0][0]) && argv[0][1] == ':') { 2609 #else 2610 if (argv[0][0] == '/') { 2611 #endif 2612 snprintf(localfile, sizeof(localfile), "%s", argv[0]); 2613 if (access(localfile, R_OK) != 0) { 2614 snprintf(localfile, sizeof(localfile), "%s%s", argv[0], EXEEXT); 2615 } 2616 } else if (argv[0][0] == '.') { 2617 getcwd(curdir, sizeof(curdir)); 2618 curdir[sizeof(curdir) - 1] = '\0'; 2619 snprintf(localfile, sizeof(localfile), "%s/%s", curdir, argv[0]); 2620 if (access(localfile, R_OK) != 0) { 2621 snprintf(localfile, sizeof(localfile), "%s/%s%s", curdir, argv[0], EXEEXT); 2622 } 2623 } else { 2624 if (backuppc_binfile) { 2625 snprintf(localfile, sizeof(localfile), "%s", backuppc_binfile); 2626 } else { 2627 #ifdef _USE_WIN32_ 2628 getcwd(curdir, sizeof(curdir)); 2629 curdir[sizeof(curdir) - 1] = '\0'; 2630 snprintf(localfile, sizeof(localfile), "%s/%s", curdir, argv[0]); 2631 if (access(localfile, R_OK) != 0) { 2632 snprintf(localfile, sizeof(localfile), "%s/%s%s", curdir, argv[0], EXEEXT); 2633 } 2634 if (access(localfile, R_OK) != 0) { 2635 snprintf(localfile, sizeof(localfile), "%s/%s", EXECPREFIX, "backuppcd.exe"); 2636 } 2637 #else 2638 /* Search the PATH for ourselves. */ 2639 CHECKPOINT; 2640 localfile[0] = '\0'; 2641 return(0); 2642 #endif 2643 } 2644 } 2645 2646 ofp = fopen(tmpfile, "wb"); 2647 if (!ofp) { 2648 return(0); 2649 } 2650 2651 ifp = fopen_net(url, "rb"); 2652 if (!ifp) { 2653 fclose(ofp); 2654 unlink(tmpfile); 2655 return(0); 2656 } 2657 2658 while (!feof_net(ifp)) { 2659 fread_ret = fread_net(buf, sizeof(buf[0]), sizeof(buf), ifp); 2660 if (fread_ret == 0) { 2661 continue; 2662 } 2663 2664 fwrite(buf, sizeof(buf[0]), fread_ret, ofp); 2665 } 2666 2667 fclose_net(ifp); 2668 fclose(ofp); 2669 2670 chmod(tmpfile, S_IXUSR | S_IRUSR | S_IWUSR); 2671 2672 newargv[newargc++] = tmpfile; 2673 newargv[newargc++] = "--Switch"; 2674 newargv[newargc++] = "--Source"; 2675 newargv[newargc++] = tmpfile; 2676 newargv[newargc++] = "--Destination"; 2677 2678 #ifdef _USE_WIN32_ 2679 /* 2680 * Under Windows, we must QUOTE EVERY ARGUMENT that might contain a 2681 * space, otherwise, Windows gets confused and splits them into 2682 * many arguments. This may be a mingw32 problem, not sure. (XXX) 2683 */ 2684 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", localfile); 2685 newargv[newargc++] = strdup(quotebuf); 2686 #else 2687 newargv[newargc++] = localfile; 2688 #endif 2689 2690 /* 2691 * Append all command line arguments given to the current instance of 2692 * BackupPCd to pass to the child. 2693 */ 2694 for (i = 1; i < argc; i++) { 2695 #ifdef _USE_WIN32_ 2696 /* 2697 * More of that lovely Windows quoting. 2698 */ 2699 snprintf(quotebuf, sizeof(quotebuf), "\"%s\"", argv[i]); 2700 newargv[newargc++] = strdup(argv[i]); 2701 #else 2702 newargv[newargc++] = argv[i]; 2703 #endif 2704 } 2705 newargv[newargc++] = NULL; 2706 2707 execv(tmpfile, newargv); 2708 2709 unlink(tmpfile); 2710 #endif 2711 return(0); 2712 } 2713 2714 /* 2715 * SYNOPSIS: 2716 * int backuppc_loop( 2717 * int argc, 2718 * char **argv, 2719 * ); 2720 * 2721 * ARGUMENTS: 2722 * int argc Argument count, should be same as passed 2723 * to main() 2724 * char **argv Argument vector, should be same as passwd to 2725 * main() 2726 * 2727 * RETURN VALUE: 2728 * This function will only return `EXIT_SUCCESS' 2729 * 2730 * NOTES: 2731 * This function is the primary worker loop. 2732 * 2733 */ 2734 int backuppc_loop(int argc, char **argv) { 2735 struct backuppc_client_info *cinfo = NULL, *curnode, *prevnode, *nextnode; 2736 struct sockaddr_in client_addr; 2737 struct timeval tmout; 2738 socklen_t client_addr_len; 2739 ssize_t recv_ret, send_ret; 2740 fd_set rfds, wfds; 2741 #ifdef HAVE_FCNTL 2742 long sock_flags; 2743 #endif 2744 int master_fd, max_fd, client_fd; 2745 int select_ret; 2746 int need_cleanup = 0; 2747 int error_count = 0; 2748 int process_node; 2749 time_t next_update, curr_time; 2750 2751 WorkLoopStatus = LOOP_RUN; 2752 2753 master_fd = net_listen(backuppc_port); 2754 2755 max_fd = master_fd; 2756 2757 next_update = time(NULL) + BPC_UPDATE_INTERVAL; 2758 2759 while (1) { 2760 if (master_fd < 0 || error_count > 10) { 2761 2762 WorkLoopStatus = LOOP_STOP; 2763 2764 break; 2765 } 2766 2767 /* 2768 * Reset the structures needed for the select() call. 2769 */ 2770 max_fd = master_fd; 2771 2772 FD_ZERO(&rfds); 2773 FD_ZERO(&wfds); 2774 FD_SET(master_fd, &rfds); 2775 for (curnode = cinfo; curnode; curnode = curnode->_next) { 2776 2777 assert(curnode != curnode->_next); 2778 2779 if (curnode->fd < 0) { 2780 continue; 2781 } 2782 2783 if (curnode->fd > max_fd) { 2784 max_fd = curnode->fd; 2785 } 2786 2787 FD_SET(curnode->fd, &rfds); 2788 2789 if (curnode->outdata_waiting || (curnode->outbufused > 0)) { 2790 FD_SET(curnode->fd, &wfds); 2791 } 2792 } 2793 2794 #ifdef _USE_WIN32_ 2795 /* 2796 * Under win32 we might be asked by ourselves (thread) to quit 2797 * so we should do this in a reasonable amount of time. 2798 */ 2799 tmout.tv_sec = 10; 2800 tmout.tv_usec = 0; 2801 #else 2802 if (need_cleanup) { 2803 /* 2804 * If clean-up has been requested, set the timeout to 2805 * a smaller value so we can perform it after a 2806 * reasonable amount of idle time. 2807 */ 2808 tmout.tv_sec = 120; 2809 tmout.tv_usec = 0; 2810 } else { 2811 tmout.tv_sec = 86400; 2812 tmout.tv_usec = 0; 2813 } 2814 #endif 2815 2816 select_ret = select(max_fd + 1, &rfds, &wfds, NULL, &tmout); 2817 2818 #ifdef _USE_WIN32_ 2819 /* 2820 * If we've been asked to terminate by a concurrent thread 2821 * set our status to LOOP_STOP (not LOOP_DONE) and 2822 * terminate the infinite loop. 2823 */ 2824 if (WorkLoopStatus != LOOP_RUN) { 2825 WorkLoopStatus = LOOP_STOP; 2826 break; 2827 } 2828 #endif 2829 2830 /* 2831 * If select() goes insane, don't get stuck in an endless 2832 * loop. 2833 */ 2834 if (select_ret < 0) { 2835 error_count++; 2836 continue; 2837 } 2838 2839 error_count = 0; 2840 2841 /* 2842 * Time-out section. Handle maintenance taks when there is 2843 * idle time. 2844 */ 2845 if (select_ret == 0) { 2846 /* 2847 * Perform automatic update if available. 2848 */ 2849 if (backuppc_updateurl) { 2850 curr_time = time(NULL); 2851 if (curr_time >= next_update) { 2852 backuppc_update(backuppc_updateurl, argc, argv); 2853 next_update = curr_time + BPC_UPDATE_INTERVAL; 2854 } 2855 } 2856 2857 /* 2858 * If clean-up has been requested, perform it now. 2859 */ 2860 if (need_cleanup) { 2861 prevnode = NULL; 2862 curnode = cinfo; 2863 while (curnode) { 2864 if (curnode->fd == -1) { 2865 /* Remove dead sockets from the list. */ 2866 if (prevnode) { 2867 prevnode->_next = curnode->_next; 2868 } else { 2869 cinfo = curnode->_next; 2870 } 2871 2872 /* Perform client de-initialization 2873 and maintenance. */ 2874 if (curnode->buf_s) { 2875 free(curnode->buf_s); 2876 } 2877 2878 if (curnode->outbuf_s) { 2879 free(curnode->outbuf_s); 2880 } 2881 2882 backuppc_process_client_fini(curnode); 2883 2884 #if defined(HAVE_SYSLOG) && defined(DEBUG) 2885 syslog(LOG_INFO, "Cleaned connection from %s", inet_ntoa(curnode->addr)); 2886 #endif 2887 2888 nextnode = curnode->_next; 2889 2890 free(curnode); 2891 2892 curnode = nextnode; 2893 2894 continue; 2895 } 2896 2897 prevnode = curnode; 2898 2899 curnode = curnode->_next; 2900 } 2901 2902 need_cleanup = 0; 2903 } 2904 2905 continue; 2906 } 2907 2908 /* Handle incoming connections first. */ 2909 if (FD_ISSET(master_fd, &rfds)) { 2910 client_addr_len = sizeof(client_addr); 2911 client_fd = accept(master_fd, (struct sockaddr *) &client_addr, &client_addr_len); 2912 2913 if (client_fd < 0) { 2914 continue; 2915 } 2916 2917 if (!backuppc_verify_addr(ntohl(client_addr.sin_addr.s_addr))) { 2918 #ifdef HAVE_SYSLOG 2919 syslog(LOG_INFO, "Closing connection from unauthorized client %s", inet_ntoa(client_addr.sin_addr)); 2920 #endif 2921 net_close(client_fd); 2922 continue; 2923 } 2924 #ifdef HAVE_SYSLOG 2925 syslog(LOG_INFO, "Accepted connection from %s", inet_ntoa(client_addr.sin_addr)); 2926 #endif 2927 2928 if (client_fd > max_fd) { 2929 max_fd = client_fd; 2930 } 2931 2932 #ifdef HAVE_FCNTL 2933 /* Make the socket non-blocking, so partial writes can occur. */ 2934 sock_flags = fcntl(client_fd, F_GETFL); 2935 if (sock_flags <= 0) { 2936 sock_flags |= O_NONBLOCK; 2937 fcntl(client_fd, F_SETFL, sock_flags); 2938 } 2939 #endif 2940 2941 curnode = malloc(sizeof(*curnode)); 2942 2943 if (curnode == NULL) { 2944 net_close(client_fd); 2945 continue; 2946 } 2947 2948 /* 2949 * Initialize all members for the node to sane values. 2950 */ 2951 curnode->buf = NULL; 2952 curnode->buf_s = NULL; 2953 curnode->bufsize = 0; 2954 curnode->bufsize_s = 0; 2955 curnode->bufused = 0; 2956 curnode->outbufsize = BPC_OUTBUF_LEN; 2957 curnode->outbuf = malloc(curnode->outbufsize); 2958 curnode->outbuf_s = curnode->outbuf; 2959 curnode->outbufsize_s = curnode->outbufsize; 2960 curnode->outbufused = 0; 2961 curnode->outdata_waiting = 0; 2962 curnode->tx_error_count = 0; 2963 curnode->rx_error_count = 0; 2964 curnode->process_handle = NULL; 2965 curnode->privs = BPC_PRIV_NONE; 2966 curnode->fd = client_fd; 2967 curnode->invalid_data = 0; 2968 memcpy(&curnode->addr, &client_addr.sin_addr, sizeof(client_addr.sin_addr)); 2969 curnode->_next = cinfo; 2970 2971 /* 2972 * Ask the "process_client" routine to initialize 2973 * its "proc_handle" and related members. 2974 */ 2975 backuppc_process_client_init(curnode); 2976 2977 cinfo = curnode; 2978 2979 continue; 2980 } 2981 2982 /* Process data from any connected clients. */ 2983 for (curnode = cinfo; curnode; curnode = curnode->_next) { 2984 /* 2985 * Skip terminated nodes. 2986 */ 2987 if (curnode->fd < 0) { 2988 continue; 2989 } 2990 2991 /* 2992 * If this node has been generating excessive read 2993 * or write errors, terminate it. 2994 */ 2995 if (curnode->tx_error_count > 10 || curnode->rx_error_count > 10) { 2996 #ifdef HAVE_SYSLOG 2997 syslog(LOG_INFO, "Closing connection from %s for excessive errors.", inet_ntoa(curnode->addr)); 2998 #endif 2999 net_close(curnode->fd); 3000 curnode->fd = -1; 3001 3002 need_cleanup = 1; 3003 continue; 3004 } 3005 3006 process_node = 0; 3007 3008 if (FD_ISSET(curnode->fd, &wfds)) { 3009 /* 3010 * if the socket is writable and we have data 3011 * to write to it, attempt to do so. 3012 */ 3013 if (curnode->outbufused > 0 && curnode->outbuf) { 3014 send_ret = send(curnode->fd, curnode->outbuf, curnode->outbufused, 0); 3015 3016 if (send_ret > 0) { 3017 curnode->outbuf += send_ret; 3018 curnode->outbufsize -= send_ret; 3019 curnode->outbufused -= send_ret; 3020 3021 /* Reset error count on successful transmission. */ 3022 curnode->tx_error_count = 0; 3023 } else { 3024 /* Note errors that occur. */ 3025 curnode->tx_error_count++; 3026 } 3027 } else { 3028 /* 3029 * If the node was checked for 3030 * writability and it was, but we have 3031 * no data to write to it, we must be 3032 * stalled somewhere, for debugging 3033 * we will print out a little message 3034 */ 3035 PRINTERR_D("Socket writable but no data to write. Stalled."); 3036 } 3037 3038 /* If there is no data in the buffer, but it has been shrunk, enlarge it. */ 3039 if (curnode->outbuf != NULL && curnode->outbufsize != curnode->outbufsize_s && curnode->outbufused ==0) { 3040 curnode->outbuf = NULL; 3041 } 3042 3043 /* If the buffer is uninitialized or emptied, give us a clean slate. */ 3044 if (curnode->outbuf == NULL) { 3045 if (curnode->outbuf_s) { 3046 curnode->outbuf = curnode->outbuf_s; 3047 curnode->outbufsize = curnode->outbufsize_s; 3048 curnode->outbufused = 0; 3049 } else { 3050 curnode->outbufsize = BPC_OUTBUF_LEN; 3051 curnode->outbuf = malloc(curnode->outbufsize); 3052 curnode->outbuf_s = curnode->outbuf; 3053 curnode->outbufsize_s = curnode->outbufsize; 3054 curnode->outbufused = 0; 3055 } 3056 } 3057 } 3058 3059 /* 3060 * If there is more data to be written for this 3061 * socket, continue processing it. 3062 */ 3063 if (curnode->outdata_waiting) { 3064 process_node = 1; 3065 } 3066 3067 /* 3068 * If the socket has data waiting to be read, attempt 3069 * to read it. 3070 */ 3071 if (FD_ISSET(curnode->fd, &rfds)) { 3072 /* 3073 * If there is no data in the buffer, but it 3074 * has been shrunk, prepare it for 3075 * enlargement. 3076 **/ 3077 if (curnode->buf != NULL && curnode->bufsize != curnode->bufsize_s && curnode->bufused == 0) { 3078 curnode->buf = NULL; 3079 } 3080 3081 /* 3082 * If the buffer is uninitialized or emptied, 3083 * give us a clean slate. 3084 */ 3085 if (curnode->buf == NULL) { 3086 if (curnode->buf_s) { 3087 curnode->buf = curnode->buf_s; 3088 curnode->bufsize = curnode->bufsize_s; 3089 curnode->bufused = 0; 3090 } else { 3091 curnode->bufsize = BPC_BUF_LEN; 3092 curnode->buf = malloc(curnode->bufsize); 3093 curnode->buf_s = curnode->buf; 3094 curnode->bufsize_s = curnode->bufsize; 3095 curnode->bufused = 0; 3096 } 3097 } 3098 3099 /* 3100 * If the buffer is entirely used, but has 3101 * been shrunk, move the data around to 3102 * make more room. 3103 */ 3104 if (curnode->bufused == curnode->bufsize && curnode->bufsize != curnode->bufsize_s) { 3105 memmove(curnode->buf_s, curnode->buf, curnode->bufused); 3106 curnode->bufsize = curnode->bufsize_s; 3107 curnode->buf = curnode->buf_s; 3108 } 3109 3110 /* 3111 * If there is space in the buffer, read data into it. 3112 */ 3113 if ((curnode->bufsize - curnode->bufused) > 0) { 3114 recv_ret = recv(curnode->fd, curnode->buf + curnode->bufused, curnode->bufsize - curnode->bufused, 0); 3115 3116 if (recv_ret == 0) { 3117 /* 3118 * A zero return code indicates 3119 * end of file, free the 3120 * descriptor and cleanup. 3121 */ 3122 #ifdef HAVE_SYSLOG 3123 syslog(LOG_INFO, "Closing connection from %s", inet_ntoa(curnode->addr)); 3124 #endif 3125 net_close(curnode->fd); 3126 curnode->fd = -1; 3127 3128 need_cleanup = 1; 3129 } else if (recv_ret < 0) { 3130 /* 3131 * If we had an error reading 3132 * from the socket, increase 3133 * its error count. 3134 */ 3135 curnode->rx_error_count++; 3136 3137 } else { 3138 /* 3139 * Mark the newly used space 3140 * and ask that the node be 3141 * processed. 3142 */ 3143 curnode->bufused += recv_ret; 3144 3145 process_node = 1; 3146 3147 /* Reset error count on success. */ 3148 curnode->rx_error_count = 0; 3149 } 3150 } else { 3151 /* Consider the buffer filling up an error. */ 3152 curnode->rx_error_count++; 3153 3154 /* 3155 * Attempt to process the node to free 3156 * up buffer space. 3157 */ 3158 process_node = 1; 3159 } 3160 } 3161 3162 if (process_node) { 3163 /* 3164 * If the output buffer is unallocated at this 3165 * point something has gone horribly wrong. 3166 * Do not attempt to process a client with 3167 * no output buffer. 3168 */ 3169 if (curnode->outbuf == NULL) { 3170 curnode->tx_error_count += 100; 3171 curnode->rx_error_count += 100; 3172 error_count++; 3173 continue; 3174 } 3175 3176 /* 3177 * If the output buffer is completely full, do 3178 * not attempt to process more information on 3179 * this node, since we'll have nowhere to 3180 * write results anyway. Print out a debug 3181 * message when this happens. 3182 */ 3183 if (curnode->outbufused == curnode->outbufsize) { 3184 PRINTERR_D("Asked to process node with no buffer space available. Stalled."); 3185 continue; 3186 } 3187 3188 /* 3189 * Actually process the node. 3190 */ 3191 backuppc_process_client(curnode); 3192 3193 /* 3194 * If the processing indicates that the buffer 3195 * has invalid data in it, terminate the client 3196 * and ask for cleanup. 3197 */ 3198 if (curnode->invalid_data) { 3199 #ifdef HAVE_SYSLOG 3200 syslog(LOG_INFO, "Closing connection from %s for sending invalid data.", inet_ntoa(curnode->addr)); 3201 #endif 3202 net_close(curnode->fd); 3203 curnode->fd = -1; 3204 need_cleanup = 1; 3205 } 3206 } 3207 } 3208 } 3209 3210 if (master_fd >= 0) { 3211 net_close(master_fd); 3212 } 3213 3214 #ifdef _USE_WIN32_ 3215 backuppcServiceStat.dwCurrentState = SERVICE_STOPPED; 3216 backuppcServiceStat.dwWaitHint = 0; 3217 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat); 3218 #endif 3219 3220 WorkLoopStatus = LOOP_DONE; 3221 3222 return(EXIT_SUCCESS); 3223 } 3224 3225 #ifdef _USE_WIN32_ 3226 /* 3227 * SYNOPSIS: 3228 * VOID WINAPI backuppcServiceControl( 3229 * DWORD request 3230 * ); 3231 * 3232 * ARGUMENTS: 3233 * DWORD request Action that is requested, only SERVICE_CONTROL_STOP 3234 * and SERVICE_CONTROL_SHUTDOWN are acceptable. 3235 * 3236 * RETURN VALUE: 3237 * (none) 3238 * 3239 * NOTES: 3240 * This function should be run in the same process as the primary worker 3241 * loop (backuppc_loop()). It will set the Win32 service status 3242 * when asked to STOP (or SHUTDOWN). It asks the main worker loop to 3243 * terminate, which can take up to 10s (10000ms). When it is called and 3244 * the worker thread has finished (i.e., set WorkLoopStatus to LOOP_DONE) 3245 * it exits as well. 3246 * 3247 */ 3248 VOID WINAPI backuppcServiceControl(DWORD request) { 3249 /* We only handle the `STOP' and `SHUTDOWN' requests. */ 3250 if (request != SERVICE_CONTROL_STOP && request != SERVICE_CONTROL_SHUTDOWN) { 3251 return; 3252 } 3253 3254 /* Figure out what we're doing. */ 3255 switch (WorkLoopStatus) { 3256 case LOOP_RUN: 3257 case LOOP_STOP: 3258 /* If the loop is running, ask it to stop. */ 3259 WorkLoopStatus = LOOP_STOP; 3260 3261 /* Tell WIn32 that we're going peacfully. */ 3262 backuppcServiceStat.dwCurrentState = SERVICE_STOP_PENDING; 3263 backuppcServiceStat.dwWaitHint = 10000; 3264 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat); 3265 break; 3266 case LOOP_DONE: 3267 /* The loop has finished and we can go away now. */ 3268 backuppcServiceStat.dwCurrentState = SERVICE_STOPPED; 3269 backuppcServiceStat.dwWaitHint = 0; 3270 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat); 3271 3272 exit(EXIT_SUCCESS); 3273 3274 break; 3275 } 3276 3277 return; 3278 } 3279 3280 /* 3281 * SYNOPSIS: 3282 * void WINAPI backuppcServiceStart( 3283 * DWORD argc 3284 * LPTSTR *argv 3285 * ); 3286 * ARGUMENTS: 3287 * DWORD argc Number of arguments 3288 * LPTSTR *argv Argument data 3289 * 3290 * RETURN VALUE: 3291 * (none) 3292 * 3293 * NOTES: 3294 * This function is called by `StartServiceCtrlDispatcher'. It registers 3295 * the service and updates its status information before and after calling 3296 * the main worker loop (backuppc_loop()). 3297 * 3298 */ 3299 void WINAPI backuppcServiceStart(DWORD argc, LPTSTR *argv) { 3300 backuppcServiceStat.dwServiceType = SERVICE_WIN32; 3301 backuppcServiceStat.dwCurrentState = SERVICE_START_PENDING; 3302 backuppcServiceStat.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; 3303 backuppcServiceStat.dwWin32ExitCode = 0; 3304 backuppcServiceStat.dwServiceSpecificExitCode = 0; 3305 backuppcServiceStat.dwCheckPoint = 0; 3306 backuppcServiceStat.dwWaitHint = 0; 3307 3308 backuppcServiceStat_handle = RegisterServiceCtrlHandler(svcName, backuppcServiceControl); 3309 3310 if (backuppcServiceStat_handle == (SERVICE_STATUS_HANDLE) 0) { 3311 fprintf(stderr, "Could not register service: %i\n", (int) GetLastError()); 3312 return; 3313 } 3314 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat); 3315 3316 backuppcServiceStat.dwCurrentState = SERVICE_RUNNING; 3317 backuppcServiceStat.dwCheckPoint = 0; 3318 backuppcServiceStat.dwWaitHint = 0; 3319 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat); 3320 3321 backuppc_loop(argc, argv); 3322 3323 backuppcServiceStat.dwCurrentState = SERVICE_STOPPED; 3324 backuppcServiceStat.dwCheckPoint = 0; 3325 backuppcServiceStat.dwWaitHint = 0; 3326 SetServiceStatus(backuppcServiceStat_handle, &backuppcServiceStat); 3327 3328 return; 3329 } 3330 #endif /* _USE_WIN32_ */ 3331 3332 /* 3333 * SYNOPSIS: 3334 * static int daemon_init(void); 3335 * 3336 * ARGUMENTS: 3337 * (none) 3338 * 3339 * RETURN VALUE: 3340 * This function returns `DAEMON_RET_FAILURE' or `DAEMON_RET_SUCCESS'. 3341 * If it was able to successfully launch as its own set of processes 3342 * SUCCESS is returned, otherwise FAILURE is returned. 3343 * 3344 * NOTES: 3345 * This is the primary daemonizing routine. Under win32 it creates a 3346 * service (svcName) and sets its initialization function to the 3347 * service start function (backuppcServiceStart). 3348 * 3349 */ 3350 static int daemon_init(void) { 3351 /* Default return value is failure, indicating that caller should 3352 continue on. */ 3353 int retval = DAEMON_RET_FAILURE; 3354 #ifndef _USE_WIN32_ 3355 #ifdef HAVE_FORK 3356 FILE *pidfile_fp = NULL; 3357 pid_t pid; 3358 3359 unlink(SKIPSTARTFILE); 3360 3361 close(STDIN_FILENO); 3362 close(STDOUT_FILENO); 3363 close(STDERR_FILENO); 3364 3365 #ifdef HAVE_SETSID 3366 setsid(); 3367 #endif 3368 3369 pid = fork(); 3370 3371 if (pid > 0) { 3372 /* Write the child PID to a file so we can read it to 3373 shutdown. */ 3374 pidfile_fp = fopen(BACKUPPC_PIDFILE, "w"); 3375 if (pidfile_fp != NULL) { 3376 fprintf(pidfile_fp, "%li\n", (long) pid); 3377 fclose(pidfile_fp); 3378 } 3379 3380 /* Tell the parent process that we have created children, indicating that 3381 it should terminate. */ 3382 return(DAEMON_RET_SUCCESS); 3383 } 3384 3385 if (pid < 0) { 3386 /* On a fork error, terminate everyone immediately. */ 3387 exit(EXIT_FAILURE); 3388 } 3389 3390 /* The child returns FAILURE to indicate that it should not terminate, but 3391 rather carry on processing. */ 3392 3393 retval = DAEMON_RET_FAILURE; 3394 #endif 3395 #else 3396 DWORD win32Error; 3397 SERVICE_TABLE_ENTRY serviceTable[] = { 3398 {svcName, backuppcServiceStart}, 3399 { NULL, NULL} 3400 }; 3401 3402 if (!StartServiceCtrlDispatcher(serviceTable)) { 3403 win32Error = GetLastError(); 3404 switch (win32Error) { 3405 case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: 3406 /* Print no error here because we're not being 3407 run as a service yet. This will happen 3408 later. CreateService() will cause a new 3409 process to be created where this will 3410 succeed. */ 3411 break; 3412 default: 3413 fprintf(stderr, "Could not start service dispatcher: %i\n", (int) win32Error); 3414 break; 3415 } 3416 } else { 3417 /* We were able to start the "Control Dispatcher" so we 3418 indicate success. This should tell the caller to 3419 terminate since we'll be starting our own set of 3420 processes. */ 3421 retval = DAEMON_RET_SUCCESS; 3422 } 3423 #endif 3424 return(retval); 3425 } 3426 3427 /* 3428 * SYNOPSIS: 3429 * static int daemon_stop(void); 3430 * 3431 * ARGUMENTS: 3432 * (none) 3433 * 3434 * RETURN VALUE: 3435 * Upon sucessfully stopping the running daemon, 0 is returned. Otherwise 3436 * -1 is returned. 3437 * 3438 * NOTES: 3439 * This function uses the Service Control functions on Win32. 3440 * This function uses a pid file (BACKUPPC_PIDFILE) on POSIX platforms. 3441 * 3442 */ 3443 static int daemon_stop(void) { 3444 int retval = -1; 3445 #ifndef _USE_WIN32_ 3446 FILE *pidfile_fp = NULL; 3447 char buf[128]; 3448 pid_t pid; 3449 int killret, unlinkret; 3450 3451 pidfile_fp = fopen(BACKUPPC_PIDFILE, "r"); 3452 if (pidfile_fp == NULL) { 3453 fprintf(stderr, "Service is not running.\n"); 3454 return(-1); 3455 } 3456 3457 fgets(buf, sizeof(buf), pidfile_fp); 3458 pid = strtol(buf, NULL, 10); 3459 3460 if (pid <= 0) { 3461 fprintf(stderr, "Invalid process ID: %li\n", (long) pid); 3462 return(-1); 3463 } 3464 3465 unlinkret = unlink(BACKUPPC_PIDFILE); 3466 if (unlinkret < 0) { 3467 fprintf(stderr, "Error removing pid file (\"%s\"): ", BACKUPPC_PIDFILE); 3468 perror("unlink"); 3469 } 3470 3471 killret = kill(pid, 1); 3472 if (killret < 0) { 3473 perror("kill"); 3474 return(-1); 3475 } 3476 3477 #ifdef HAVE_SYSLOG 3478 syslog(LOG_INFO, "Terminating running backuppcd (pid = %lu)", (unsigned long) pid); 3479 #endif 3480 3481 retval = 0; 3482 #else 3483 /* Open a connection to the SCM if there isn't one already. */ 3484 if (manager == NULL) { 3485 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 3486 if (manager == NULL) { 3487 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError()); 3488 return(-1); 3489 } 3490 } 3491 3492 /* Connect to our service. */ 3493 service = OpenService(manager, svcName, SERVICE_ALL_ACCESS); 3494 if (service == NULL) { 3495 fprintf(stderr, "Could not open service: %i\n", (int) GetLastError()); 3496 return(-1); 3497 } 3498 3499 /* Ask ourselves to stop through the SCM. */ 3500 if (!ControlService(service, SERVICE_CONTROL_STOP, &backuppcServiceStat)) { 3501 if (GetLastError() != ERROR_SERVICE_NOT_ACTIVE) { 3502 fprintf(stderr, "Could not stop service: %i\n", (int) GetLastError()); 3503 return(-1); 3504 } 3505 } 3506 3507 fprintf(stderr, "Service stopped.\n"); 3508 3509 retval = 0; 3510 #endif 3511 return(retval); 3512 } 3513 3514 /* 3515 * SYNOPSIS: 3516 * static int daemon_remove(void); 3517 * 3518 * ARGUMENTS: 3519 * (none) 3520 * 3521 * RETURN VALUE: 3522 * Upon sucessfully removing the (possibly running) daemon from startup, 0 3523 * is returned. Otherwise -1 is returned. 3524 * 3525 * NOTES: 3526 * On win32 this does the services thing. 3527 * 3528 * Otherwise, it cooperates with the supplied "backuppc.init" script to 3529 * manage the SKIPSTARTFILE. If this file exists, the "backuppc.init" 3530 * script's start action aborts. backuppcd deletes the file upon sucessful 3531 * startup. This function creates the file and stops the running daemon. 3532 * 3533 */ 3534 static int daemon_remove(void) { 3535 int retval = -1; 3536 int stop_ret; 3537 3538 stop_ret = daemon_stop(); 3539 3540 if (stop_ret < 0) { 3541 retval = -1; 3542 } 3543 3544 #ifndef _USE_WIN32_ 3545 creat(SKIPSTARTFILE, 0600); 3546 retval = 0; 3547 #else 3548 if (manager == NULL) { 3549 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 3550 if (manager == NULL) { 3551 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError()); 3552 return(-1); 3553 } 3554 } 3555 3556 service = OpenService(manager, svcName, SERVICE_ALL_ACCESS); 3557 if (service == NULL) { 3558 fprintf(stderr, "Could not open service: %i\n", (int) GetLastError()); 3559 return(-1); 3560 } 3561 3562 if (!DeleteService(service)) { 3563 fprintf(stderr, "Could not delete service: %i\n", (int) GetLastError()); 3564 return(-1); 3565 } 3566 3567 fprintf(stderr, "Service deleted.\n"); 3568 3569 retval = 0; 3570 #endif 3571 return(retval); 3572 } 3573 3574 /* 3575 * SYNOPSIS: 3576 * static void daemon_start( 3577 * int argc, 3578 * char **argv 3579 * ); 3580 * 3581 * ARGUMENTS: 3582 * int argc Number of arguments 3583 * char *argv Argument data 3584 * 3585 * RETURN VALUE: 3586 * (none) 3587 * 3588 * NOTES: 3589 * 3590 */ 3591 static void daemon_start(int argc, char **argv) { 3592 #ifdef _USE_WIN32_ 3593 /* Create a Win32 Service. */ 3594 /* Most of this was taken from "tinc" (src/process.c) */ 3595 #ifdef NO_WIN32_NT4 3596 /* Windows NT 4.0 lacks the `ChangeServiceConfig2' call. */ 3597 SERVICE_DESCRIPTION description = {"BackupPC Client Daemon"}; 3598 #endif 3599 char svcCommand[8192], *svcptr; 3600 int argind; 3601 3602 /* 3603 * This whole mess is to construct the "lpBinaryPathName" which needs 3604 * quotes and all kinds of other non-sense. 3605 */ 3606 svcptr = svcCommand; 3607 3608 strcpy(svcptr, "\""); 3609 svcptr += strlen(svcptr); /* This is not the same as svcptr++. */ 3610 3611 /* If the full path wasn't specified, assume it's in the current directory. */ 3612 if (strchr(argv[0], '\\') == NULL) { 3613 GetCurrentDirectory(sizeof(svcCommand) - (svcptr - svcCommand) - 1, svcptr); 3614 svcptr += strlen(svcptr); 3615 strncat(svcptr, "\\", sizeof(svcCommand) - (svcptr - svcCommand) - 1); 3616 svcptr += strlen(svcptr); 3617 } 3618 strncat(svcptr, argv[0], sizeof(svcCommand) - (svcptr - svcCommand) - 1); 3619 svcptr += strlen(svcptr); 3620 strncat(svcptr, "\"", sizeof(svcCommand) - (svcptr - svcCommand) - 1); 3621 svcptr += strlen(svcptr); 3622 3623 for (argind = 1; argind < argc; argind++) { 3624 strncat(svcptr, " \"", sizeof(svcCommand) - (svcptr - svcCommand) - 1); 3625 svcptr += strlen(svcptr); 3626 3627 strncat(svcptr, argv[argind], sizeof(svcCommand) - (svcptr - svcCommand) - 1); 3628 svcptr += strlen(svcptr); 3629 3630 strncat(svcptr, "\"", sizeof(svcCommand) - (svcptr - svcCommand) - 1); 3631 svcptr += strlen(svcptr); 3632 } 3633 3634 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 3635 if (manager == NULL) { 3636 fprintf(stderr, "Could not contact service manager: %i\n", (int) GetLastError()); 3637 exit(EXIT_FAILURE); 3638 } 3639 3640 /* 3641 * This will ultimately spawn another set of processes so we may exit. 3642 */ 3643 service = CreateService(manager, svcName, svcName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcCommand, "NDIS", NULL, NULL, NULL, NULL); 3644 3645 if (service == NULL) { 3646 if (GetLastError() == ERROR_SERVICE_EXISTS) { 3647 service = OpenService(manager, svcName, SERVICE_ALL_ACCESS); 3648 } 3649 3650 if (service == NULL) { 3651 fprintf(stderr, "Could not create service: %i\n", (int) GetLastError()); 3652 exit(EXIT_FAILURE); 3653 } 3654 } 3655 3656 #ifdef NO_WIN32_NT4 3657 /* Windows NT 4.0 lacks this call. */ 3658 ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description); 3659 #endif 3660 3661 if (!StartService(service, 0, NULL)) { 3662 fprintf(stderr, "Could not start service: %i\n", (int) GetLastError()); 3663 exit(EXIT_FAILURE); 3664 } else { 3665 printf("Service started.\n"); 3666 } 3667 3668 3669 exit(EXIT_SUCCESS); 3670 #endif 3671 return; 3672 } 3673 3674 /* 3675 * SYNOPSIS: 3676 * static void backuppc_pathmangle( 3677 * char *pathname 3678 * ); 3679 * 3680 * ARGUMENTS: 3681 * char *pathname Pathname to mangle. 3682 * 3683 * RETURN VALUE: 3684 * (none) 3685 * 3686 * NOTES: 3687 * 3688 */ 3689 static int backuppc_opt_remove_svc(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra) { 3690 if (daemon_remove() < 0) { 3691 exit(EXIT_FAILURE); 3692 } 3693 3694 exit(EXIT_SUCCESS); 3695 } 3696 3697 /* 3698 * SYNOPSIS: 3699 * static void backuppc_pathmangle( 3700 * char *pathname 3701 * ) 3702 * 3703 * ARGUMENTS: 3704 * char *pathname Pathname to mangle. 3705 * 3706 * RETURN VALUE: 3707 * (none) 3708 * 3709 * NOTES: 3710 * 3711 */ 3712 static int backuppc_opt_stop_svc(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra) { 3713 if (daemon_stop() < 0) { 3714 exit(EXIT_FAILURE); 3715 } 3716 3717 exit(EXIT_SUCCESS); 3718 } 3719 3720 static int backuppc_opt_showvers(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra) { 3721 printf("%s\n", PACKAGE_VERSION); 3722 exit(EXIT_SUCCESS); 3723 } 3724 3725 static int backuppc_opt_prio(const char *shortvar, const char *var, const char *arguments, const char *value, lc_flags_t flags, void *extra) { 3726 char *prio_names[3] = {"min", "max", "normal"}; 3727 int prio_vals[3] = {BPC_PRIO_MIN, BPC_PRIO_MAX, BPC_PRIO_NORM}; 3728 int prio_val = -1; 3729 int i; 3730 3731 if (!value) { 3732 return(LC_CBRET_ERROR); 3733 } 3734 3735 if (strlen(value) > 0) { 3736 for (i = 0; i < (sizeof(prio_names) / sizeof(*prio_names)); i++) { 3737 if (strncasecmp(prio_names[i], value, strlen(value)) == 0) { 3738 if (prio_val == -1) { 3739 prio_val = prio_vals[i]; 3740 } else { 3741 fprintf(stderr, "Ambigious priority name: %s, should be Min, Max, or Normal.\n", value); 3742 return(LC_CBRET_ERROR); 3743 } 3744 } 3745 } 3746 } 3747 3748 if (prio_val == -1) { 3749 fprintf(stderr, "Invalid priority name: %s, should be Min, Max, or Normal.\n", value); 3750 return(LC_CBRET_ERROR); 3751 } 3752 3753 backuppc_setpriority(prio_val); 3754 3755 return(LC_CBRET_OKAY); 3756 } 3757 3758 /* 3759 * SYNOPSIS: 3760 * static void backuppc_pathmangle( 3761 * char *pathname 3762 * ) 3763 * 3764 * ARGUMENTS: 3765 * char *pathname Pathname to mangle. 3766 * 3767 * RETURN VALUE: 3768 * (none) 3769 * 3770 * NOTES: 3771 * 3772 */ 3773 int main(int argc, char *argv[]) { 3774 int lc_p_ret = 0; 3775 char *update_source = NULL, *update_dest = NULL, *update_delefile = NULL; 3776 char *config_file = NULL; 3777 int do_switch = 0; 3778 3779 /* 3780 * Initialize the authentication subsystem. 3781 * 3782 * It will add its own set of options to the configuration processor 3783 */ 3784 bpcd_auth_init(); 3785 3786 /* 3787 * Register configuration commands and command line arguments. 3788 */ 3789 lc_register_callback("Remove", 'r', LC_VAR_NONE, backuppc_opt_remove_svc, NULL); 3790 lc_register_callback("Stop", 'k', LC_VAR_NONE, backuppc_opt_stop_svc, NULL); 3791 lc_register_callback("Version", 'V', LC_VAR_NONE, backuppc_opt_showvers, NULL); 3792 lc_register_callback("Priority", 'P', LC_VAR_STRING, backuppc_opt_prio, NULL); 3793 lc_register_var("Port", LC_VAR_INT, &backuppc_port, 'p'); 3794 lc_register_var("UpdateURL", LC_VAR_STRING, &backuppc_updateurl, 'U'); 3795 lc_register_var("Source", LC_VAR_STRING, &update_source, 0); 3796 lc_register_var("Destination", LC_VAR_STRING, &update_dest, 0); 3797 lc_register_var("Switch", LC_VAR_BOOL_BY_EXISTANCE, &do_switch, 0); 3798 lc_register_var("DeleteFile", LC_VAR_STRING, &update_delefile, 0); 3799 lc_register_var("BinaryFile", LC_VAR_STRING, &backuppc_binfile, 0); 3800 lc_register_var("ConfigFile", LC_VAR_STRING, &config_file, 'C'); 3801 3802 /* 3803 * Process standard config files, command line arguments, and 3804 * environment variables. 3805 */ 3806 lc_p_ret = lc_process(argc, argv, "backuppcd", LC_CONF_SPACE, SYSCONFDIR "/backuppcd.conf"); 3807 if (lc_p_ret < 0) { 3808 fprintf(stderr, "Error processing configuration information: %s.\n", lc_geterrstr()); 3809 return(EXIT_FAILURE); 3810 } 3811 3812 /* 3813 * If an alternative config file is specified above, process it. 3814 */ 3815 if (config_file) { 3816 lc_p_ret = lc_process_file("backuppcd", config_file, LC_CONF_SPACE); 3817 3818 if (lc_p_ret < 0) { 3819 fprintf(stderr, "Error processing configuration information: %s.\n", lc_geterrstr()); 3820 return(EXIT_FAILURE); 3821 } 3822 } 3823 3824 /* 3825 * Finished with configuration. 3826 */ 3827 lc_cleanup(); 3828 3829 /* 3830 * If we've been told to delete a file, do so without regard for 3831 * failure. 3832 */ 3833 if (update_delefile) { 3834 unlink(update_delefile); 3835 } 3836 3837 /* 3838 * Since you can never open a running executable for writing so to 3839 * upgrade ourselves we must: 3840 * a. Download the new version to some temporary location 3841 * b. Call the new version and tell it to replace the old version 3842 * with itself (--Switch argument) 3843 * c. Call the copy 3844 * d. Delete the file from the temporary location 3845 */ 3846 if (do_switch) { 3847 if (update_source == NULL || update_dest == NULL) { 3848 fprintf(stderr, "Error: You must provide a --Source and --Destination to use --Switch\n"); 3849 return(EXIT_FAILURE); 3850 } 3851 3852 backuppc_switchupdate(update_source, update_dest, argc, argv); 3853 3854 return(EXIT_SUCCESS); 3855 } 3856 3857 #ifndef _USE_WIN32_ 3858 /* 3859 * We cannot check for a new version at start-up on Windows because it 3860 * really messes with the "Services" stuff. Bummer, man. 3861 */ 3862 if (backuppc_updateurl) { 3863 backuppc_update(backuppc_updateurl, argc, argv); 3864 } 3865 #endif 3866 3867 #ifndef DEBUG 3868 /* 3869 * If daemon initialization went well, we're no longer needed. 3870 */ 3871 if (daemon_init() == DAEMON_RET_SUCCESS) { 3872 return(EXIT_SUCCESS); 3873 } 3874 3875 daemon_start(argc, argv); 3876 #endif 3877 3878 #ifdef HAVE_SIGNAL 3879 /* 3880 * We don't care about SIGPIPE, we properly handle read errors. 3881 */ 3882 signal(SIGPIPE, SIG_IGN); 3883 #endif 3884 3885 /* 3886 * This will be replaced with a proper logging mechanism at some point (XXX) 3887 */ 3888 #ifdef HAVE_OPENLOG 3889 openlog("backuppcd", LOG_PID, LOG_DAEMON); 3890 #endif 3891 3892 /* 3893 * Begin primary processing. 3894 */ 3895 return(backuppc_loop(argc, argv)); 3896 } |