int extra_comms(struct async *as, char **incexc, int *srestore, struct conf **confs, struct conf **cconfs) { struct vers vers; struct asfd *asfd; asfd=as->asfd; //char *restorepath=NULL; const char *peer_version=NULL; if(vers_init(&vers, cconfs)) goto error; if(vers.cli<vers.directory_tree) { set_int(confs[OPT_DIRECTORY_TREE], 0); set_int(cconfs[OPT_DIRECTORY_TREE], 0); } // Clients before 1.2.7 did not know how to do extra comms, so skip // this section for them. if(vers.cli<vers.min) return 0; if(asfd->read_expect(asfd, CMD_GEN, "extra_comms_begin")) { logp("problem reading in extra_comms\n"); goto error; } // Want to tell the clients the extra comms features that are // supported, so that new clients are more likely to work with old // servers. if(vers.cli==vers.feat_list) { // 1.3.0 did not support the feature list. if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin ok")) { logp("problem writing in extra_comms\n"); goto error; } } else { if(send_features(asfd, cconfs)) goto error; } if(extra_comms_read(as, &vers, srestore, incexc, confs, cconfs)) goto error; peer_version=get_string(cconfs[OPT_PEER_VERSION]); // This needs to come after extra_comms_read, as the client might // have set PROTO_1 or PROTO_2. switch(get_e_protocol(cconfs[OPT_PROTOCOL])) { case PROTO_AUTO: // The protocol has not been specified. Make a choice. if(vers.cli<vers.burp2) { // Client is burp-1.x.x, use protocol1. set_e_protocol(confs[OPT_PROTOCOL], PROTO_1); set_e_protocol(cconfs[OPT_PROTOCOL], PROTO_1); logp("Client is burp-%s - using protocol=%d\n", peer_version, PROTO_1); } else { // Client is burp-2.x.x, use protocol2. // This will probably never be reached because // the negotiation will take care of it. set_e_protocol(confs[OPT_PROTOCOL], PROTO_2); set_e_protocol(cconfs[OPT_PROTOCOL], PROTO_2); logp("Client is burp-%s - using protocol=%d\n", peer_version, PROTO_2); } break; case PROTO_1: // It is OK for the client to be burp1 and for the // server to be forced to protocol1. break; case PROTO_2: if(vers.cli>=vers.burp2) break; logp("protocol=%d is set server side, " "but client is burp version %s\n", peer_version); goto error; } if(get_e_protocol(cconfs[OPT_PROTOCOL])==PROTO_1) { if(get_e_rshash(cconfs[OPT_RSHASH])==RSHASH_UNSET) { set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4); set_e_rshash(cconfs[OPT_RSHASH], RSHASH_MD4); } } return 0; error: return -1; }
static int send_features(struct asfd *asfd, struct conf **cconfs) { int ret=-1; char *feat=NULL; struct stat statp; const char *restorepath=NULL; enum protocol protocol=get_e_protocol(cconfs[OPT_PROTOCOL]); struct strlist *startdir=get_strlist(cconfs[OPT_STARTDIR]); struct strlist *incglob=get_strlist(cconfs[OPT_INCGLOB]); if(append_to_feat(&feat, "extra_comms_begin ok:") /* clients can autoupgrade */ || append_to_feat(&feat, "autoupgrade:") /* clients can give server incexc conf so that the server knows better what to do on resume */ || append_to_feat(&feat, "incexc:") /* clients can give the server an alternative client to restore from */ || append_to_feat(&feat, "orig_client:") /* clients can tell the server what kind of system they are. */ || append_to_feat(&feat, "uname:")) goto end; /* Clients can receive restore initiated from the server. */ if(!(restorepath=get_restorepath(cconfs)) || set_string(cconfs[OPT_RESTORE_PATH], restorepath)) goto end; if(!lstat(restorepath, &statp) && S_ISREG(statp.st_mode) && append_to_feat(&feat, "srestore:")) goto end; /* Clients can receive incexc conf from the server. Only give it as an option if the server has some starting directory configured in the clientconfdir. */ if((startdir || incglob) && append_to_feat(&feat, "sincexc:")) goto end; /* Clients can be sent cntrs on resume/verify/restore. */ /* FIX THIS: Disabled until I rewrite a better protocol. if(append_to_feat(&feat, "counters:")) goto end; */ // We support CMD_MESSAGE. if(append_to_feat(&feat, "msg:")) goto end; if(protocol==PROTO_AUTO) { /* If the server is configured to use either protocol, let the client know that it can choose. */ logp("Server is using protocol=0 (auto)\n"); if(append_to_feat(&feat, "csetproto:")) goto end; } else { char p[32]=""; /* Tell the client what we are going to use. */ logp("Server is using protocol=%d\n", (int)protocol); snprintf(p, sizeof(p), "forceproto=%d:", (int)protocol); if(append_to_feat(&feat, p)) goto end; } #ifndef RS_DEFAULT_STRONG_LEN if(append_to_feat(&feat, "rshash=blake2:")) goto end; #endif //printf("feat: %s\n", feat); if(asfd->write_str(asfd, CMD_GEN, feat)) { logp("problem in extra_comms\n"); goto end; } ret=0; end: if(feat) free(feat); return ret; }
static int extra_comms_read(struct async *as, struct vers *vers, int *srestore, char **incexc, struct conf **globalcs, struct conf **cconfs) { int ret=-1; struct asfd *asfd; struct iobuf *rbuf; asfd=as->asfd; rbuf=asfd->rbuf; while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; if(rbuf->cmd!=CMD_GEN) { iobuf_log_unexpected(rbuf, __func__); goto end; } if(!strcmp(rbuf->buf, "extra_comms_end")) { if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end ok")) goto end; break; } else if(!strncmp_w(rbuf->buf, "autoupgrade:")) { char *os=NULL; os=rbuf->buf+strlen("autoupgrade:"); iobuf_free_content(rbuf); if(os && *os && autoupgrade_server(as, vers->ser, vers->cli, os, globalcs)) goto end; } else if(!strcmp(rbuf->buf, "srestore ok")) { iobuf_free_content(rbuf); // Client can accept the restore. // Load the restore config, then send it. *srestore=1; if(conf_parse_incexcs_path(cconfs, get_string(cconfs[OPT_RESTORE_PATH])) || incexc_send_server_restore(asfd, cconfs)) goto end; // Do not unlink it here - wait until // the client says that it wants to do the // restore. // Also need to leave it around if the // restore is to an alternative client, so // that the code below that reloads the config // can read it again. //unlink(get_string(cconfs[OPT_RESTORE_PATH])); } else if(!strcmp(rbuf->buf, "srestore not ok")) { const char *restore_path=get_string( cconfs[OPT_RESTORE_PATH]); // Client will not accept the restore. unlink(restore_path); if(set_string(cconfs[OPT_RESTORE_PATH], NULL)) goto end; logp("Client not accepting server initiated restore.\n"); } else if(!strcmp(rbuf->buf, "sincexc ok")) { // Client can accept incexc conf from the // server. iobuf_free_content(rbuf); if(incexc_send_server(asfd, cconfs)) goto end; } else if(!strcmp(rbuf->buf, "incexc")) { // Client is telling server its incexc // configuration so that it can better decide // what to do on resume. iobuf_free_content(rbuf); if(incexc_recv_server(asfd, incexc, globalcs)) goto end; if(*incexc) { char *tmp=NULL; char comp[32]=""; snprintf(comp, sizeof(comp), "compression = %d\n", get_int(cconfs[OPT_COMPRESSION])); if(!(tmp=prepend(*incexc, comp))) goto end; free_w(incexc); *incexc=tmp; } } else if(!strcmp(rbuf->buf, "countersok")) { // Client can accept counters on // resume/verify/restore. logp("Client supports being sent counters.\n"); set_int(cconfs[OPT_SEND_CLIENT_CNTR], 1); } else if(!strncmp_w(rbuf->buf, "uname=") && strlen(rbuf->buf)>strlen("uname=")) { char *uname=rbuf->buf+strlen("uname="); if(!strncasecmp("Windows", uname, strlen("Windows"))) set_int(cconfs[OPT_CLIENT_IS_WINDOWS], 1); } else if(!strncmp_w(rbuf->buf, "orig_client=") && strlen(rbuf->buf)>strlen("orig_client=")) { if(conf_switch_to_orig_client(globalcs, cconfs, rbuf->buf+strlen("orig_client="))) goto end; // If this started out as a server-initiated // restore, need to load the restore file // again. if(*srestore) { if(conf_parse_incexcs_path(cconfs, get_string(cconfs[OPT_RESTORE_PATH]))) goto end; } if(asfd->write_str(asfd, CMD_GEN, "orig_client ok")) goto end; } else if(!strncmp_w(rbuf->buf, "restore_spool=")) { // Client supports temporary spool directory // for restores. if(set_string(cconfs[OPT_RESTORE_SPOOL], rbuf->buf+strlen("restore_spool="))) goto end; } else if(!strncmp_w(rbuf->buf, "protocol=")) { char msg[128]=""; // Client wants to set protocol. enum protocol protocol=get_e_protocol( cconfs[OPT_PROTOCOL]); if(protocol!=PROTO_AUTO) { snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s but server is set to protocol=%d\n", rbuf->buf, protocol); log_and_send_oom(asfd, __func__); goto end; } else if(!strcmp(rbuf->buf+strlen("protocol="), "1")) { set_e_protocol(cconfs[OPT_PROTOCOL], PROTO_1); set_e_protocol(globalcs[OPT_PROTOCOL], PROTO_1); } else if(!strcmp(rbuf->buf+strlen("protocol="), "2")) { set_e_protocol(cconfs[OPT_PROTOCOL], PROTO_2); set_e_protocol(globalcs[OPT_PROTOCOL], PROTO_2); } else { snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s, which is unknown\n", rbuf->buf); log_and_send_oom(asfd, __func__); goto end; } logp("Client has set protocol=%d\n", (int)get_e_protocol(cconfs[OPT_PROTOCOL])); } else if(!strncmp_w(rbuf->buf, "rshash=blake2")) { #ifdef RS_DEFAULT_STRONG_LEN logp("Client is trying to use librsync hash blake2, but server does not support it.\n"); goto end; #else set_e_rshash(cconfs[OPT_RSHASH], RSHASH_BLAKE2); set_e_rshash(globalcs[OPT_RSHASH], RSHASH_BLAKE2); #endif } else if(!strncmp_w(rbuf->buf, "msg")) { set_int(cconfs[OPT_MESSAGE], 1); set_int(globalcs[OPT_MESSAGE], 1); } else { iobuf_log_unexpected(rbuf, __func__); goto end; } } ret=0; end: iobuf_free_content(rbuf); return ret; }
// Return 0 for OK, -1 for error. int do_backup_client(struct asfd *asfd, struct conf **confs, enum action action, int resume) { int ret=-1; if(action==ACTION_ESTIMATE) logp("do estimate client\n"); else { logp("do backup client\n"); if(get_e_protocol(confs[OPT_PROTOCOL])==PROTO_1) logp("Using librsync hash %s\n", rshash_to_str(get_e_rshash(confs[OPT_RSHASH]))); } #ifdef HAVE_WIN32 win32_enable_backup_privileges(); #ifdef WIN32_VSS if(win32_start_vss(confs)) return ret; #endif if(action==ACTION_BACKUP_TIMED) set_low_priority(); #endif // Scan the file system and send the results to the server. // Skip phase1 if the server wanted to resume. if(!resume) { if(get_int(confs[OPT_BREAKPOINT])==1) { breakpoint(confs, __func__); goto end; } if(backup_phase1_client(asfd, confs, action==ACTION_ESTIMATE)) goto end; } switch(action) { case ACTION_DIFF: case ACTION_DIFF_LONG: ret=1; goto end; case ACTION_ESTIMATE: cntr_print(get_cntr(confs[OPT_CNTR]), ACTION_ESTIMATE); break; default: // Now, the server will be telling us what data we need // to send. if(get_int(confs[OPT_BREAKPOINT])==2) { breakpoint(confs, __func__); goto end; } if(get_e_protocol(confs[OPT_PROTOCOL])==PROTO_1) ret=backup_phase2_client_protocol1(asfd, confs, resume); else ret=backup_phase2_client_protocol2(asfd, confs, resume); if(ret) goto end; break; } ret=0; end: #if defined(HAVE_WIN32) if(action==ACTION_BACKUP_TIMED) unset_low_priority(); #if defined(WIN32_VSS) win32_stop_vss(); #endif #endif return ret; }
static void check_default(struct conf **c, enum conf_opt o) { switch(o) { case OPT_BURP_MODE: fail_unless(get_e_burp_mode(c[o])==BURP_MODE_UNSET); break; case OPT_LOCKFILE: case OPT_PIDFILE: case OPT_ADDRESS: case OPT_PORT: case OPT_STATUS_ADDRESS: case OPT_STATUS_PORT: case OPT_SSL_CERT_CA: case OPT_SSL_CERT: case OPT_SSL_KEY: case OPT_SSL_KEY_PASSWORD: case OPT_SSL_PEER_CN: case OPT_SSL_CIPHERS: case OPT_SSL_DHFILE: case OPT_CA_CONF: case OPT_CA_NAME: case OPT_CA_SERVER_NAME: case OPT_CA_BURP_CA: case OPT_CA_CSR_DIR: case OPT_PEER_VERSION: case OPT_CLIENT_LOCKDIR: case OPT_MONITOR_LOGFILE: case OPT_CNAME: case OPT_PASSWORD: case OPT_PASSWD: case OPT_SERVER: case OPT_ENCRYPTION_PASSWORD: case OPT_AUTOUPGRADE_OS: case OPT_AUTOUPGRADE_DIR: case OPT_BACKUP: case OPT_BACKUP2: case OPT_RESTOREPREFIX: case OPT_RESTORE_SPOOL: case OPT_BROWSEFILE: case OPT_BROWSEDIR: case OPT_B_SCRIPT_PRE: case OPT_B_SCRIPT_POST: case OPT_R_SCRIPT_PRE: case OPT_R_SCRIPT_POST: case OPT_B_SCRIPT: case OPT_R_SCRIPT: case OPT_RESTORE_PATH: case OPT_ORIG_CLIENT: case OPT_CONFFILE: case OPT_USER: case OPT_GROUP: case OPT_DIRECTORY: case OPT_TIMESTAMP_FORMAT: case OPT_CLIENTCONFDIR: case OPT_S_SCRIPT_PRE: case OPT_S_SCRIPT_POST: case OPT_MANUAL_DELETE: case OPT_S_SCRIPT: case OPT_TIMER_SCRIPT: case OPT_N_SUCCESS_SCRIPT: case OPT_N_FAILURE_SCRIPT: case OPT_DEDUP_GROUP: case OPT_VSS_DRIVES: case OPT_REGEX: case OPT_RESTORE_CLIENT: fail_unless(get_string(c[o])==NULL); break; case OPT_RATELIMIT: fail_unless(get_float(c[o])==0); break; case OPT_CLIENT_IS_WINDOWS: case OPT_RANDOMISE: case OPT_B_SCRIPT_POST_RUN_ON_FAIL: case OPT_R_SCRIPT_POST_RUN_ON_FAIL: case OPT_SEND_CLIENT_CNTR: case OPT_BREAKPOINT: case OPT_SYSLOG: case OPT_PROGRESS_COUNTER: case OPT_MONITOR_BROWSE_CACHE: case OPT_S_SCRIPT_PRE_NOTIFY: case OPT_S_SCRIPT_POST_RUN_ON_FAIL: case OPT_S_SCRIPT_POST_NOTIFY: case OPT_S_SCRIPT_NOTIFY: case OPT_HARDLINKED_ARCHIVE: case OPT_N_SUCCESS_WARNINGS_ONLY: case OPT_N_SUCCESS_CHANGES_ONLY: case OPT_CROSS_ALL_FILESYSTEMS: case OPT_READ_ALL_FIFOS: case OPT_READ_ALL_BLOCKDEVS: case OPT_SPLIT_VSS: case OPT_STRIP_VSS: case OPT_ATIME: case OPT_SCAN_PROBLEM_RAISES_ERROR: case OPT_OVERWRITE: case OPT_STRIP: case OPT_MESSAGE: fail_unless(get_int(c[o])==0); break; case OPT_DAEMON: case OPT_STDOUT: case OPT_FORK: case OPT_DIRECTORY_TREE: case OPT_PASSWORD_CHECK: case OPT_LIBRSYNC: case OPT_VERSION_WARN: case OPT_PATH_LENGTH_WARN: case OPT_CLIENT_CAN_DELETE: case OPT_CLIENT_CAN_DIFF: case OPT_CLIENT_CAN_FORCE_BACKUP: case OPT_CLIENT_CAN_LIST: case OPT_CLIENT_CAN_RESTORE: case OPT_CLIENT_CAN_VERIFY: case OPT_SERVER_CAN_RESTORE: case OPT_B_SCRIPT_RESERVED_ARGS: case OPT_R_SCRIPT_RESERVED_ARGS: case OPT_ACL: case OPT_XATTR: fail_unless(get_int(c[o])==1); break; case OPT_NETWORK_TIMEOUT: fail_unless(get_int(c[o])==60*60*2); break; case OPT_SSL_COMPRESSION: case OPT_MAX_CHILDREN: case OPT_MAX_STATUS_CHILDREN: fail_unless(get_int(c[o])==5); break; case OPT_COMPRESSION: fail_unless(get_int(c[o])==9); break; case OPT_MAX_STORAGE_SUBDIRS: fail_unless(get_int(c[o])==30000); break; case OPT_MAX_HARDLINKS: fail_unless(get_int(c[o])==10000); break; case OPT_UMASK: fail_unless(get_mode_t(c[o])==0022); break; case OPT_STARTDIR: case OPT_B_SCRIPT_PRE_ARG: case OPT_B_SCRIPT_POST_ARG: case OPT_R_SCRIPT_PRE_ARG: case OPT_R_SCRIPT_POST_ARG: case OPT_B_SCRIPT_ARG: case OPT_R_SCRIPT_ARG: case OPT_S_SCRIPT_PRE_ARG: case OPT_S_SCRIPT_POST_ARG: case OPT_S_SCRIPT_ARG: case OPT_TIMER_ARG: case OPT_N_SUCCESS_ARG: case OPT_N_FAILURE_ARG: case OPT_RESTORE_CLIENTS: case OPT_KEEP: case OPT_INCEXCDIR: case OPT_INCLUDE: case OPT_EXCLUDE: case OPT_FSCHGDIR: case OPT_NOBACKUP: case OPT_INCEXT: case OPT_EXCEXT: case OPT_INCREG: case OPT_EXCREG: case OPT_EXCFS: case OPT_EXCOM: case OPT_INCGLOB: case OPT_FIFOS: case OPT_BLOCKDEVS: fail_unless(get_strlist(c[o])==NULL); break; case OPT_PROTOCOL: fail_unless(get_e_protocol(c[o])==PROTO_AUTO); break; case OPT_HARD_QUOTA: case OPT_SOFT_QUOTA: case OPT_MIN_FILE_SIZE: case OPT_MAX_FILE_SIZE: fail_unless(get_uint64_t(c[o])==0); break; case OPT_WORKING_DIR_RECOVERY_METHOD: fail_unless(get_e_recovery_method(c[o])== RECOVERY_METHOD_DELETE); break; case OPT_RSHASH: fail_unless(get_e_rshash(c[o])==RSHASH_UNSET); break; case OPT_CNTR: fail_unless(get_cntr(c)==NULL); break; case OPT_MAX: break; // No default, so we get compiler warnings if something was // missed. } }
int do_restore_client(struct asfd *asfd, struct conf **confs, enum action act, int vss_restore) { int ret=-1; char msg[512]=""; struct sbuf *sb=NULL; struct blk *blk=NULL; BFILE *bfd=NULL; char *fullpath=NULL; char *style=NULL; char *datpath=NULL; enum protocol protocol=get_e_protocol(confs[OPT_PROTOCOL]); const char *backup=get_string(confs[OPT_BACKUP]); const char *regex=get_string(confs[OPT_REGEX]); if(!(bfd=bfile_alloc())) goto end; bfile_init(bfd, 0, confs); snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act), backup?backup:"", regex?regex:""); logp("doing %s\n", msg); if(asfd->write_str(asfd, CMD_GEN, msg) || asfd->read_expect(asfd, CMD_GEN, "ok")) goto error; logp("doing %s confirmed\n", act_str(act)); #if defined(HAVE_WIN32) if(act==ACTION_RESTORE) win32_enable_backup_privileges(); #endif if(!(style=get_restore_style(asfd, confs))) goto error; if(!strcmp(style, RESTORE_SPOOL)) { if(restore_spool(asfd, confs, &datpath)) goto error; } else logp("Streaming restore direct\n"); printf("\n"); // if(get_int(confs[OPT_SEND_CLIENT_CNTR]) && cntr_recv(confs)) // goto error; if(!(sb=sbuf_alloc(confs)) || (protocol==PROTO_2 && !(blk=blk_alloc()))) { log_and_send_oom(asfd, __func__); goto error; } while(1) { sbuf_free_content(sb); switch(sbuf_fill_w(sb, asfd, blk, datpath, confs)) { case 0: break; case 1: if(asfd->write_str(asfd, CMD_GEN, "restoreend_ok")) goto error; goto end; // It was OK. default: case -1: goto error; } if(protocol==PROTO_2 && blk->data) { int wret; if(act==ACTION_VERIFY) cntr_add(get_cntr(confs[OPT_CNTR]), CMD_DATA, 1); else wret=write_data(asfd, bfd, blk); if(!datpath) free(blk->data); blk->data=NULL; if(wret) goto error; continue; } switch(sb->path.cmd) { case CMD_DIRECTORY: case CMD_FILE: case CMD_ENC_FILE: case CMD_SOFT_LINK: case CMD_HARD_LINK: case CMD_SPECIAL: case CMD_METADATA: case CMD_ENC_METADATA: case CMD_VSS: case CMD_ENC_VSS: case CMD_VSS_T: case CMD_ENC_VSS_T: case CMD_EFS_FILE: if(get_int(confs[OPT_STRIP])) { int s; s=strip_path_components(asfd, sb, confs); if(s<0) goto error; if(s==0) { // Too many components stripped // - carry on. continue; } // It is OK, sb.path is now stripped. } free_w(&fullpath); if(!(fullpath=prepend_s( get_string(confs[OPT_RESTOREPREFIX]), sb->path.buf))) { log_and_send_oom(asfd, __func__); goto error; } if(act==ACTION_RESTORE) { strip_invalid_characters(&fullpath); if(!overwrite_ok(sb, confs, #ifdef HAVE_WIN32 bfd, #endif fullpath)) { char msg[512]=""; // Something exists at that path. snprintf(msg, sizeof(msg), "Path exists: %s", fullpath); if(restore_interrupt(asfd, sb, msg, confs)) goto error; else continue; } } break; case CMD_MESSAGE: case CMD_WARNING: log_recvd(&sb->path, confs, 1); printf("\n"); continue; default: break; } switch(sb->path.cmd) { // These are the same in both protocol1 and protocol2. case CMD_DIRECTORY: if(restore_dir(asfd, sb, fullpath, act, confs)) goto error; continue; case CMD_SOFT_LINK: case CMD_HARD_LINK: if(restore_link(asfd, sb, fullpath, act, confs)) goto error; continue; case CMD_SPECIAL: if(restore_special(asfd, sb, fullpath, act, confs)) goto error; continue; default: break; } if(protocol==PROTO_2) { if(restore_switch_protocol2(asfd, sb, fullpath, act, bfd, vss_restore, confs)) goto error; } else { if(restore_switch_protocol1(asfd, sb, fullpath, act, bfd, vss_restore, confs)) goto error; } } end: ret=0; error: // It is possible for a fd to still be open. bfd->close(bfd, asfd); bfile_free(&bfd); cntr_print_end(get_cntr(confs[OPT_CNTR])); cntr_print(get_cntr(confs[OPT_CNTR]), act); if(!ret) logp("%s finished\n", act_str(act)); else logp("ret: %d\n", ret); sbuf_free(&sb); free_w(&style); if(datpath) { recursive_delete(datpath, NULL, 1); free(datpath); } free_w(&fullpath); return ret; }