Beispiel #1
0
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;
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}