예제 #1
0
static int maybe_send_extrameta(const char *path, char cmd, const char *attribs, struct cntr *p1cntr)
{
	if(has_extrameta(path, cmd))
	{
		if(async_write_str(CMD_STAT, attribs)
		  || async_write_str(metasymbol, path))
			return -1;
		do_filecounter(p1cntr, metasymbol, 1);
	}
	return 0;
}
예제 #2
0
파일: incexc_send.c 프로젝트: hcgpalm/burp
static int do_start(const char *reqstr, const char *repstr)
{
	int ret=-1;
	char cmd='\0';
	char *buf=NULL;
	size_t len=0;

	if(async_write_str(CMD_GEN, reqstr))
		goto end;
	if(async_read(&cmd, &buf, &len))
		goto end;
	if(cmd==CMD_GEN)
	{
		if(strcmp(buf, repstr))
		{
			logp("unexpected response to %s: %s\n", reqstr, buf);
			goto end;
		}
	}
	else
	{
		logp("unexpected response to %s: %c:%s\n", reqstr, cmd, buf);
		goto end;
	}
	ret=0;
end:
	if(buf) free(buf);
	return ret;
}
예제 #3
0
파일: asyncio.c 프로젝트: barroque/burp
void log_and_send_oom(const char *function)
{
	char m[256]="";
	snprintf(m, sizeof(m), "out of memory in %s()\n", __FUNCTION__);
	logp("%s", m);
	if(fd>0) async_write_str(CMD_ERROR, m);
}
예제 #4
0
파일: delete_client.c 프로젝트: bassu/burp
int do_delete_client(struct config *conf)
{
	char msg[128]="";
	snprintf(msg, sizeof(msg), "delete %s", conf->backup?conf->backup:"");
	if(async_write_str(CMD_GEN, msg)
	  || async_read_expect(CMD_GEN, "ok"))
		return -1;
	logp("Deletion in progress\n");
	return 0;
}
예제 #5
0
파일: incexc_send.c 프로젝트: hcgpalm/burp
static int send_incexc_str(const char *pre, const char *str)
{
	char *tosend=NULL;
	if(!str) return 0;
	if(!(tosend=prepend(pre, str, strlen(str), " = ")))
		return -1;
	if(async_write_str(CMD_GEN, tosend))
	{
		logp("Error in async_write_str when sending incexc\n");
		return -1;
	}
	return 0;
}
예제 #6
0
파일: msg.c 프로젝트: goneri/burp
static int do_write(BFILE *bfd, FILE *fp, unsigned char *out, size_t outlen, char **metadata, unsigned long long *sent)
{
	int ret=0;
	if(metadata)
	{
		// Append it to our metadata.
		out[outlen]='\0';
		//printf("\nadd outlen: %lu\n", outlen);
		if(!(*metadata=prepend_len(*metadata, *sent,
				(const char *)out, outlen,
				"", 0, (size_t *)sent)))
		{
			logp("error when appending metadata\n");
			async_write_str(CMD_ERROR, "error when appending metadata");
			return -1;
		}
	}
	else
	{
#ifdef HAVE_WIN32
		if((ret=bwrite(bfd, out, outlen))<=0)
		{
			logp("error when appending: %d\n", ret);
			async_write_str(CMD_ERROR, "write failed");
			return -1;
		}
#else
		if((fp && (ret=fwrite(out, 1, outlen, fp))<=0))
		{
			logp("error when appending: %d\n", ret);
			async_write_str(CMD_ERROR, "write failed");
			return -1;
		}
#endif
		*sent+=outlen;
	}
	return 0;
}
예제 #7
0
파일: counter.c 프로젝트: barroque/burp
int send_counters(const char *client, struct cntr *p1cntr, struct cntr *cntr)
{
	char buf[4096]="";
	counters_to_str(buf, sizeof(buf),
		client,
		STATUS_RUNNING,
		" " /* normally the path for status server */,
		p1cntr, cntr);
	if(async_write_str(CMD_GEN, buf))
	{
		logp("Error when sending counters to client.\n");
		return -1;
	}
	return 0;
}
예제 #8
0
int incexc_recv_server(char **incexc, struct config *conf, struct cntr *p1cntr)
{
	int ret=-1;
	char *tmp=NULL;
	char *buf=NULL;
	if(async_write_str(CMD_GEN, "incexc ok"))
		goto end;
	while(1)
	{
		char cmd;
		size_t len=0;

		if(async_read(&cmd, &buf, &len))
			break;
		if(cmd==CMD_GEN)
		{
			if(!strcmp(buf, "incexc end"))
			{
				if(async_write_str(CMD_GEN, "incexc end ok"))
					goto end;
				ret=0;
				break;
			}
			if(!(tmp=prepend(*incexc?:"", buf, strlen(buf),
				*incexc?"\n":"")))
					goto end;
			if(*incexc) free(*incexc);
			*incexc=tmp;
		}
		else
		{
			logp("unexpected command from client when receiving incexc: %c:%s\n", cmd, buf);
			break;
		}
		if(buf) { free(buf); buf=NULL; }
	}
예제 #9
0
파일: handy.c 프로젝트: goneri/burp
int write_endfile(unsigned long long bytes, unsigned char *checksum)
{
	int ret=0;
	char endmsg[128]="";

	snprintf(endmsg, sizeof(endmsg),
#ifdef HAVE_WIN32
		"%I64u:%s",
#else
		"%llu:%s",
#endif
		bytes, get_checksum_str(checksum));
	ret=async_write_str(CMD_END_FILE, endmsg);
	return ret;
}
예제 #10
0
파일: asyncio.c 프로젝트: goneri/burp
// should be in src/lib/log.c
int logw(struct cntr *cntr, const char *fmt, ...)
{
	int r=0;
	char buf[512]="";
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), fmt, ap);
	if(doing_estimate) printf("\nWARNING: %s\n", buf);
	else
	{
		r=async_write_str(CMD_WARNING, buf);
		logp("WARNING: %s\n", buf);
	}
	va_end(ap);
	do_filecounter(cntr, CMD_WARNING, 1);
	return r;
}
예제 #11
0
// Return 0 for OK, -1 for error, 1 for timer conditions not met.
static int maybe_check_timer(const char *phase1str, struct config *conf, int *resume)
{
	char rcmd=0;
	char *rdst=NULL;
	size_t rlen=0;
	int complen=0;

        if(async_write_str(CMD_GEN, phase1str)) return -1;

        if(async_read(&rcmd, &rdst, &rlen)) return -1;

        if(rcmd==CMD_GEN && !strcmp(rdst, "timer conditions not met"))
        {
                free(rdst);
                logp("Timer conditions on the server were not met\n");
                return 1;
        }
        else if(rcmd!=CMD_GEN)
        {
                logp("unexpected command from server: %c:%s\n", rcmd ,rdst);
                free(rdst);
                return -1;
        }

	if(!strncmp(rdst, "ok", 2))
		complen=3;
	else if(!strncmp(rdst, "resume", 6))
	{
		complen=7;
		*resume=1;
		logp("server wants to resume previous backup.\n");
	}
	else
	{
                logp("unexpected command from server: %c:%s\n", rcmd ,rdst);
                free(rdst);
                return -1;
	}
        // The server now tells us the compression level in the OK response.
        if(strlen(rdst)>3) conf->compression=atoi(rdst+complen);
        logp("Compression level: %d\n", conf->compression);

	return 0;
}
예제 #12
0
static int forget_file(struct sbuf *sb, char cmd, struct cntr *cntr)
{
	// Tell the server to forget about this
	// file, otherwise it might get stuck
	// on a select waiting for it to arrive.
	if(async_write_str(CMD_INTERRUPT, sb->path))
		return 0;

	if(cmd==CMD_FILE && sb->datapth)
	{
		rs_signature_t *sumset=NULL;
		// The server will be sending
		// us a signature. Munch it up
		// then carry on.
		if(load_signature(&sumset, cntr))
			return -1;
		else rs_free_sumset(sumset);
	}
	return 0;
}
예제 #13
0
static int do_restore_end(enum action act, struct cntr *cntr)
{
	char cmd;
	int ret=0;
	int quit=0;
	size_t len=0;

	if(async_write_str(CMD_GEN, "restoreend"))
		ret=-1;

	while(!ret && !quit)
	{
		char *buf=NULL;
		if(async_read(&cmd, &buf, &len))
		{
			ret=-1; quit++;
		}
		else if(cmd==CMD_GEN && !strcmp(buf, "restoreend ok"))
		{
			logp("got restoreend ok\n");
			quit++;
		}
		else if(cmd==CMD_WARNING)
		{
			logp("WARNING: %s\n", buf);
			do_filecounter(cntr, cmd, 0);
		}
		else if(cmd==CMD_INTERRUPT)
		{
			// ignore - client wanted to interrupt a file
		}
		else
		{
			logp("unexpected cmd from client at end of restore: %c:%s\n", cmd, buf);
			ret=-1; quit++;
		}
		if(buf) { free(buf); buf=NULL; }
	}

	return ret;
}
예제 #14
0
파일: asyncio.c 프로젝트: goneri/burp
void log_and_send(const char *msg)
{
	logp("%s\n", msg);
	if(fd>0) async_write_str(CMD_ERROR, msg);
}
예제 #15
0
파일: ca_server.c 프로젝트: goneri/burp
/* Return 1 for everything OK, signed and returned, -1 for error, 0 for
   nothing done. */
int ca_server_maybe_sign_client_cert(const char *client, const char *cversion, struct config *conf, struct cntr *p1cntr)
{
	int ret=0;
	char *buf=NULL;
	long min_ver=0;
	long cli_ver=0;

	if((min_ver=version_to_long("1.3.2"))<0
	 || (cli_ver=version_to_long(cversion))<0)
		return -1;
	// Clients before 1.3.2 did not know how to send cert signing requests.
	if(cli_ver<min_ver) return 0;

	while(1)
	{
		char cmd;
		size_t len=0;
		if(async_read(&cmd, &buf, &len))
		{
			ret=-1;
			break;
		}
		if(cmd==CMD_GEN)
		{
			if(!strcmp(buf, "csr"))
			{
				// Client wants to sign a certificate.
				logp("Client %s wants a certificate signed\n",
					client);
				if(!conf->ca_conf || !gca_dir)
				{
					logp("But server is not configured to sign client certificate requests.\n");
					logp("See option 'ca_conf'.\n");
					async_write_str(CMD_ERROR, "server not configured to sign client certificates");
					ret=-1;
					break;
				}
				// sign_client_cert() will return 1 for
				// everything signed and returned, or -1
				// for error
				ret=sign_client_cert(client, conf, p1cntr);
				break;

			}
			else if(!strcmp(buf, "nocsr"))
			{
				// Client does not want to sign a certificate.
				// No problem, just carry on.
				logp("Client %s does not want a certificate signed\n", client);
				ret=async_write_str(CMD_GEN, "nocsr ok");
				break;
			}
			else
			{
				logp("unexpected command from client when expecting csr: %c:%s\n", cmd, buf);
				ret=-1;
				break;
			}
		}
		else
		{
			logp("unexpected command from client when expecting csr: %c:%s\n", cmd, buf);
			ret=-1;
			break;
		}

		if(buf) free(buf); buf=NULL;
	}

	if(buf) free(buf);
	return ret;
}
예제 #16
0
파일: ca_server.c 프로젝트: goneri/burp
/* Return 1 for everything OK, signed and returned, -1 for error */
static int sign_client_cert(const char *client, struct config *conf, struct cntr *p1cntr)
{
	int ret=-1;
	char msg[256]="";
	char csrpath[512]="";
	char crtpath[512]="";
	struct stat statp;
	snprintf(csrpath, sizeof(csrpath), "%s/%s.csr", gca_dir, client);
	snprintf(crtpath, sizeof(crtpath), "%s/%s.crt", gca_dir, client);

	if(!strcmp(client, conf->ca_name))
	{
		char msg[512]="";
		snprintf(msg, sizeof(msg), "Will not accept a client certificate request with the same name as the CA (%s)!", conf->ca_name);
		log_and_send(msg);
		// Do not goto end, as it will delete things;
		return -1;
	}

	if(!lstat(crtpath, &statp))
	{
		char msg[512]="";
		snprintf(msg, sizeof(msg), "Will not accept a client certificate request for '%s' - %s already exists!", client, crtpath);
		log_and_send(msg);
		// Do not goto end, as it will delete things;
		return -1;
	}

	if(!lstat(csrpath, &statp))
	{
		char msg[512]="";
		snprintf(msg, sizeof(msg), "Will not accept a client certificate request for '%s' - %s already exists!", client, csrpath);
		log_and_send(msg);
		// Do not goto end, as it will delete things;
		return -1;
	}

	// Tell the client that we will do it, and send the server name at the
	// same time.
	snprintf(msg, sizeof(msg), "csr ok:%s", conf->ca_server_name);
	if(async_write_str(CMD_GEN, msg))
	{
		// Do not goto end, as it will delete things;
		return -1;
	}

	/* After this point, we might have uploaded files, so on error, go
	   to end and delete any new files. */

	// Get the CSR from the client.
	if(receive_a_file(csrpath, p1cntr)) goto end;

	// Now, sign it.
	logp("Signing certificate signing request from %s\n", client);
	logp("Running '%s --name %s --ca %s --sign --batch --dir %s --config %s'\n", conf->ca_burp_ca, client, conf->ca_name, gca_dir, conf->ca_conf);
	if(run_script(conf->ca_burp_ca, NULL, 0, "--name", client,
		"--ca", conf->ca_name, "--sign", "--batch", "--dir", gca_dir,
		"--config", conf->ca_conf,
		NULL /* cntr */, 1 /* wait */,
		0 /* do not use logp - stupid openssl prints lots of dots
		     one at a time with no way to turn it off */))
	{
		logp("Error running %s\n", conf->ca_burp_ca);
		goto end;
	}

	// Now, we should have a signed certificate.
	// Need to send it back to the client.
	if(send_a_file(crtpath, p1cntr))
		goto end;

	// Also need to send the CA public certificate back to the client.
	if(send_a_file(conf->ssl_cert_ca, p1cntr))
		goto end;

	ret=1;
end:
	if(ret<0)
	{
		unlink(crtpath);
		unlink(csrpath);
	}
	return ret;
}
예제 #17
0
// Return -1 on error or success, 0 to continue normally.
int autoupgrade_server(long ser_ver, long cli_ver, const char *os, struct config *conf, struct cntr *p1cntr)
{
	int ret=-1;
	char *path=NULL;
	char *base_path=NULL;
	char *script_path=NULL;
	char *package_path=NULL;
	char *script_path_top=NULL;
	char *script_path_specific=NULL;
	struct stat stats;
	struct stat statp;

	if(!conf->autoupgrade_dir)
	{
		// Autoupgrades not turned on on the server.
		ret=0;
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}

	if(cli_ver>=ser_ver)
	{
		// No need to upgrade - client is same version as server,
		// or newer.
		ret=0;
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}

	if(!(base_path=prepend_s(conf->autoupgrade_dir, os, strlen(os)))
	  || !(path=prepend_s(base_path, VERSION, strlen(VERSION)))
	  || !(script_path_top=prepend_s(base_path, "script", strlen("script")))
	  || !(script_path_specific=prepend_s(path, "script", strlen("script")))
	  || !(package_path=prepend_s(path, "package", strlen("package"))))
	{
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}

	if(!stat(script_path_specific, &stats))
		script_path=script_path_specific;
	else if(!stat(script_path_top, &stats))
		script_path=script_path_top;
	else
	{
		logp("Want to autoupgrade client, but no file at:\n");
		logp("%s\n", script_path_top);
		logp("or:\n");
		logp("%s\n", script_path_specific);
		ret=0; // this is probably OK
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}
	if(stat(package_path, &statp))
	{
		logp("Want to autoupgrade client, but no file available at:\n");
		logp("%s\n", package_path);
		ret=0; // this is probably OK
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}

	if(!S_ISREG(stats.st_mode))
	{
		logp("%s is not a regular file\n", script_path);
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}
	if(!S_ISREG(statp.st_mode))
	{
		logp("%s is not a regular file\n", package_path);
		async_write_str(CMD_GEN, "do not autoupgrade");
		goto end;
	}

	if(async_write_str(CMD_GEN, "autoupgrade ok"))
		goto end;

	if(send_a_file(script_path, p1cntr))
	{
		logp("Problem sending %s\n", script_path);
		goto end;
	}
	if(send_a_file(package_path, p1cntr))
	{
		logp("Problem sending %s\n", package_path);
		goto end;
	}
	ret=0;
	/* Clients currently exit after forking, so exit ourselves. */
	logp("Expecting client to upgrade - now exiting\n");
	async_free();
	exit(0);
end:
	if(path) free(path);
	if(base_path) free(base_path);
	if(script_path_specific) free(script_path_specific);
	if(script_path_top) free(script_path_top);
	if(package_path) free(package_path);
	return ret;
}
예제 #18
0
파일: ca_client.c 프로젝트: goneri/burp
/* Return 1 for everything OK, signed and returned, -1 for error, 0 for
   nothing done. */
int ca_client_setup(struct config *conf, struct cntr *p1cntr)
{
	char cmd;
	int ret=-1;
	size_t len=0;
	char *buf=NULL;
	char csr_path[256]="";
	char ssl_cert_tmp[512]="";
	char ssl_cert_ca_tmp[512]="";
	struct stat statp;

	// Do not continue if we have none of the following things set.
	if(  !conf->ca_burp_ca
	  || !conf->ca_csr_dir
	  || !conf->ssl_cert_ca
	  || !conf->ssl_cert
	  || !conf->ssl_key
	// Do not try to get a new certificate if we already have a
	// key.
	  || !lstat(conf->ssl_key, &statp))
	{
		if(async_write_str(CMD_GEN, "nocsr")
		  || async_read_expect(CMD_GEN, "nocsr ok"))
		{
			logp("problem reading from server nocsr\n");
			return -1;
		}
		logp("nocsr ok\n");
		return 0;
	}

	// Tell the server we want to do a signing request.
	if(async_write_str(CMD_GEN, "csr"))
		return -1;

	if(async_rw_ensure_read(&cmd, &buf, &len, '\0', NULL, 0))
	{
		logp("problem reading from server csr\n");
		goto end;
	}
	if(cmd!=CMD_GEN || strncmp(buf, "csr ok:", strlen("csr ok:")))
	{
		logp("unexpected command from server: %c:%s\n", cmd, buf);
		goto end;
	}
	// The server appends its name after 'csr ok:'
	if(conf->ssl_peer_cn) free(conf->ssl_peer_cn);
	if(!(conf->ssl_peer_cn=strdup(buf+strlen("csr ok:"))))
	{
		logp("out of memory\n");
		goto end;
	}

	logp("Server will sign a certificate request\n");

	// First need to generate a client key and a certificate signing
	// request.
	snprintf(csr_path, sizeof(csr_path), "%s/%s.csr",
		conf->ca_csr_dir, conf->cname);
	if(generate_key_and_csr(conf, csr_path)) goto end;

	// Then copy the csr to the server.
	if(send_a_file(csr_path, p1cntr)) goto end;

	snprintf(ssl_cert_tmp, sizeof(ssl_cert_tmp), "%s.%d",
		conf->ssl_cert, getpid());
	snprintf(ssl_cert_ca_tmp, sizeof(ssl_cert_ca_tmp), "%s.%d",
		conf->ssl_cert_ca, getpid());

	// The server will then sign it, and give it back.
	if(receive_a_file(ssl_cert_tmp, p1cntr)) goto end;

	// The server will also send the CA certificate.
	if(receive_a_file(ssl_cert_ca_tmp, p1cntr)) goto end;

	if(do_rename(ssl_cert_tmp, conf->ssl_cert)
	  || do_rename(ssl_cert_ca_tmp, conf->ssl_cert_ca))
		goto end;

	// Need to rewrite our configuration file to contain the server
	// name (ssl_peer_cn)
	if(rewrite_client_conf(conf)) goto end;

	// My goodness, everything seems to have gone OK. Stand back!
	ret=1;
end:
	if(buf) free(buf);
	if(ret<0)
	{
		// On error, remove any possibly newly created files, so that
		// this function might run again on another go.
		unlink(csr_path);
		unlink(conf->ssl_key);
		unlink(conf->ssl_cert);
		unlink(conf->ssl_cert_ca);
		unlink(ssl_cert_tmp);
		unlink(ssl_cert_ca_tmp);
	}
	return ret;
}
예제 #19
0
/* May return 1 to mean try again. This happens after a successful certificate
   signing request so that it connects again straight away with the new
   key/certificate.
   Returns 2 if there were restore/verify warnings.
   Returns 3 if timer conditions were not met.
*/
static int do_client(struct config *conf, enum action act, int vss_restore, int json)
{
	int ret=0;
	int rfd=-1;
	int resume=0;
	SSL *ssl=NULL;
	BIO *sbio=NULL;
	char buf[256]="";
	SSL_CTX *ctx=NULL;
	struct cntr cntr;
	struct cntr p1cntr;
	char *incexc=NULL;
	char *server_version=NULL;
	const char *phase1str="backupphase1";

	reset_filecounter(&p1cntr, time(NULL));
	reset_filecounter(&cntr, time(NULL));

	setup_signals_client();
//	settimers(0, 100);
	logp("begin client\n");

	if(act!=ACTION_ESTIMATE)
	{
		ssl_load_globals();
		if(!(ctx=ssl_initialise_ctx(conf)))
		{
			logp("error initialising ssl ctx\n");
			ret=-1;
			goto end;
		}

		SSL_CTX_set_session_id_context(ctx,
			(const unsigned char *)&s_server_session_id_context,
			sizeof(s_server_session_id_context));

		if((rfd=init_client_socket(conf->server, conf->port))<0)
		{
			ret=-1;
			goto end;
		}

		if(!(ssl=SSL_new(ctx))
		  || !(sbio=BIO_new_socket(rfd, BIO_NOCLOSE)))
		{
			ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
			logp("Problem joining SSL to the socket: %s\n", buf);
			ret=-1;
			goto end;
		}
		SSL_set_bio(ssl, sbio, sbio);
		if(SSL_connect(ssl)<=0)
		{
			ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
			logp("SSL connect error: %s\n", buf);
			ret=-1;
			goto end;
		}
	}

	if((ret=async_init(rfd, ssl, conf, act==ACTION_ESTIMATE)))
		goto end;

	// Set quality of service bits on backup packets.
	if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED)
		set_bulk_packets();

	if(act!=ACTION_ESTIMATE)
	{
		char cmd=0;
		size_t len=0;
		char *feat=NULL;
		int ca_ret=0;
		if((ret=authorise_client(conf, &server_version, &p1cntr)))
			goto end;

		if(server_version)
		{
			logp("Server version: %s\n", server_version);
			// Servers before 1.3.2 did not tell us their versions.
			// 1.3.2 and above can do the automatic CA stuff that
			// follows.
			if((ca_ret=ca_client_setup(conf, &p1cntr))<0)
			{
				// Error
				logp("Error with certificate signing request\n");
				ret=-1;
				goto end;
			}
			else if(ca_ret>0)
			{
				// Certificate signed successfully.
				// Everything is OK, but we will reconnect now, in
				// order to use the new keys/certificates.
				ret=1;
				goto end;
			}
		}

		set_non_blocking(rfd);

		if((ret=ssl_check_cert(ssl, conf)))
		{
			logp("check cert failed\n");
			goto end;
		}

		if((ret=async_write_str(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.
		else if((ret=async_read(&cmd, &feat, &len)))
		{
			logp("Problem reading response to extra_comms_begin\n");
			goto end;
		}
		else if(cmd!=CMD_GEN)
		{
			logp("Unexpected command from server when reading response to extra_comms_begin: %c:%s\n", cmd, feat);
			ret=-1;
			goto end;
		}
		else if(strncmp(feat,
		  "extra_comms_begin ok", strlen("extra_comms_begin ok")))
		{
			logp("Unexpected response from server when reading response to extra_comms_begin: %c:%s\n", cmd, feat);
			ret=-1;
			goto end;
		}

		// Can add extra bits here. The first extra bit is the
		// autoupgrade stuff.

		if(server_supports_autoupgrade(feat))
		{
			if(conf->autoupgrade_dir && conf->autoupgrade_os
			  && (ret=autoupgrade_client(conf, &p1cntr)))
				goto end;
		}

		// :srestore: means that the server wants to do a restore.
		if(server_supports(feat, ":srestore:"))
		{
			if(conf->server_can_restore)
			{
				logp("Server is initiating a restore\n");
				if(incexc) { free(incexc); incexc=NULL; }
				if((ret=incexc_recv_client_restore(&incexc,
					conf, &p1cntr)))
						goto end;
				if(incexc)
				{
					if((ret=parse_incexcs_buf(conf,
						incexc))) goto end;
					act=ACTION_RESTORE;
					log_restore_settings(conf, 1);
				}
			}
			else
			{
				logp("Server wants to initiate a restore\n");
				logp("Client configuration says no\n");
				if(async_write_str(CMD_GEN, "srestore not ok"))
				{
					ret=-1;
					goto end;
				}
			}
		}

		if(conf->orig_client)
		{
			char str[512]="";
			snprintf(str, sizeof(str),
				"orig_client=%s", conf->orig_client);
			if(!server_supports(feat, ":orig_client:"))
			{
				logp("Server does not support switching client.\n");
				ret=-1;
				goto end;
			}
			if((ret=async_write_str(CMD_GEN, str))
			  || (ret=async_read_expect(CMD_GEN, "orig_client ok")))
			{
				logp("Problem requesting %s\n", str);
				ret=-1;
				goto end;
			}
			logp("Switched to client %s\n", conf->orig_client);
		}

		// :sincexc: is for the server giving the client the
		// incexc config.
		if(act==ACTION_BACKUP
		  || act==ACTION_BACKUP_TIMED)
		{
			if(!incexc && server_supports(feat, ":sincexc:"))
			{
				logp("Server is setting includes/excludes.\n");
				if(incexc) { free(incexc); incexc=NULL; }
				if((ret=incexc_recv_client(&incexc,
					conf, &p1cntr))) goto end;
				if(incexc && (ret=parse_incexcs_buf(conf,
					incexc))) goto end;
			}
		}

		if(server_supports(feat, ":counters:"))
		{
			if(async_write_str(CMD_GEN, "countersok"))
				goto end;
			conf->send_client_counters=1;
		}

		// :incexc: is for the client sending the server the
		// incexc config so that it better knows what to do on
		// resume.
		if(server_supports(feat, ":incexc:")
		  && (ret=incexc_send_client(conf, &p1cntr)))
			goto end;

		if((ret=async_write_str(CMD_GEN, "extra_comms_end"))
		  || (ret=async_read_expect(CMD_GEN, "extra_comms_end ok")))
		{
			logp("Problem requesting extra_comms_end\n");
			goto end;
		}

		if(feat) free(feat);
	}

	rfd=-1;
	switch(act)
	{
		case ACTION_BACKUP_TIMED:
			phase1str="backupphase1timed";
		case ACTION_BACKUP:
		{
			// Set bulk packets quality of service flags on backup.
			if(incexc)
			{
				logp("Server is overriding the configuration\n");
				logp("with the following settings:\n");
				if(log_incexcs_buf(incexc))
				{
					ret=-1;
					goto end;
				}
			}
			if(!conf->sdcount)
			{
				logp("Found no include paths!\n");
				ret=-1;
				goto end;
			}

			if(!(ret=maybe_check_timer(phase1str,
				conf, &resume)))
			{
				if(conf->backup_script_pre)
				{
					int a=0;
					const char *args[12];
					args[a++]=conf->backup_script_pre;
					args[a++]="pre";
					args[a++]="reserved2";
					args[a++]="reserved3";
					args[a++]="reserved4";
					args[a++]="reserved5";
					args[a++]=NULL;
					if(run_script(args,
						conf->backup_script_pre_arg,
						conf->bprecount,
						&p1cntr, 1, 1)) ret=-1;
				}

				if(!ret && do_backup_client(conf,
					resume, 0, &p1cntr, &cntr))
						ret=-1;

				if((conf->backup_script_post_run_on_fail
				  || !ret) && conf->backup_script_post)
				{
					int a=0;
					const char *args[12];
					args[a++]=conf->backup_script_post;
					args[a++]="post";
					// Tell post script whether the restore
					// failed.
					args[a++]=ret?"1":"0";
					args[a++]="reserved3";
					args[a++]="reserved4";
					args[a++]="reserved5";
					args[a++]=NULL;
					if(run_script(args,
						conf->backup_script_post_arg,
						conf->bpostcount,
						&cntr, 1, 1)) ret=-1;
				}
			}

			if(ret<0)
				logp("error in backup\n");
			else if(ret>0)
			{
				// Timer script said no.
				// Have a distinct return value to
				// differentiate between other cases
				// (ssl reconnection and restore/verify
				// warnings).
				ret=3;
			}
			else
				logp("backup finished ok\n");
			
			break;
		}
		case ACTION_RESTORE:
		case ACTION_VERIFY:
		{
			if(conf->restore_script_pre)
			{
				int a=0;
				const char *args[12];
				args[a++]=conf->restore_script_pre;
				args[a++]="pre";
				args[a++]="reserved2";
				args[a++]="reserved3";
				args[a++]="reserved4";
				args[a++]="reserved5";
				args[a++]=NULL;
				if(run_script(args,
					conf->restore_script_pre_arg,
					conf->rprecount, &cntr, 1, 1)) ret=-1;
			}
			if(!ret && do_restore_client(conf,
				act, vss_restore, &p1cntr, &cntr)) ret=-1;
			if((conf->restore_script_post_run_on_fail
			  || !ret) && conf->restore_script_post)
			{
				int a=0;
				const char *args[12];
				args[a++]=conf->restore_script_pre;
				args[a++]="post";
				// Tell post script whether the restore
				// failed.
				args[a++]=ret?"1":"0";
				args[a++]="reserved3";
				args[a++]="reserved4";
				args[a++]="reserved5";
				args[a++]=NULL;
				if(run_script(args,
					conf->restore_script_post_arg,
					conf->rpostcount, &cntr, 1, 1)) ret=-1;
			}

			// Return non-zero if there were warnings,
			// so that the test script can easily check.
			if(p1cntr.warning+cntr.warning)
				ret=2;

			break;
		}
		case ACTION_ESTIMATE:
			if(!ret) ret=do_backup_client(conf, 0, 1,
					&p1cntr, &cntr);
			break;
		case ACTION_DELETE:
			if(!ret) ret=do_delete_client(conf);
			break;
		case ACTION_LIST:
		case ACTION_LONG_LIST:
		default:
			ret=do_list_client(conf, act, json);
			break;
	}

end:
	close_fd(&rfd);
	async_free();
	if(act!=ACTION_ESTIMATE) ssl_destroy_ctx(ctx);

	if(incexc) free(incexc);
	if(server_version) free(server_version);

        //logp("end client\n");
	return ret;
}
예제 #20
0
파일: list_client.c 프로젝트: barroque/burp
int do_list_client(struct config *conf, enum action act, int json)
{
	int ret=0;
	size_t slen=0;
	char msg[512]="";
	char scmd=0;
	struct stat statp;
	char *statbuf=NULL;
	char ls[2048]="";
	char *dpth=NULL;
	int first_entry=1;
	// format long list as JSON
	int emit_json = (act==ACTION_LONG_LIST && conf->backup && json);
//logp("in do_list\n");
	if(conf->browsedir)
	  snprintf(msg, sizeof(msg), "listb %s:%s",
		conf->backup?conf->backup:"", conf->browsedir);
	else
	  snprintf(msg, sizeof(msg), "list %s:%s",
		conf->backup?conf->backup:"", conf->regex?conf->regex:"");
	if(async_write_str(CMD_GEN, msg)
	  || async_read_expect(CMD_GEN, "ok"))
		return -1;

	if(emit_json)
	{
		printf("{\n");
	}
	
	// This should probably should use the sbuf stuff.
	while(1)
	{
		char fcmd=0;
		size_t flen=0;
		int64_t winattr=0;
		int compression=-1;
		char *fname=NULL;
		if(async_read(&scmd, &statbuf, &slen))
		{
			//ret=-1; break;
			break;
		}
		if(scmd==CMD_TIMESTAMP)
		{
			// A backup timestamp, just print it.
			if(emit_json)
			{
				printf("\t\"backup\":\n"
				       "\t\t{\n"
				       "\t\t\t\"timestamp\": \"%s\",\n"
				       "\t\t\t\"directory\": \"%s\",\n"
				       "\t\t\t\"regex\": \"%s\"\n"
				       "\t\t},\n",
				       statbuf,
				       conf->browsedir? conf->browsedir:"",
				       conf->regex? conf->regex:"");
			}
			else
			{
				printf("Backup: %s\n", statbuf);
				if(conf->browsedir)
					printf("Listing directory: %s\n",
					       conf->browsedir);
				if(conf->regex)
					printf("With regex: %s\n",
					       conf->regex);
			}
			if(statbuf) { free(statbuf); statbuf=NULL; }
			continue;
		}
		else if(scmd==CMD_DATAPTH)
		{
			if(statbuf) { free(statbuf); statbuf=NULL; }
			continue;
		}
		else if(scmd!=CMD_STAT)
		{
			logp("expected %c cmd - got %c:%s\n",
				CMD_STAT, scmd, statbuf);
			ret=-1; break;
		}

		decode_stat(statbuf, &statp, &winattr, &compression);

		if(async_read(&fcmd, &fname, &flen))
		{
			logp("got stat without an object\n");
			ret=-1; break;
		}
		else if(fcmd==CMD_DIRECTORY
			|| fcmd==CMD_FILE
			|| fcmd==CMD_ENC_FILE
			|| fcmd==CMD_EFS_FILE
			|| fcmd==CMD_SPECIAL)
		{
			*ls='\0';
			if(act==ACTION_LONG_LIST)
			{
				if(emit_json)
				{
					char *esc_fname = NULL;
					ls_output_json(ls, sizeof(ls), first_entry, fcmd, fname, &esc_fname, NULL, NULL, &statp);
					printf(ls, esc_fname? esc_fname:"", "");
					if(esc_fname)
						free(esc_fname);
				}
				else
				{
					ls_output(ls, fname, &statp);
					printf("%s\n", ls);
				}
			}
			else
			{
				printf("%s\n", fname);
			}
			if (first_entry)
			{
				first_entry = 0;
			}
		}
		else if(cmd_is_link(fcmd)) // symlink or hardlink
		{
			char lcmd=0;
			size_t llen=0;
			char *lname=NULL;
			if(async_read(&lcmd, &lname, &llen)
			  || lcmd!=fcmd)
			{
				logp("could not get second part of link %c:%s\n", fcmd, fname);
				ret=-1;
			}
			else
			{
				if(act==ACTION_LONG_LIST)
				{
					*ls='\0';
					if(emit_json)
					{
						char *esc_fname = NULL;
						char *esc_lname = NULL;
						ls_output_json(ls, sizeof(ls), first_entry, fcmd, fname, &esc_fname, lname, &esc_lname, &statp);
						printf(ls, esc_fname? esc_fname:"", esc_lname? esc_lname:"");
						if(esc_fname)
							free(esc_fname);
						if(esc_lname)
							free(esc_lname);
					}
					else
					{
						ls_output(ls, fname, &statp);
						printf("%s -> %s\n", ls, lname);
					}
				}
				else
				{
					printf("%s\n", fname);
				}
				if (first_entry)
				{
					first_entry = 0;
				}
			}
			if(lname) free(lname);
		}
		else
		{
			fprintf(stderr, "unlistable %c:%s\n", fcmd, fname?:"");
		}
		if(fname) free(fname);
		if(statbuf) { free(statbuf); statbuf=NULL; }
	}
	if(statbuf) free(statbuf);
	if(dpth) free(dpth);
	if(emit_json)
	{
		if(!first_entry)
		{
			printf("\t\t]\n");
		}
		printf("}\n");
	}
	if(!ret) logp("List finished ok\n");
	return ret;
}
예제 #21
0
static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *cntr)
{
    int ret=0;
    int quit=0;
    char cmd;
    char *buf=NULL;
    size_t len=0;
    char attribs[MAXSTRING];

    struct sbuf sb;

    init_sbuf(&sb);

    if(!resume)
    {
        // Only do this bit if the server did not tell us to resume.
        if(async_write_str(CMD_GEN, "backupphase2")
                || async_read_expect(CMD_GEN, "ok"))
            return -1;
    }

    while(!quit)
    {
        if(async_read(&cmd, &buf, &len))
        {
            ret=-1;
            quit++;
        }
        else if(buf)
        {
            //logp("now: %c:%s\n", cmd, buf);
            if(cmd==CMD_DATAPTH)
            {
                sb.datapth=buf;
                buf=NULL;
                continue;
            }
            else if(cmd==CMD_STAT)
            {
                // Ignore the stat data - we will fill it
                // in again. Some time may have passed by now,
                // and it is best to make it as fresh as
                // possible.
                free(buf);
                buf=NULL;
                continue;
            }
            else if(cmd==CMD_FILE
                    || cmd==CMD_ENC_FILE
                    || cmd==CMD_METADATA
                    || cmd==CMD_ENC_METADATA
                    || cmd==CMD_EFS_FILE)
            {
                int forget=0;
                int64_t winattr=0;
                struct stat statbuf;
                char *extrameta=NULL;
                size_t elen=0;
                unsigned long long bytes=0;
                BFILE bfd;
                FILE *fp=NULL;

                sb.path=buf;
                buf=NULL;

#ifdef HAVE_WIN32
                if(win32_lstat(sb.path, &statbuf, &winattr))
#else
                if(lstat(sb.path, &statbuf))
#endif
                {
                    logw(cntr, "Path has vanished: %s", sb.path);
                    if(forget_file(&sb, cmd, cntr))
                    {
                        ret=-1;
                        quit++;
                    }
                    free_sbuf(&sb);
                    continue;
                }

                if(conf->min_file_size
                        && statbuf.st_size<(boffset_t)conf->min_file_size)
                {
                    logw(cntr, "File size decreased below min_file_size after initial scan: %s", sb.path);
                    forget++;
                }
                else if(conf->max_file_size
                        && statbuf.st_size>(boffset_t)conf->max_file_size)
                {
                    logw(cntr, "File size increased above max_file_size after initial scan: %s", sb.path);
                    forget++;
                }

                if(!forget)
                {
                    encode_stat(attribs, &statbuf, winattr);
                    if(open_file_for_send(&bfd, &fp,
                                          sb.path, winattr, cntr))
                        forget++;
                }

                if(forget)
                {
                    if(forget_file(&sb, cmd, cntr))
                    {
                        ret=-1;
                        quit++;
                    }
                    free_sbuf(&sb);
                    continue;
                }

                if(cmd==CMD_METADATA
                        || cmd==CMD_ENC_METADATA)
                {
                    if(get_extrameta(sb.path,
                                     &statbuf, &extrameta, &elen,
                                     cntr))
                    {
                        logw(cntr, "Meta data error for %s", sb.path);
                        free_sbuf(&sb);
                        close_file_for_send(&bfd, &fp);
                        continue;
                    }
                    if(!extrameta)
                    {
                        logw(cntr, "No meta data after all: %s", sb.path);
                        free_sbuf(&sb);
                        close_file_for_send(&bfd, &fp);
                        continue;
                    }
                }

                if(cmd==CMD_FILE && sb.datapth)
                {
                    unsigned long long sentbytes=0;
                    // Need to do sig/delta stuff.
                    if(async_write_str(CMD_DATAPTH, sb.datapth)
                            || async_write_str(CMD_STAT, attribs)
                            || async_write_str(CMD_FILE, sb.path)
                            || load_signature_and_send_delta(
                                &bfd, fp,
                                &bytes, &sentbytes, cntr))
                    {
                        logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth);
                        ret=-1;
                        quit++;
                    }
                    else
                    {
                        do_filecounter(cntr, CMD_FILE_CHANGED, 1);
                        do_filecounter_bytes(cntr, bytes);
                        do_filecounter_sentbytes(cntr, sentbytes);
                    }
                }
                else
                {
                    //logp("need to send whole file: %s\n",
                    //	sb.path);
                    // send the whole file.
                    if(async_write_str(CMD_STAT, attribs)
                            || async_write_str(cmd, sb.path)
                            || send_whole_file_w(cmd, sb.path,
                                                 NULL, 0, &bytes,
                                                 conf->encryption_password,
                                                 cntr, conf->compression,
                                                 &bfd, fp,
                                                 extrameta, elen))
                    {
                        ret=-1;
                        quit++;
                    }
                    else
                    {
                        do_filecounter(cntr, cmd, 1);
                        do_filecounter_bytes(cntr, bytes);
                        do_filecounter_sentbytes(cntr, bytes);
                    }
                }
                close_file_for_send(&bfd, &fp);
                free_sbuf(&sb);
                if(extrameta) free(extrameta);
            }
            else if(cmd==CMD_WARNING)
            {
                do_filecounter(cntr, cmd, 0);
                free(buf);
                buf=NULL;
            }
            else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end"))
            {
                if(async_write_str(CMD_GEN, "okbackupphase2end"))
                    ret=-1;
                quit++;
            }
            else
            {
                logp("unexpected cmd from server: %c %s\n",
                     cmd, buf);
                ret=-1;
                quit++;
                free(buf);
                buf=NULL;
            }
        }
    }
    return ret;
}
예제 #22
0
파일: auth_server.c 프로젝트: tcheneau/burp
int authorise_server(struct config *conf, char **client, char **cversion, struct config *cconf, struct cntr *p1cntr)
{
	char cmd;
	char *cp=NULL;
	size_t len=0;
	char *buf=NULL;
	char *password=NULL;
	char whoareyou[256]="";
	if(async_read(&cmd, &buf, &len))
	{
		logp("unable to read initial message\n");
		return -1;
	}
	if(cmd!=CMD_GEN || strncmp(buf, "hello", strlen("hello")))
	{
		logp("unexpected command given: %c %s\n", cmd, buf);
		free(buf);
		return -1;
	}
	// String may look like...
	// "hello"
	// "hello:(version)"
	// (version) is a version number
	if((cp=strchr(buf, ':')))
	{
		cp++;
		if(cp) *cversion=strdup(cp);
	}
	free(buf); buf=NULL;

	snprintf(whoareyou, sizeof(whoareyou), "whoareyou");
	if(*cversion)
	{
		long min_ver=0;
		long cli_ver=0;
		if((min_ver=version_to_long("1.3.2"))<0
		  || (cli_ver=version_to_long(*cversion))<0)
			return -1;
		// Stick the server version on the end of the whoareyou string.
		// if the client version is recent enough.
		if(min_ver<=cli_ver)
		 snprintf(whoareyou, sizeof(whoareyou),
			"whoareyou:%s", VERSION);
	}

	async_write_str(CMD_GEN, whoareyou);
	if(async_read(&cmd, &buf, &len) || !len)
	{
		logp("unable to get client name\n");
		if(*cversion) free(*cversion); *cversion=NULL;
		return -1;
	}
	*client=buf;
	buf=NULL;
	async_write_str(CMD_GEN, "okpassword");
	if(async_read(&cmd, &buf, &len) || !len)
	{
		logp("unable to get password for client %s\n", *client);
		if(*client) free(*client); *client=NULL;
		if(*cversion) free(*cversion); *cversion=NULL;
		free(buf); buf=NULL;
		return -1;
	}
	password=buf;
	buf=NULL;

	if(check_client_and_password(conf, *client, password, cconf))
	{
		if(*client) free(*client); *client=NULL;
		if(*cversion) free(*cversion); *cversion=NULL;
		free(password); password=NULL;
		return -1;
	}

	version_warn(p1cntr, *client, *cversion);

	logp("auth ok for client: %s\n", *client);
	if(password) free(password);

	async_write_str(CMD_GEN, "ok");
	return 0;
}
예제 #23
0
int do_restore_server(const char *basedir, enum action act, const char *client, int srestore, char **dir_for_notify, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf)
{
	int a=0;
	int i=0;
	int ret=0;
	int found=0;
	struct bu *arr=NULL;
	unsigned long index=0;
	char *tmppath1=NULL;
	char *tmppath2=NULL;
	regex_t *regex=NULL;

	logp("in do_restore\n");

	if(compile_regex(&regex, cconf->regex)) return -1;

	if(!(tmppath1=prepend_s(basedir, "tmp1", strlen("tmp1")))
	  || !(tmppath2=prepend_s(basedir, "tmp2", strlen("tmp2"))))
	{
		if(tmppath1) free(tmppath1);
		if(regex) { regfree(regex); free(regex); }
		return -1;
	}

	if(get_current_backups(basedir, &arr, &a, 1))
	{
		if(tmppath1) free(tmppath1);
		if(tmppath2) free(tmppath2);
		if(regex) { regfree(regex); free(regex); }
		return -1;
	}

	if(!(index=strtoul(cconf->backup, NULL, 10)) && a>0)
	{
		// No backup specified, do the most recent.
		ret=restore_manifest(arr, a, a-1,
			tmppath1, tmppath2, regex, srestore, act, client,
			dir_for_notify,
			p1cntr, cntr, cconf);
		found=TRUE;
	}

	if(!found) for(i=0; i<a; i++)
	{
		if(!strcmp(arr[i].timestamp, cconf->backup)
			|| arr[i].index==index)
		{
			found=TRUE;
			//logp("got: %s\n", arr[i].path);
			ret|=restore_manifest(arr, a, i,
				tmppath1, tmppath2, regex,
				srestore, act, client, dir_for_notify,
				p1cntr, cntr, cconf);
			break;
		}
	}

	free_current_backups(&arr, a);

	if(!found)
	{
		logp("backup not found\n");
		async_write_str(CMD_ERROR, "backup not found");
		ret=-1;
	}
	if(tmppath1)
	{
		unlink(tmppath1);
		free(tmppath1);
	}
	if(tmppath2)
	{
		unlink(tmppath2);
		free(tmppath2);
	}
	if(regex)
	{
		regfree(regex);
		free(regex);
	}
	return ret;
}
예제 #24
0
파일: list_server.c 프로젝트: barroque/burp
int do_list_server(const char *basedir, const char *backup, const char *listregex, const char *browsedir, const char *client, struct cntr *p1cntr, struct cntr *cntr)
{
	int a=0;
	int i=0;
	int ret=0;
	int found=0;
	struct bu *arr=NULL;
	unsigned long index=0;
	regex_t *regex=NULL;

	logp("in do_list\n");

	if(compile_regex(&regex, listregex)) return -1;

	if(get_current_backups(basedir, &arr, &a, 1))
	{
		if(regex) { regfree(regex); free(regex); }
		return -1;
	}

	write_status(client, STATUS_LISTING, NULL, p1cntr, cntr);

	if(backup && *backup) index=strtoul(backup, NULL, 10);

	for(i=0; i<a; i++)
	{
		// Search all backups for things matching the regex.
		if(listregex && backup && *backup=='a')
		{
			found=TRUE;
			async_write(CMD_TIMESTAMP,
				arr[i].timestamp, strlen(arr[i].timestamp));
			ret+=list_manifest(arr[i].path, regex, browsedir,
				client, p1cntr, cntr);
		}
		// Search or list a particular backup.
		else if(backup && *backup)
		{
			if(!found
			  && (!strcmp(arr[i].timestamp, backup)
				|| arr[i].index==index))
			{
				found=TRUE;
				async_write(CMD_TIMESTAMP,
				  arr[i].timestamp, strlen(arr[i].timestamp));
				ret=list_manifest(arr[i].path, regex,
					browsedir, client, p1cntr, cntr);
			}
		}
		// List the backups.
		else
		{
			found=TRUE;
			async_write(CMD_TIMESTAMP,
				arr[i].timestamp, strlen(arr[i].timestamp));
		}
	}
	free_current_backups(&arr, a);

	if(backup && *backup && !found)
	{
		async_write_str(CMD_ERROR, "backup not found");
		ret=-1;
	}
	if(regex) { regfree(regex); free(regex); }
	return ret;
}
예제 #25
0
static int do_backup_phase2_client(struct config *conf, int resume, struct cntr *p1cntr, struct cntr *cntr)
{
	int ret=0;
	int quit=0;
	char cmd;
	char *buf=NULL;
	size_t len=0;
	char attribs[MAXSTRING];
	// For efficiency, open Windows files for the VSS data, and do not
	// close them until another time around the loop, when the actual
	// data is read.
	BFILE bfd;
	// Windows VSS headers tell us how much file
	// data to expect.
	size_t datalen=0;
#ifdef HAVE_WIN32
	binit(&bfd, 0);
#endif

	struct sbuf sb;

	init_sbuf(&sb);

	if(!resume)
	{
		// Only do this bit if the server did not tell us to resume.
		if(async_write_str(CMD_GEN, "backupphase2")
		  || async_read_expect(CMD_GEN, "ok"))
			return -1;
	}
	else if(conf->send_client_counters)
	{
		// On resume, the server might update the client with the
 		// counters.
		if(recv_counters(p1cntr, cntr))
			return -1;	
	}

	while(!quit)
	{
		if(async_read(&cmd, &buf, &len))
		{
			ret=-1;
			quit++;
		}
		else if(buf)
		{
			//logp("now: %c:%s\n", cmd, buf);
			if(cmd==CMD_DATAPTH)
			{
				sb.datapth=buf;
				buf=NULL;
				continue;
			}
			else if(cmd==CMD_STAT)
			{
				// Ignore the stat data - we will fill it
				// in again. Some time may have passed by now,
				// and it is best to make it as fresh as
				// possible.
				free(buf);
				buf=NULL;
				continue;
			}
			else if(cmd==CMD_FILE
			  || cmd==CMD_ENC_FILE
			  || cmd==CMD_METADATA
			  || cmd==CMD_ENC_METADATA
			  || cmd==CMD_VSS
			  || cmd==CMD_ENC_VSS
			  || cmd==CMD_VSS_T
			  || cmd==CMD_ENC_VSS_T
			  || cmd==CMD_EFS_FILE)
			{
				int forget=0;
				int64_t winattr=0;
				struct stat statbuf;
				char *extrameta=NULL;
				size_t elen=0;
				unsigned long long bytes=0;
				FILE *fp=NULL;
				int compression=conf->compression;

				sb.path=buf;
				buf=NULL;

#ifdef HAVE_WIN32
				if(win32_lstat(sb.path, &statbuf, &winattr))
#else
				if(lstat(sb.path, &statbuf))
#endif
				{
					logw(cntr, "Path has vanished: %s", sb.path);
					if(forget_file(&sb, cmd, cntr))
					{
						ret=-1;
						quit++;
					}
					free_sbuf(&sb);
					continue;
				}

				if(conf->min_file_size
				  && statbuf.st_size<
					(boffset_t)conf->min_file_size
				  && (cmd==CMD_FILE
				  || cmd==CMD_ENC_FILE
				  || cmd==CMD_EFS_FILE))
				{
					logw(cntr, "File size decreased below min_file_size after initial scan: %c:%s", cmd, sb.path);
					forget++;
				}
				else if(conf->max_file_size
				  && statbuf.st_size>
					(boffset_t)conf->max_file_size
				  && (cmd==CMD_FILE
				  || cmd==CMD_ENC_FILE
				  || cmd==CMD_EFS_FILE))
				{
					logw(cntr, "File size increased above max_file_size after initial scan: %c:%s", cmd, sb.path);
					forget++;
				}

				if(!forget)
				{
					compression=in_exclude_comp(conf->excom,
					  conf->excmcount, sb.path,
					  conf->compression);
					encode_stat(attribs,
					  &statbuf, winattr, compression);
					if(open_file_for_send(
#ifdef HAVE_WIN32
						&bfd, NULL,
#else
						NULL, &fp,
#endif
						sb.path, winattr,
						&datalen, cntr))
							forget++;
				}

				if(forget)
				{
					if(forget_file(&sb, cmd, cntr))
					{
						ret=-1;
						quit++;
					}
					free_sbuf(&sb);
					continue;
				}

				if(cmd==CMD_METADATA
				  || cmd==CMD_ENC_METADATA
				  || cmd==CMD_VSS
				  || cmd==CMD_ENC_VSS
#ifdef HAVE_WIN32
				  || conf->strip_vss
#endif
				  )
				{
					if(get_extrameta(
#ifdef HAVE_WIN32
						&bfd,
#else
						NULL,
#endif
						sb.path,
						&statbuf, &extrameta, &elen,
						winattr, cntr,
						&datalen))
					{
						logw(cntr, "Meta data error for %s", sb.path);
						free_sbuf(&sb);
						close_file_for_send(&bfd, &fp);
						continue;
					}
					if(extrameta)
					{
#ifdef HAVE_WIN32
						if(conf->strip_vss)
						{
							free(extrameta);
							extrameta=NULL;
							elen=0;
						}
#endif
					}
					else
					{
						logw(cntr, "No meta data after all: %s", sb.path);
						free_sbuf(&sb);
						close_file_for_send(&bfd, &fp);
						continue;
					}
				}

				if(cmd==CMD_FILE && sb.datapth)
				{
					unsigned long long sentbytes=0;
					// Need to do sig/delta stuff.
					if(async_write_str(CMD_DATAPTH, sb.datapth)
					  || async_write_str(CMD_STAT, attribs)
					  || async_write_str(CMD_FILE, sb.path)
					  || load_signature_and_send_delta(
						&bfd, fp,
						&bytes, &sentbytes, cntr,
						datalen))
					{
						logp("error in sig/delta for %s (%s)\n", sb.path, sb.datapth);
						ret=-1;
						quit++;
					}
					else
					{
						do_filecounter(cntr, CMD_FILE_CHANGED, 1);
						do_filecounter_bytes(cntr, bytes);
						do_filecounter_sentbytes(cntr, sentbytes);
					}
				}
				else
				{
					//logp("need to send whole file: %s\n",
					//	sb.path);
					// send the whole file.

					if((async_write_str(CMD_STAT, attribs)
					  || async_write_str(cmd, sb.path))
					  || send_whole_file_w(cmd, sb.path,
						NULL, 0, &bytes,
						conf->encryption_password,
						cntr, compression,
						&bfd, fp,
						extrameta, elen,
						datalen))
					{
						ret=-1;
						quit++;
					}
					else
					{
						do_filecounter(cntr, cmd, 1);
						do_filecounter_bytes(cntr, bytes);
						do_filecounter_sentbytes(cntr, bytes);
					}
				}
#ifdef HAVE_WIN32
				// If using Windows do not close bfd - it needs
				// to stay open to read VSS/file data/VSS.
				// It will get closed either when given a
				// different file path, or when this function
				// exits.
				
				//if(cmd!=CMD_VSS
				// && cmd!=CMD_ENC_VSS)
				//	close_file_for_send(&bfd, NULL);
#else
				close_file_for_send(NULL, &fp);
#endif
				free_sbuf(&sb);
				if(extrameta) free(extrameta);
			}
			else if(cmd==CMD_WARNING)
			{
				do_filecounter(cntr, cmd, 0);
				free(buf);
				buf=NULL;
			}
			else if(cmd==CMD_GEN && !strcmp(buf, "backupphase2end"))
			{
				if(async_write_str(CMD_GEN, "okbackupphase2end"))
					ret=-1;
				quit++;
			}
			else
			{
				logp("unexpected cmd from server: %c %s\n",
					cmd, buf);
				ret=-1;
				quit++;
				free(buf);
				buf=NULL;
			}
		}
	}
#ifdef HAVE_WIN32
	// It is possible for a bfd to still be open.
	close_file_for_send(&bfd, NULL);
#endif
	return ret;
}
예제 #26
0
파일: msg.c 프로젝트: goneri/burp
int transfer_gzfile_in(struct sbuf *sb, const char *path, BFILE *bfd, FILE *fp, unsigned long long *rcvd, unsigned long long *sent, const char *encpassword, int enccompressed, struct cntr *cntr, char **metadata)
{
	char cmd;
	char *buf=NULL;
	size_t len=0;
	int quit=0;
	int ret=-1;
	unsigned char out[ZCHUNK];
	size_t doutlen=0;
	//unsigned char doutbuf[1000+EVP_MAX_BLOCK_LENGTH];
	unsigned char doutbuf[ZCHUNK-EVP_MAX_BLOCK_LENGTH];

	z_stream zstrm;

	EVP_CIPHER_CTX *enc_ctx=NULL;

	// Checksum stuff
	//MD5_CTX md5;
	//unsigned char checksum[MD5_DIGEST_LENGTH+1];

//logp("in transfer_gzfile_in\n");

#ifdef HAVE_WIN32
	if(sb && sb->cmd==CMD_EFS_FILE)
		return transfer_efs_in(bfd, rcvd, sent, cntr);
#endif

	//if(!MD5_Init(&md5))
	//{
	//	logp("MD5_Init() failed");
	//	return -1;
	//}

	zstrm.zalloc=Z_NULL;
	zstrm.zfree=Z_NULL;
	zstrm.opaque=Z_NULL;
	zstrm.avail_in=0;
	zstrm.next_in=Z_NULL;

	if(inflateInit2(&zstrm, (15+16)))
	{
		logp("unable to init inflate\n");
		return -1;
	}

	if(encpassword && !(enc_ctx=enc_setup(0, encpassword)))
	{
		inflateEnd(&zstrm);
		return -1;
	}

	while(!quit)
	{
		if(async_read(&cmd, &buf, &len))
		{
			if(enc_ctx)
			{
				EVP_CIPHER_CTX_cleanup(enc_ctx);
				free(enc_ctx);
			}
			inflateEnd(&zstrm);
			return -1;
		}
		(*rcvd)+=len;

		//logp("transfer in: %c:%s\n", cmd, buf);
		switch(cmd)
		{
			case CMD_APPEND: // append
				if(!fp && !bfd && !metadata)
				{
					logp("given append, but no file or metadata to write to\n");
					async_write_str(CMD_ERROR, "append with no file or metadata");
					quit++; ret=-1;
				}
				else
				{
					size_t lentouse;
					unsigned char *buftouse=NULL;
/*
					if(!MD5_Update(&md5, buf, len))
					{
						logp("MD5 update enc error\n");
						quit++; ret=-1;
						break;
					}
*/
					// If doing decryption, it needs
					// to be done before uncompressing.
					if(enc_ctx)
					{
					  // updating our checksum needs to
					  // be done first
/*
					  if(!MD5_Update(&md5, buf, len))
					  {
						logp("MD5 update enc error\n");
						quit++; ret=-1;
						break;
					  }
					  else 
*/
					  if(!EVP_CipherUpdate(enc_ctx,
						doutbuf, (int *)&doutlen,
						(unsigned char *)buf,
						len))
					  {
						logp("Decryption error\n");
						quit++; ret=-1;
					  	break;
					  }
					  if(!doutlen) break;
					  lentouse=doutlen;
					  buftouse=doutbuf;
					}
					else
					{
					  lentouse=len;
					  buftouse=(unsigned char *)buf;
					}
					//logp("want to write: %d\n", zstrm.avail_in);

					if(do_inflate(&zstrm, bfd, fp, out,
						buftouse, lentouse, metadata,
						encpassword,
						enccompressed,
						sent))
					{
						ret=-1; quit++;
						break;
					}
				}
				break;
			case CMD_END_FILE: // finish up
				if(enc_ctx)
				{
					if(!EVP_CipherFinal_ex(enc_ctx,
						doutbuf, (int *)&doutlen))
					{
						logp("Decryption failure at the end.\n");
						ret=-1; quit++;
						break;
					}
					if(doutlen && do_inflate(&zstrm, bfd,
					  fp, out, doutbuf, doutlen, metadata,
					  encpassword,
					  enccompressed, sent))
					{
						ret=-1; quit++;
						break;
					}
				}
/*
				if(MD5_Final(checksum, &md5))
				{
					char *oldsum=NULL;
					const char *newsum=NULL;

					if((oldsum=strchr(buf, ':')))
					{
						oldsum++;
						newsum=get_checksum_str(checksum);
						// log if the checksum differed
						if(strcmp(newsum, oldsum))
							logw(cntr, "md5sum for '%s' did not match! (%s!=%s)\n", path, newsum, oldsum);
					}
				}
				else
				{
					logp("MD5_Final() failed\n");
				}
*/
				quit++;
				ret=0;
				break;
			case CMD_WARNING:
				logp("WARNING: %s\n", buf);
				do_filecounter(cntr, cmd, 0);
				break;
			default:
				logp("unknown append cmd: %c\n", cmd);
				quit++;
				ret=-1;
				break;
		}
		if(buf) free(buf);
		buf=NULL;
	}
	inflateEnd(&zstrm);
	if(enc_ctx)
	{
		EVP_CIPHER_CTX_cleanup(enc_ctx);
		free(enc_ctx);
	}

	if(ret) logp("transfer file returning: %d\n", ret);
	return ret;
}
예제 #27
0
// returns 1 for finished ok.
static int do_stuff_to_receive(struct sbuf *rb, FILE *p2fp, const char *datadirtmp, struct dpth *dpth, const char *working, char **last_requested, const char *deltmppath, struct cntr *cntr, struct config *cconf)
{
	int ret=0;
	char rcmd;
	size_t rlen=0;
	size_t wlen=0;
	char *rbuf=NULL;

	// This also attempts to write anything in the write buffer.
	if(async_rw(&rcmd, &rbuf, &rlen, '\0', NULL, &wlen))
	{
		logp("error in async_rw\n");
		return -1;
	}

	if(rbuf)
	{
		if(rcmd==CMD_WARNING)
		{
			logp("WARNING: %s\n", rbuf);
			do_filecounter(cntr, rcmd, 0);
		}
		else if(rb->fp || rb->zp)
		{
			// Currently writing a file (or meta data)
			if(rcmd==CMD_APPEND)
			{
				int app;
				//logp("rlen: %d\n", rlen);
				if((rb->zp
				  && (app=gzwrite(rb->zp, rbuf, rlen))<=0)
				|| (rb->fp
				  && (app=fwrite(rbuf, 1, rlen, rb->fp))<=0))
				{
					logp("error when appending: %d\n", app);
					async_write_str(CMD_ERROR, "write failed");
					ret=-1;
				}
				do_filecounter_recvbytes(cntr, rlen);
			}
			else if(rcmd==CMD_END_FILE)
			{
				// Finished the file.
				// Write it to the phase2 file, and free the
				// buffers.

				if(close_fp(&(rb->fp)))
				{
					logp("error closing delta for %s in receive\n", rb->path);
					ret=-1;
				}
				if(gzclose_fp(&(rb->zp)))
				{
					logp("error gzclosing delta for %s in receive\n", rb->path);
					ret=-1;
				}
				rb->endfile=rbuf;
				rb->elen=rlen;
				rbuf=NULL;
				if(!ret && rb->receivedelta
				  && finish_delta(rb, working, deltmppath))
					ret=-1;
				else if(!ret)
				{
					if(sbuf_to_manifest(rb, p2fp, NULL))
						ret=-1;
					else
					{
					  char cmd=rb->cmd;
					  if(rb->receivedelta)
						do_filecounter_changed(cntr,
							cmd);
					  else
						do_filecounter(cntr, cmd, 0);
					  if(*last_requested
					  && !strcmp(rb->path, *last_requested))
					  {
						free(*last_requested);
						*last_requested=NULL;
					  }
					}
				}

				if(!ret)
				{
					char *cp=NULL;
					cp=strchr(rb->endfile, ':');
					if(rb->endfile)
					 do_filecounter_bytes(cntr,
					  strtoull(rb->endfile, NULL, 10));
					if(cp)
					{
						// checksum stuff goes here
					}
				}

				free_sbuf(rb);
			}
			else
			{
				logp("unexpected cmd from client while writing file: %c %s\n", rcmd, rbuf);
				ret=-1;
			}
		}
		// Otherwise, expecting to be told of a file to save.
		else if(rcmd==CMD_DATAPTH)
		{
			rb->datapth=rbuf;
			rbuf=NULL;
		}
		else if(rcmd==CMD_STAT)
		{
			rb->statbuf=rbuf;
			rb->slen=rlen;
			rbuf=NULL;
		}
		else if(filedata(rcmd))
		{
			rb->cmd=rcmd;
			rb->plen=rlen;
			rb->path=rbuf;
			rbuf=NULL;

			if(rb->datapth)
			{
				// Receiving a delta.
				if(start_to_receive_delta(rb,
				  working, deltmppath, cconf))
				{
					logp("error in start_to_receive_delta\n");
					ret=-1;
				}
			}
			else
			{
				// Receiving a whole new file.
				if(start_to_receive_new_file(rb,
					datadirtmp, dpth, cntr, cconf))
				{
					logp("error in start_to_receive_new_file\n");
					ret=-1;
				}
			}
		}
		else if(rcmd==CMD_GEN && !strcmp(rbuf, "okbackupphase2end"))
		{
			ret=1;
			//logp("got okbackupphase2end\n");
		}
		else if(rcmd==CMD_INTERRUPT)
		{
			// Interrupt - forget about the last requested file
			// if it matches. Otherwise, we can get stuck on the
			// select in the async stuff, waiting for something
			// that will never arrive.
			if(*last_requested && !strcmp(rbuf, *last_requested))
			{
				free(*last_requested);
				*last_requested=NULL;
			}
		}
		else
		{
			logp("unexpected cmd from client while expecting a file: %c %s\n", rcmd, rbuf);
			ret=-1;
		}

		if(rbuf) { free(rbuf); rbuf=NULL; }
	}

	//logp("returning: %d\n", ret);
	return ret;
}
예제 #28
0
파일: restore_server.c 프로젝트: fenio/burp
int do_restore_server(const char *basedir, const char *backup, const char *restoreregex, enum action act, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf)
{
	int a=0;
	int i=0;
	int ret=0;
	int found=0;
	struct bu *arr=NULL;
	unsigned long index=0;
	char *tmppath1=NULL;
	char *tmppath2=NULL;
	regex_t *regex=NULL;
	bool all=FALSE;

	logp("in do_restore\n");

	if(compile_regex(&regex, restoreregex)) return -1;

	if(!(tmppath1=prepend_s(basedir, "tmp1", strlen("tmp1")))
	  || !(tmppath2=prepend_s(basedir, "tmp2", strlen("tmp2"))))
	{
		if(tmppath1) free(tmppath1);
		if(regex) { regfree(regex); free(regex); }
		return -1;
	}

	if(get_current_backups(basedir, &arr, &a, 1))
	{
		if(tmppath1) free(tmppath1);
		if(tmppath2) free(tmppath2);
		if(regex) { regfree(regex); free(regex); }
		return -1;
	}

	if(backup && *backup=='a')
	{
		all=TRUE;
	}
	else if(!(index=strtoul(backup, NULL, 10)) && a>0)
	{
		// No backup specified, do the most recent.
		ret=restore_manifest(arr, a, a-1,
			tmppath1, tmppath2, regex, act, client,
			p1cntr, cntr, cconf, all);
		found=TRUE;
	}

	if(!found) for(i=0; i<a; i++)
	{
		if(all || !strcmp(arr[i].timestamp, backup)
			|| arr[i].index==index)
		{
			found=TRUE;
			//logp("got: %s\n", arr[i].path);
			ret|=restore_manifest(arr, a, i,
				tmppath1, tmppath2, regex, act, client,
				p1cntr, cntr, cconf, all);
			if(!all) break;
		}
	}

	// If doing all backups, send restore end.
	if(!ret && all && found)
		ret=do_restore_end(act, cntr);

	free_current_backups(&arr, a);

	if(!found)
	{
		logp("backup not found\n");
		async_write_str(CMD_ERROR, "backup not found");
		ret=-1;
	}
	if(tmppath1)
	{
		unlink(tmppath1);
		free(tmppath1);
	}
	if(tmppath2)
	{
		unlink(tmppath2);
		free(tmppath2);
	}
	if(regex)
	{
		regfree(regex);
		free(regex);
	}
	return ret;
}
예제 #29
0
int send_file(FF_PKT *ff, bool top_level, struct config *conf, struct cntr *p1cntr)
{
   char msg[128]="";
   char attribs[MAXSTRING];

   if(!file_is_included(conf->incexcdir, conf->iecount,
	conf->incext, conf->incount,
	conf->excext, conf->excount,
	conf->increg, conf->ircount,
	conf->excreg, conf->ercount,
	ff->fname, top_level)) return 0;
#ifdef HAVE_WIN32
// Useful Windows attributes debug
/*
	printf("\n%llu", ff->winattr);
	printf("\n%s\n", ff->fname);
if(ff->winattr & FILE_ATTRIBUTE_READONLY) printf("readonly\n");
if(ff->winattr & FILE_ATTRIBUTE_HIDDEN) printf("hidden\n");
if(ff->winattr & FILE_ATTRIBUTE_SYSTEM) printf("system\n");
if(ff->winattr & FILE_ATTRIBUTE_DIRECTORY) printf("directory\n");
if(ff->winattr & FILE_ATTRIBUTE_ARCHIVE) printf("archive\n");
if(ff->winattr & FILE_ATTRIBUTE_DEVICE) printf("device\n");
if(ff->winattr & FILE_ATTRIBUTE_NORMAL) printf("normal\n");
if(ff->winattr & FILE_ATTRIBUTE_TEMPORARY) printf("temporary\n");
if(ff->winattr & FILE_ATTRIBUTE_SPARSE_FILE) printf("sparse\n");
if(ff->winattr & FILE_ATTRIBUTE_REPARSE_POINT) printf("reparse\n");
if(ff->winattr & FILE_ATTRIBUTE_COMPRESSED) printf("compressed\n");
if(ff->winattr & FILE_ATTRIBUTE_OFFLINE) printf("offline\n");
if(ff->winattr & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) printf("notcont\n");
if(ff->winattr & FILE_ATTRIBUTE_ENCRYPTED) printf("encrypted\n");
if(ff->winattr & FILE_ATTRIBUTE_VIRTUAL) printf("virtual\n");
*/
	if(ff->winattr & FILE_ATTRIBUTE_ENCRYPTED)
	{
//		if(ff->type!=FT_DIREND)
//			logw(p1cntr, "EFS not yet supported: %s", ff->fname);
//		return 0;

		if(ff->type==FT_REGE
		  || ff->type==FT_REG
		  || ff->type==FT_DIRBEGIN)
		{
			encode_stat(attribs,
				&ff->statp, ff->winattr, conf->compression);
			if(async_write_str(CMD_STAT, attribs)
			  || async_write_str(CMD_EFS_FILE, ff->fname))
				return -1;
			do_filecounter(p1cntr, CMD_EFS_FILE, 1);
			if(ff->type==FT_REG)
				do_filecounter_bytes(p1cntr,
					(unsigned long long)ff->statp.st_size);
			return 0;
		}
		else if(ff->type==FT_DIREND)
			return 0;
		else
		{
			// Hopefully, here is never reached.
			logw(p1cntr, "EFS type %d not yet supported: %s",
				ff->type,
				ff->fname);
			return 0;
		}
	}
#endif

   //logp("%d: %s\n", ff->type, ff->fname);

   switch (ff->type) {
   case FT_LNKSAVED:
        //printf("Lnka: %s -> %s\n", ff->fname, ff->link);
   	encode_stat(attribs, &ff->statp, ff->winattr, conf->compression);
	if(async_write_str(CMD_STAT, attribs)
	  || async_write_str(CMD_HARD_LINK, ff->fname)
	  || async_write_str(CMD_HARD_LINK, ff->link))
		return -1;
	do_filecounter(p1cntr, CMD_HARD_LINK, 1);
	// At least FreeBSD 8.2 can have different xattrs on hard links.
	if(maybe_send_extrameta(ff->fname, CMD_HARD_LINK, attribs, p1cntr))
		return -1;
      break;
   case FT_FIFO:
   case FT_REGE:
   case FT_REG:
      encode_stat(attribs, &ff->statp, ff->winattr,
		in_exclude_comp(conf->excom, conf->excmcount,
			ff->fname, conf->compression));
      if(async_write_str(CMD_STAT, attribs)
	|| async_write_str(filesymbol, ff->fname))
		return -1;
      do_filecounter(p1cntr, filesymbol, 1);
      if(ff->type==FT_REG)
	do_filecounter_bytes(p1cntr, (unsigned long long)ff->statp.st_size);
      if(maybe_send_extrameta(ff->fname, filesymbol, attribs, p1cntr))
		return -1;
      break;
   case FT_LNK:
	//printf("link: %s -> %s\n", ff->fname, ff->link);
   	encode_stat(attribs, &ff->statp, ff->winattr, conf->compression);
	if(async_write_str(CMD_STAT, attribs)
	  || async_write_str(CMD_SOFT_LINK, ff->fname)
	  || async_write_str(CMD_SOFT_LINK, ff->link))
		return -1;
	do_filecounter(p1cntr, CMD_SOFT_LINK, 1);
        if(maybe_send_extrameta(ff->fname, CMD_SOFT_LINK, attribs, p1cntr))
		return -1;
      break;
   case FT_DIREND:
      return 0;
   case FT_NOFSCHG:
   case FT_DIRBEGIN:
   case FT_REPARSE:
   case FT_JUNCTION:
	{
         char errmsg[100] = "";
         if (ff->type == FT_NOFSCHG)
            snprintf(errmsg, sizeof(errmsg), _("\t[will not descend: file system change not allowed]"));
	 if(*errmsg)
	 {
		snprintf(msg, sizeof(msg),
			"%s%s%s\n", "Dir: ", ff->fname, errmsg);
		logw(p1cntr, "%s", msg);
	 }
	 else
	 {
		encode_stat(attribs,
			&ff->statp, ff->winattr, conf->compression);
	      	if(async_write_str(CMD_STAT, attribs)) return -1;
#if defined(WIN32_VSS)
		if(async_write_str(filesymbol, ff->fname)) return -1;
		do_filecounter(p1cntr, filesymbol, 1);
#else
		if(async_write_str(CMD_DIRECTORY, ff->fname)) return -1;
		do_filecounter(p1cntr, CMD_DIRECTORY, 1);
        	if(maybe_send_extrameta(ff->fname, CMD_DIRECTORY,
			attribs, p1cntr)) return -1;
#endif
	 }
	}
      break;
   case FT_SPEC: // special file - fifo, socket, device node...
      encode_stat(attribs, &ff->statp, ff->winattr, conf->compression);
      if(async_write_str(CMD_STAT, attribs)
	  || async_write_str(CMD_SPECIAL, ff->fname))
		return -1;
      do_filecounter(p1cntr, CMD_SPECIAL, 1);
      if(maybe_send_extrameta(ff->fname, CMD_SPECIAL, attribs, p1cntr))
		return -1;
      break;
   case FT_NOACCESS:
      logw(p1cntr, _("Err: Could not access %s: %s"), ff->fname, strerror(errno));
      break;
   case FT_NOFOLLOW:
      logw(p1cntr, _("Err: Could not follow ff->link %s: %s"), ff->fname, strerror(errno));
      break;
   case FT_NOSTAT:
      logw(p1cntr, _("Err: Could not stat %s: %s"), ff->fname, strerror(errno));
      break;
   case FT_NOCHG:
      logw(p1cntr, _("Skip: File not saved. No change. %s"), ff->fname);
      break;
   case FT_ISARCH:
      logw(p1cntr, _("Err: Attempt to backup archive. Not saved. %s"), ff->fname);
      break;
   case FT_NOOPEN:
      logw(p1cntr, _("Err: Could not open directory %s: %s"), ff->fname, strerror(errno));
      break;
   case FT_RAW:
      logw(p1cntr, _("Err: Raw partition: %s"), ff->fname);
      break;
   default:
      logw(p1cntr, _("Err: Unknown file ff->type %d: %s"), ff->type, ff->fname);
      break;
   }
   return 0;
}
예제 #30
0
int backup_phase2_server(gzFile *cmanfp, const char *phase1data, const char *phase2data, const char *unchangeddata, const char *datadirtmp, struct dpth *dpth, const char *currentdata, const char *working, const char *client, struct cntr *p1cntr, int resume, struct cntr *cntr, struct config *cconf)
{
	int ars=0;
	int ret=0;
	gzFile p1zp=NULL;
	char *deltmppath=NULL;
	char *last_requested=NULL;
	// Where to write phase2data.
	// Data is not getting written to a compressed file.
	// This is important for recovery if the power goes.
	FILE *p2fp=NULL;
	// unchanged data
	FILE *ucfp=NULL;
	int resume_partial=resume;

	struct sbuf cb;		// file list in current manifest
	struct sbuf p1b;	// file list from client

	struct sbuf rb;		// receiving file from client

	init_sbuf(&cb);
	init_sbuf(&p1b);
	init_sbuf(&rb);

	if(!(p1zp=gzopen_file(phase1data, "rb")))
		goto error;

	// Open in read+write mode, so that they can be read through if
	// we need to resume.
	// First, open them in a+ mode, so that they will be created if they
	// do not exist.
	if(!(ucfp=open_file(unchangeddata, "a+b")))
		goto error;
	if(!(p2fp=open_file(phase2data, "a+b")))
		goto error;
	close_fp(&ucfp);
	close_fp(&p2fp);

	if(!(ucfp=open_file(unchangeddata, "r+b")))
		goto error;
	if(!(p2fp=open_file(phase2data, "r+b")))
		goto error;

	if(resume && do_resume(p1zp, p2fp, ucfp, dpth, cconf, client,
		p1cntr, cntr)) goto error;

	logp("Begin phase2 (receive file data)\n");

	if(!(deltmppath=prepend_s(working, "delta.tmp", strlen("delta.tmp"))))
		goto error;

	while(1)
	{
		int sts=0;
	//	logp("in loop, %s %s %c\n",
	//		*cmanfp?"got cmanfp":"no cmanfp",
	//		rb.path?:"no rb.path", rb.path?'X':rb.cmd);
		if(rb.path) write_status(client, STATUS_BACKUP,
			rb.path, p1cntr, cntr);
		else write_status(client, STATUS_BACKUP,
			p1b.path, p1cntr, cntr);
		if((last_requested || !p1zp || writebuflen)
		  && (ars=do_stuff_to_receive(&rb, p2fp, datadirtmp, dpth,
			working, &last_requested, deltmppath, cntr, cconf)))
		{
			if(ars<0) goto error;
			// 1 means ok.
			break;
		}

		if((sts=do_stuff_to_send(&p1b, &last_requested))<0)
			goto error;

		if(!sts && p1zp)
		{
		   free_sbuf(&p1b);

		   if((ars=sbuf_fill_phase1(NULL, p1zp, &p1b, cntr)))
		   {
			if(ars<0) goto error;
			// ars==1 means it ended ok.
			gzclose_fp(&p1zp);
			//logp("ended OK - write phase2end");
			if(async_write_str(CMD_GEN, "backupphase2end"))
				goto error;
		   }

		   //logp("check: %s\n", p1b.path);

		   if(!*cmanfp)
		   {
			// No old manifest, need to ask for a new file.
			//logp("no cmanfp\n");
			if(process_new(&p1b, ucfp, currentdata,
				datadirtmp, deltmppath,
				dpth, &resume_partial,
				cntr, cconf)) goto error;
		   }
		   else
		   {
			// Have an old manifest, look for it there.

			// Might already have it, or be ahead in the old
			// manifest.
			if(cb.path)
			{
				if((ars=maybe_process_file(&cb, &p1b,
					ucfp, currentdata, datadirtmp,
					deltmppath, dpth, &resume_partial,
					cntr, cconf)))
				{
					if(ars<0) goto error;
					// Do not free it - need to send stuff.
					continue;
				}
				//free_sbuf(&p1b);
			}

			while(*cmanfp)
			{
				free_sbuf(&cb);
				if((ars=sbuf_fill(NULL, *cmanfp, &cb, cntr)))
				{
					// ars==1 means it ended ok.
					if(ars<0) goto error;
					gzclose_fp(cmanfp);
		//logp("ran out of current manifest\n");
					if(process_new(&p1b, ucfp,
						currentdata, datadirtmp,
						deltmppath, dpth,
						&resume_partial, cntr, cconf))
							goto error;
					break;
				}
		//logp("against: %s\n", cb.path);
				if((ars=maybe_process_file(&cb, &p1b,
					ucfp, currentdata, datadirtmp,
					deltmppath, dpth, &resume_partial,
					cntr, cconf)))
				{
					if(ars<0) goto error;
					// Do not free it - need to send stuff.
					break;
				}
			}
		   }
		}
	}

	goto end;

error:
	ret=-1;
end:
	if(close_fp(&p2fp))
	{
		logp("error closing %s in backup_phase2_server\n",
			phase2data);
		ret=-1;
	}
	if(close_fp(&ucfp))
	{
		logp("error closing %s in backup_phase2_server\n",
			unchangeddata);
		ret=-1;
	}
	free(deltmppath);
	free_sbuf(&cb);
	free_sbuf(&p1b);
	free_sbuf(&rb);
	gzclose_fp(&p1zp);
	if(!ret) unlink(phase1data);

	logp("End phase2 (receive file data)\n");

	return ret;
}