static int conf_set_from_global(struct conf **globalc, struct conf **cc) { int i=0; for(i=0; i<OPT_MAX; i++) { if(!(cc[i]->flags & CONF_FLAG_CC_OVERRIDE)) continue; switch(cc[i]->conf_type) { case CT_STRING: set_string(cc[i], get_string(globalc[i])); break; case CT_UINT: set_int(cc[i], get_int(globalc[i])); break; case CT_FLOAT: set_float(cc[i], get_float(globalc[i])); break; case CT_MODE_T: set_mode_t(cc[i], get_mode_t(globalc[i])); break; case CT_SSIZE_T: set_uint64_t(cc[i], get_uint64_t(globalc[i])); break; case CT_E_BURP_MODE: set_e_burp_mode(cc[i], get_e_burp_mode(globalc[i])); break; case CT_E_PROTOCOL: set_e_protocol(cc[i], get_e_protocol(globalc[i])); break; case CT_E_RECOVERY_METHOD: set_e_recovery_method(cc[i], get_e_recovery_method(globalc[i])); break; case CT_E_RSHASH: set_e_rshash(cc[i], get_e_rshash(globalc[i])); break; case CT_STRLIST: // Done later. break; case CT_CNTR: break; // No default so that there are warnings if anything // was missed. } } // If ssl_peer_cn is not set, default it to the client name. if(!get_string(globalc[OPT_SSL_PEER_CN]) && set_string(cc[OPT_SSL_PEER_CN], get_string(cc[OPT_CNAME]))) return -1; return 0; }
static int load_conf_field_and_value(struct conf **c, const char *f, // field const char *v, // value const char *conf_path, int line) { if(!strcmp(f, "compression")) { int compression=get_compression(v); if(compression<0) return -1; set_int(c[OPT_COMPRESSION], compression); } else if(!strcmp(f, "ssl_compression")) { int compression=get_compression(v); if(compression<0) return -1; set_int(c[OPT_SSL_COMPRESSION], compression); } else if(!strcmp(f, "ratelimit")) { float f=0; f=atof(v); // User is specifying Mega bits per second. // Need to convert to bytes per second. f=(f*1024*1024)/8; if(!f) { logp("ratelimit should be greater than zero\n"); return -1; } set_float(c[OPT_RATELIMIT], f); } else { int i=0; for(i=0; i<OPT_MAX; i++) { if(strcmp(c[i]->field, f)) continue; switch(c[i]->conf_type) { case CT_STRING: return set_string(c[i], v); case CT_UINT: return set_int(c[i], atoi(v)); case CT_FLOAT: return set_float(c[i], atof(v)); break; case CT_MODE_T: return set_mode_t(c[i], strtol(v, NULL, 8)); case CT_SSIZE_T: { uint64_t s=0; return get_file_size(v, &s, conf_path, line) || set_uint64_t(c[i], s); } case CT_E_BURP_MODE: return set_e_burp_mode(c[i], str_to_burp_mode(v)); case CT_E_PROTOCOL: return set_e_protocol(c[i], str_to_protocol(v)); case CT_E_RECOVERY_METHOD: return set_e_recovery_method(c[i], str_to_recovery_method(v)); case CT_STRLIST: return add_to_strlist(c[i], v, !strcmp(c[i]->field, "include")); case CT_E_RSHASH: break; case CT_CNTR: break; // No default so we get a warning if something // was missed; } } } return 0; }
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; }
int extra_comms(struct async *as, struct conf **confs, enum action *action, char **incexc) { int ret=-1; char *feat=NULL; struct asfd *asfd; struct iobuf *rbuf; const char *orig_client=get_string(confs[OPT_ORIG_CLIENT]); asfd=as->asfd; rbuf=asfd->rbuf; if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin")) { logp("Problem requesting extra_comms_begin\n"); goto end; } // Servers greater than 1.3.0 will list the extra_comms // features they support. if(asfd->read(asfd)) { logp("Problem reading response to extra_comms_begin\n"); goto end; } feat=rbuf->buf; if(rbuf->cmd!=CMD_GEN || strncmp_w(feat, "extra_comms_begin ok")) { iobuf_log_unexpected(rbuf, __func__); goto end; } logp("%s\n", feat); iobuf_init(rbuf); // Can add extra bits here. The first extra bit is the // autoupgrade stuff. if(server_supports_autoupgrade(feat) && get_string(confs[OPT_AUTOUPGRADE_DIR]) && get_string(confs[OPT_AUTOUPGRADE_OS]) && autoupgrade_client(as, confs)) goto end; // :srestore: means that the server wants to do a restore. if(server_supports(feat, ":srestore:")) { if(get_int(confs[OPT_SERVER_CAN_RESTORE])) { logp("Server is initiating a restore\n"); if(incexc_recv_client_restore(asfd, incexc, confs)) goto end; if(*incexc) { if(conf_parse_incexcs_buf(confs, *incexc)) goto end; *action=ACTION_RESTORE; log_restore_settings(confs, 1); } } else { logp("Server wants to initiate a restore\n"); logp("Client configuration says no\n"); if(asfd->write_str(asfd, CMD_GEN, "srestore not ok")) goto end; } } if(orig_client) { char str[512]=""; snprintf(str, sizeof(str), "orig_client=%s", orig_client); if(!server_supports(feat, ":orig_client:")) { logp("Server does not support switching client.\n"); goto end; } if(asfd->write_str(asfd, CMD_GEN, str) || asfd->read_expect(asfd, CMD_GEN, "orig_client ok")) { logp("Problem requesting %s\n", str); goto end; } logp("Switched to client %s\n", orig_client); } // :sincexc: is for the server giving the client the // incexc config. if(*action==ACTION_BACKUP || *action==ACTION_BACKUP_TIMED || *action==ACTION_TIMER_CHECK) { if(!*incexc && server_supports(feat, ":sincexc:")) { logp("Server is setting includes/excludes.\n"); if(incexc_recv_client(asfd, incexc, confs)) goto end; if(*incexc && conf_parse_incexcs_buf(confs, *incexc)) goto end; } } if(server_supports(feat, ":counters:")) { if(asfd->write_str(asfd, CMD_GEN, "countersok")) goto end; set_int(confs[OPT_SEND_CLIENT_CNTR], 1); } // :incexc: is for the client sending the server the // incexc conf so that it better knows what to do on // resume. if(server_supports(feat, ":incexc:") && incexc_send_client(asfd, confs)) goto end; if(server_supports(feat, ":uname:")) { const char *clientos=NULL; #ifdef HAVE_WIN32 #ifdef _WIN64 clientos="Windows 64bit"; #else clientos="Windows 32bit"; #endif #else struct utsname utsname; if(!uname(&utsname)) clientos=(const char *)utsname.sysname; #endif if(clientos) { char msg[128]=""; snprintf(msg, sizeof(msg), "uname=%s", clientos); if(asfd->write_str(asfd, CMD_GEN, msg)) goto end; } } if(server_supports(feat, ":csetproto:")) { char msg[128]=""; // Use protocol2 if no choice has been made on client side. if(get_e_protocol(confs[OPT_PROTOCOL])==PROTO_AUTO) { logp("Server has protocol=0 (auto)\n"); set_e_protocol(confs[OPT_PROTOCOL], PROTO_2); } // Send choice to server. snprintf(msg, sizeof(msg), "protocol=%d", get_e_protocol(confs[OPT_PROTOCOL])); if(asfd->write_str(asfd, CMD_GEN, msg)) goto end; logp("Using protocol=%d\n", get_e_protocol(confs[OPT_PROTOCOL])); } else if(server_supports(feat, ":forceproto=1:")) { logp("Server is forcing protocol 1\n"); if(get_e_protocol(confs[OPT_PROTOCOL])!=PROTO_AUTO && get_e_protocol(confs[OPT_PROTOCOL])!=PROTO_1) { logp("But client has set protocol=%d!\n", get_e_protocol(confs[OPT_PROTOCOL])); goto end; } set_e_protocol(confs[OPT_PROTOCOL], PROTO_1); } else if(server_supports(feat, ":forceproto=2:")) { logp("Server is forcing protocol 2\n"); if(get_e_protocol(confs[OPT_PROTOCOL])!=PROTO_AUTO && get_e_protocol(confs[OPT_PROTOCOL])!=PROTO_2) { logp("But client has set protocol=%d!\n", get_e_protocol(confs[OPT_PROTOCOL])); goto end; } set_e_protocol(confs[OPT_PROTOCOL], PROTO_2); } if(server_supports(feat, ":msg:")) { set_int(confs[OPT_MESSAGE], 1); if(asfd->write_str(asfd, CMD_GEN, "msg")) goto end; } #ifndef RS_DEFAULT_STRONG_LEN if(server_supports(feat, ":rshash=blake2:")) { set_e_rshash(confs[OPT_RSHASH], RSHASH_BLAKE2); // Send choice to server. if(asfd->write_str(asfd, CMD_GEN, "rshash=blake2")) goto end; } else #endif set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4); if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end") || asfd->read_expect(asfd, CMD_GEN, "extra_comms_end ok")) { logp("Problem requesting extra_comms_end\n"); goto end; } ret=0; end: 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; }