Beispiel #1
0
static int working_resume(struct async *as, struct sdirs *sdirs,
	const char *incexc, int *resume, struct conf **cconfs)
{
	if(get_string(cconfs[OPT_RESTORE_CLIENT]))
	{
		// This client is not the original client, resuming might cause
		// all sorts of trouble.
		log_and_send(as->asfd, "Found interrupted backup - not resuming because the connected client is not the original");
		return -1;
	}

	logp("Found interrupted backup.\n");

	// Check that the current incexc configuration is the same
	// as before.
	switch(incexc_matches(sdirs->rworking, incexc))
	{
		case 1:
			// Attempt to resume on the next backup.
			logp("Will resume on the next backup request.\n");
			*resume=1;
			return 0;
		case 0:
			logp("Includes/excludes changed since last backup.\n");
			logp("Will delete instead of resuming.\n");
			return working_delete(as, sdirs, cconfs);
		case -1:
		default:
			return -1;
	}
}
Beispiel #2
0
int check_for_rubble_burp2(struct asfd *asfd, struct sdirs *sdirs,
	const char *incexc, int *resume, struct conf *cconf)
{
	// FIX THIS - currently just deletes the interrupted backup.
	ssize_t len=0;
	char *real=NULL;
	char lnk[32]="";
	if((len=readlink(sdirs->working, lnk, sizeof(lnk)-1))<0)
		return 0;
	else if(!len)
	{
		unlink(sdirs->working);
		return 0;
	}
	lnk[len]='\0';
	if(!(real=prepend_s(sdirs->client, lnk)))
	{
		log_and_send_oom(asfd, __func__);
		return -1;
	}
	if(recursive_delete(real, "", 1))
	{
		char msg[256]="";
		snprintf(msg, sizeof(msg),
			"Could not remove interrupted directory: %s", real);
		log_and_send(asfd, msg);
		return -1;
	}
	unlink(sdirs->working);
	return 0;
}
Beispiel #3
0
static int start_to_receive_new_file(struct asfd *asfd,
	struct sdirs *sdirs, struct conf **cconfs,
	struct sbuf *sb, struct dpth *dpth)
{
	int ret=-1;
	char *rpath=NULL;
	int istreedata=0;

//logp("start to receive: %s\n", sb->path.buf);

	if(!(rpath=set_new_datapth(asfd,
		sdirs, cconfs, sb, dpth, &istreedata)))
			goto end;
	
	if(!(sb->protocol1->fzp=fzp_open(rpath, "wb")))
	{
		log_and_send(asfd, "make file failed");
		goto end;
	}
	if(!istreedata) dpth_incr(dpth);
	ret=0;
end:
	free_w(&rpath);
	return ret;
}
Beispiel #4
0
static char *set_new_datapth(struct sbuf *sb, const char *datadirtmp, struct dpth *dpth, int *istreedata, struct config *cconf)
{
	char *rpath=NULL;
	if(cconf->directory_tree) *istreedata=treedata(sb);

	if(*istreedata)
	{
		// We want to place this file in a directory structure like
		// the directory structure on the original client.
		if(!(sb->datapth=prepend_s("t", sb->path, strlen(sb->path))))
		{
			log_and_send_oom(__FUNCTION__);
			return NULL;
		}
	}
	else
	{
		mk_dpth(dpth, cconf, sb->cmd);
		if(!(sb->datapth=strdup(dpth->path))) // file data path
		{
			log_and_send_oom(__FUNCTION__);
			return NULL;
		}
	}
	if(build_path(datadirtmp, sb->datapth, strlen(sb->datapth),
		&rpath, datadirtmp))
	{
		log_and_send("build path failed");
		return NULL;
	}
	return rpath;
}
Beispiel #5
0
static char *set_new_datapth(struct asfd *asfd,
	struct sdirs *sdirs, struct conf **cconfs,
	struct sbuf *sb, struct dpth *dpth, int *istreedata)
{
	char *tmp=NULL;
	char *rpath=NULL;
	if(get_int(cconfs[OPT_DIRECTORY_TREE]))
		*istreedata=treedata(sb, cconfs);

	if(*istreedata)
	{
		// We want to place this file in a directory structure like
		// the directory structure on the original client.
		if(!(tmp=prepend_s(TREE_DIR, sb->path.buf)))
		{
			log_and_send_oom(asfd, __func__);
			return NULL;
		}
	}
	else
	{
		if(!(tmp=strdup_w(dpth_protocol1_mk(dpth,
			get_int(cconfs[OPT_COMPRESSION]),
			sb->path.cmd), __func__))) return NULL;
	}
	iobuf_from_str(&sb->protocol1->datapth, CMD_DATAPTH, tmp);
	if(build_path(sdirs->datadirtmp,
		sb->protocol1->datapth.buf, &rpath, sdirs->datadirtmp))
	{
		log_and_send(asfd, "build path failed");
		return NULL;
	}
	return rpath;
}
Beispiel #6
0
// Return 1 if the backup is now finalising.
int check_for_rubble(struct async *as,
	struct sdirs *sdirs, const char *incexc,
	int *resume, struct conf **cconfs)
{
	struct asfd *asfd=as->asfd;

	switch(is_lnk(sdirs->finishing))
	{
		case 1:
			if(recover_finishing(as, sdirs, cconfs))
				return -1;
			return 1;
		case 0:
			log_and_send(asfd,
				"Finishing directory is not a symlink.\n");
			return -1;
	}

	switch(is_lnk(sdirs->working))
	{
		case 1:
			return recover_working(as,
				sdirs, incexc, resume, cconfs);
		case 0:
			log_and_send(asfd,
				"Working directory is not a symlink.\n");
			return -1;
	}

	switch(is_lnk(sdirs->currenttmp))
	{
		case 1:
			return recover_currenttmp(sdirs);
		case 0:
			log_and_send(asfd,
				"Currenttmp directory is not a symlink.\n");
			return -1;
	}

	return 0;
}
Beispiel #7
0
Datei: child.c Projekt: vshn/burp
static int run_server_script(struct asfd *asfd,
	const char *pre_or_post,
	const char *script, struct strlist *script_arg,
	uint8_t notify, struct conf **cconfs, int backup_ret, int timer_ret)
{
	int a=0;
	int ret=0;
	char *logbuf=NULL;
	const char *args[12];
	struct iobuf *rbuf=asfd->rbuf;
	const char *cname=get_string(cconfs[OPT_CNAME]);

	args[a++]=script;
	args[a++]=pre_or_post;
	args[a++]=rbuf->buf?rbuf->buf:"", // Action requested by client.
	args[a++]=cname;
	args[a++]=backup_ret?"1":"0", // Indicate success or failure.
	// Indicate whether the timer script said OK or not.
	args[a++]=timer_ret?"1":"0",
	args[a++]=NULL;

	// Do not have a client storage directory, so capture the
	// output in a buffer to pass to the notification script.
	if(run_script_to_buf(asfd, args, script_arg, cconfs, 1, 1, 0, &logbuf))
	{
		char msg[256];
		snprintf(msg, sizeof(msg),
			"server %s script %s returned an error",
			pre_or_post, script);
		log_and_send(asfd, msg);
		ret=-1;
		if(!notify) goto end;

		a=0;
		args[a++]=get_string(cconfs[OPT_N_FAILURE_SCRIPT]);
		args[a++]=cname;
		// magic - set basedir blank and the
		// notify script will know to get the content
		// from the next argument (usually storagedir)
		args[a++]=""; // usually basedir
		args[a++]=logbuf?logbuf:""; //usually storagedir
		args[a++]=""; // usually file
		args[a++]=""; // usually brv
		args[a++]=""; // usually warnings
		args[a++]=NULL;
		run_script(asfd, args, get_strlist(cconfs[OPT_N_FAILURE_ARG]),
			cconfs, 1, 1, 0);
	}
end:
	free_w(&logbuf);
	return ret;
}
Beispiel #8
0
// Return 1 if the backup is now finalising.
int check_for_rubble(struct async *as,
	struct sdirs *sdirs, const char *incexc,
	int *resume, struct conf **cconfs)
{
	struct stat statp;
	struct asfd *asfd=as->asfd;

	if(!lstat(sdirs->finishing, &statp))
	{
		if(S_ISLNK(statp.st_mode))
		{
			if(recover_finishing(as, sdirs, cconfs))
				return -1;
			return 1;
		}
		log_and_send(asfd, "Finishing directory is not a symlink.\n");
		return -1;
	}

	if(!lstat(sdirs->working, &statp))
	{
		if(S_ISLNK(statp.st_mode))
			return recover_working(as,
				sdirs, incexc, resume, cconfs);
		log_and_send(asfd, "Working directory is not a symlink.\n");
		return -1;
	}

	if(!lstat(sdirs->currenttmp, &statp))
	{
		if(S_ISLNK(statp.st_mode))
			return recover_currenttmp(sdirs);
		log_and_send(asfd, "Currenttmp directory is not a symlink.\n");
		return -1;
	}

	return 0;
}
Beispiel #9
0
static int working_delete(struct async *as, struct sdirs *sdirs)
{
	// Try to remove it and start again.
	logp("deleting old working directory\n");
	if(recursive_delete(sdirs->rworking))
	{
		log_and_send(as->asfd,
			"Old working directory is in the way.\n");
		return -1;
	}
	// Get rid of the symlink.
	unlink(sdirs->working);
	return 0;
}
Beispiel #10
0
static int setup_cntr(struct asfd *asfd, const char *manifest,
        regex_t *regex, int srestore,
        enum action act, char status, struct conf **cconfs)
{
	int ars=0;
	int ret=-1;
	struct fzp *fzp=NULL;
	struct sbuf *sb=NULL;
	struct cntr *cntr=get_cntr(cconfs);

// FIX THIS: this is only trying to work for protocol1.
	if(get_protocol(cconfs)!=PROTO_1) return 0;

	if(!(sb=sbuf_alloc(PROTO_1))) goto end;
	if(!(fzp=fzp_gzopen(manifest, "rb")))
	{
		log_and_send(asfd, "could not open manifest");
		goto end;
	}
	while(1)
	{
		if((ars=sbuf_fill_from_file(sb, fzp, NULL, NULL)))
		{
			if(ars<0) goto end;
			// ars==1 means end ok
			break;
		}
		else
		{
			if(want_to_restore(srestore, sb, regex, cconfs))
			{
				cntr_add_phase1(cntr, sb->path.cmd, 0);
				if(sb->endfile.buf)
				  cntr_add_val(cntr,
					CMD_BYTES_ESTIMATED,
					strtoull(sb->endfile.buf,
						NULL, 10), 0);
			}
		}
		sbuf_free_content(sb);
	}
	ret=0;
end:
	sbuf_free(&sb);
	fzp_close(&fzp);
	return ret;
}
Beispiel #11
0
int list_server_init(
    struct asfd *a,
    struct sdirs *s,
    struct cntr *c,
    enum protocol p,
    const char *backup_str,
    const char *regex_str,
    const char *browsedir_str)
{
    asfd=a;
    cntr=c;
    protocol=p;
    backup=backup_str;
    browsedir=browsedir_str;
    if(bu_get_list(s, &bu_list))
        goto error;
    if(regex_str
            && *regex_str
            && !(regex=regex_compile(regex_str)))
    {
        char msg[256]="";
        snprintf(msg, sizeof(msg), "unable to compile regex: %s\n",
                 regex_str);
        log_and_send(asfd, msg);
        goto error;
    }
    list_mode=LIST_MODE_BACKUPS;
    if(regex || browsedir)
        list_mode=LIST_MODE_CONTENTS_MANY;
    if(backup && *backup)
    {
        if((bno=strtoul(backup, NULL, 10))>0)
            list_mode=LIST_MODE_CONTENTS_ONE;
        else if(*backup=='c')
            list_mode=LIST_MODE_CONTENTS_ONE;
        else if(*backup=='a')
            list_mode=LIST_MODE_CONTENTS_MANY;
        else
            list_mode=LIST_MODE_CONTENTS_ONE;
    }
    return 0;
error:
    list_server_free();
    return -1;
}
Beispiel #12
0
static int working_delete(struct async *as, struct sdirs *sdirs,
	struct conf **cconfs)
{
	// Try to remove it and start again.
	logp("deleting old working directory\n");
	if(get_protocol(cconfs)==PROTO_2)
	{
		logp("protocol 2 - unimplemented - need cleanup of data directory\n");
	}
	if(recursive_delete(sdirs->rworking))
	{
		log_and_send(as->asfd,
			"Old working directory is in the way.\n");
		return -1;
	}
	// Get rid of the symlink.
	unlink(sdirs->working);
	return 0;
}
Beispiel #13
0
static int start_to_receive_new_file(struct sbuf *sb, const char *datadirtmp, struct dpth *dpth, struct cntr *cntr, struct config *cconf)
{
	int ret=-1;
	char *rpath=NULL;
	int istreedata=0;

//logp("start to receive: %s\n", sb->path);

	if(!(rpath=set_new_datapth(sb, datadirtmp, dpth, &istreedata, cconf)))
		return -1;
	
	if(!(sb->fp=open_file(rpath, "wb")))
	{
		log_and_send("make file failed");
		if(rpath) free(rpath);
		return -1;
	}
	if(!istreedata) incr_dpth(dpth, cconf);
	if(rpath) free(rpath);
	return 0; 
}
Beispiel #14
0
int restore_switch_protocol1(struct asfd *asfd, struct sbuf *sb,
	const char *fullpath, enum action act,
	BFILE *bfd, int vss_restore, struct cntr *cntr,
	const char *encryption_password)
{
	switch(sb->path.cmd)
	{
		case CMD_FILE:
		case CMD_VSS_T:
		case CMD_ENC_FILE:
		case CMD_ENC_VSS_T:
		case CMD_EFS_FILE:
			if(!sb->protocol1->datapth.buf)
			{
				char msg[256];
				snprintf(msg, sizeof(msg),
				  "datapth not supplied for %c:%s in %s\n",
					sb->path.cmd, sb->path.buf, __func__);
				log_and_send(asfd, msg);
				return -1;
			}
			return restore_file_or_get_meta(asfd, bfd, sb,
				fullpath, act,
				NULL, NULL, vss_restore, cntr,
				encryption_password);
		case CMD_METADATA:
		case CMD_VSS:
		case CMD_ENC_METADATA:
		case CMD_ENC_VSS:
			return restore_metadata(asfd, bfd, sb,
				fullpath, act,
				vss_restore, cntr, encryption_password);
		default:
			// Other cases (dir/links/etc) are handled in the
			// calling function.
			logp("unknown cmd: %c\n", sb->path.cmd);
			return -1;
	}
}
Beispiel #15
0
static int start_to_receive_new_file(struct asfd *asfd,
	struct sdirs *sdirs, struct conf *cconf,
	struct sbuf *sb, struct dpthl *dpthl)
{
	char *rpath=NULL;
	int istreedata=0;

//logp("start to receive: %s\n", sb->path);

	if(!(rpath=set_new_datapth(asfd, sdirs, cconf, sb, dpthl, &istreedata)))
		return -1;
	
	if(!(sb->burp1->fp=open_file(rpath, "wb")))
	{
		log_and_send(asfd, "make file failed");
		if(rpath) free(rpath);
		return -1;
	}
	if(!istreedata) incr_dpthl(dpthl, cconf);
	if(rpath) free(rpath);
	return 0; 
}
Beispiel #16
0
static char *set_new_datapth(struct asfd *asfd,
	struct sdirs *sdirs, struct conf *cconf,
	struct sbuf *sb, struct dpthl *dpthl, int *istreedata)
{
	static char *tmp=NULL;
	char *rpath=NULL;
	if(cconf->directory_tree) *istreedata=treedata(sb);

	if(*istreedata)
	{
		// We want to place this file in a directory structure like
		// the directory structure on the original client.
		if(!(tmp=prepend_s("t", sb->path.buf)))
		{
			log_and_send_oom(asfd, __func__);
			return NULL;
		}
	}
	else
	{
		mk_dpthl(dpthl, cconf, sb->path.cmd);
		if(!(tmp=strdup(dpthl->path))) // file data path
		{
			log_and_send_oom(asfd, __func__);
			return NULL;
		}
	}
	iobuf_from_str(&sb->burp1->datapth, CMD_DATAPTH, tmp);
	if(build_path(sdirs->datadirtmp,
		sb->burp1->datapth.buf, &rpath, sdirs->datadirtmp))
	{
		log_and_send(asfd, "build path failed");
		return NULL;
	}
	return rpath;
}
Beispiel #17
0
// Return 0 for everything OK, signed and returned, -1 for error.
static int sign_client_cert(struct asfd *asfd,
	const char *client, struct conf *conf)
{
	int a=0;
	int ret=-1;
	char msg[256]="";
	char csrpath[512]="";
	char crtpath[512]="";
	struct stat statp;
	const char *args[15];
	csr_done=0;
	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(asfd, 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(asfd, 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(asfd, 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(asfd->write_str(asfd, 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(asfd, csrpath, conf)) 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);
	a=0;
	args[a++]=conf->ca_burp_ca;
	args[a++]="--name";
	args[a++]=client;
	args[a++]="--ca";
	args[a++]=conf->ca_name;
	args[a++]="--sign";
	args[a++]="--batch";
	args[a++]="--dir";
	args[a++]=gca_dir;
	args[a++]="--config";
	args[a++]=conf->ca_conf;
	args[a++]=NULL;
	if(run_script(asfd, args, NULL, conf, 1 /* wait */,
		0, 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(asfd, crtpath, conf))
		goto end;

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

	ret=0;
	csr_done++;
end:
	if(ret<0)
	{
		unlink(crtpath);
		unlink(csrpath);
	}
	return ret;
}
Beispiel #18
0
static int process_data_dir_file(struct asfd *asfd,
	struct bu *bu, struct bu *b, const char *path,
	struct sbuf *sb, enum action act, struct sdirs *sdirs,
	struct conf **cconfs)
{
	int ret=-1;
	int patches=0;
	char *dpath=NULL;
	struct stat dstatp;
	const char *tmp=NULL;
	const char *best=NULL;
	uint64_t bytes=0;
	static char *tmppath1=NULL;
	static char *tmppath2=NULL;
	struct cntr *cntr=NULL;
	if(cconfs) cntr=get_cntr(cconfs);

	if((!tmppath1 && !(tmppath1=prepend_s(sdirs->client, "tmp1")))
	  || (!tmppath2 && !(tmppath2=prepend_s(sdirs->client, "tmp2"))))
		goto end;

	best=path;
	tmp=tmppath1;
	// Now go down the list, applying any deltas.
	for(b=b->prev; b && b->next!=bu; b=b->prev)
	{
		free_w(&dpath);
		if(!(dpath=prepend_s(b->delta, sb->protocol1->datapth.buf)))
			goto end;

		if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode))
			continue;

		if(!patches)
		{
			// Need to gunzip the first one.
			if(inflate_or_link_oldfile(asfd, best, tmp,
				cconfs, sb->compression))
			{
				char msg[256]="";
				snprintf(msg, sizeof(msg),
				  "error when inflating %s\n", best);
				log_and_send(asfd, msg);
				goto end;
			}
			best=tmp;
			if(tmp==tmppath1) tmp=tmppath2;
			else tmp=tmppath1;
		}

		if(do_patch(asfd, best, dpath, tmp,
			0 /* do not gzip the result */,
			sb->compression /* from the manifest */, cconfs))
		{
			char msg[256]="";
			snprintf(msg, sizeof(msg), "error when patching %s\n",
				path);
			log_and_send(asfd, msg);
			goto end;
		}

		best=tmp;
		if(tmp==tmppath1) tmp=tmppath2;
		else tmp=tmppath1;
		unlink(tmp);
		patches++;
	}

	switch(act)
	{
		case ACTION_RESTORE:
			if(send_file(asfd, sb, patches, best, &bytes, cntr))
				goto end;
			break;
		case ACTION_VERIFY:
			if(verify_file(asfd, sb, patches, best, &bytes, cntr))
				goto end;
			break;
		default:
			logp("Unknown action: %d\n", act);
			goto end;
	}
	cntr_add(cntr, sb->path.cmd, 0);
	cntr_add_bytes(cntr, strtoull(sb->endfile.buf, NULL, 10));
	cntr_add_sentbytes(cntr, bytes);

	ret=0;
end:
	free_w(&dpath);
	return ret;
}
Beispiel #19
0
static int run_action_server_do(struct async *as, struct sdirs *sdirs,
	const char *incexc, int srestore, int *timer_ret, struct conf **cconfs)
{
	int ret;
	int resume=0;
	char msg[256]="";
	struct iobuf *rbuf=as->asfd->rbuf;

	// Make sure some directories exist.
	if(mkpath(&sdirs->current, sdirs->dedup))
	{
		snprintf(msg, sizeof(msg),
			"could not mkpath %s", sdirs->current);
		log_and_send(as->asfd, msg);
		return -1;
	}

	if(rbuf->cmd!=CMD_GEN) return unknown_command(as->asfd);

	// List and diff should work even while backups are running.
	if(!strncmp_w(rbuf->buf, "list ")
	  || !strncmp_w(rbuf->buf, "listb "))
		return run_list(as->asfd, sdirs, cconfs);

	if(!strncmp_w(rbuf->buf, "diff "))
		return run_diff(as->asfd, sdirs, cconfs);

	switch((ret=get_lock_sdirs(as->asfd, sdirs)))
	{
		case 0: break; // OK.
		case 1: return 1; // Locked out.
		default: // Error.
			maybe_do_notification(as->asfd, ret,
				"", "error in get_lock_sdirs()",
				"", buf_to_notify_str(rbuf), cconfs);
			return -1;
	}

	switch((ret=check_for_rubble(as, sdirs, incexc, &resume, cconfs)))
	{
		case 0: break; // OK.
		case 1: return 1; // Now finalising.
		default: // Error.
			maybe_do_notification(as->asfd, ret,
				"", "error in check_for_rubble()",
				"", buf_to_notify_str(rbuf), cconfs);
			return -1;
	}

	if(!strncmp_w(rbuf->buf, "backup"))
	{
		ret=run_backup(as, sdirs, cconfs, incexc, timer_ret, resume);
		if(*timer_ret<0)
			maybe_do_notification(as->asfd, ret, "",
				"error running timer script",
				"", "backup", cconfs);
		else if(!*timer_ret)
			maybe_do_notification(as->asfd, ret, sdirs->client,
				sdirs->current, "log", "backup", cconfs);
		return ret;
	}

	if(!strncmp_w(rbuf->buf, "restore ")
	  || !strncmp_w(rbuf->buf, "verify "))
		return run_restore(as->asfd, sdirs, cconfs, srestore);

	if(!strncmp_w(rbuf->buf, "Delete "))
		return run_delete(as->asfd, sdirs, cconfs);

	// Old clients will send 'delete', possibly accidentally due to the
	// user trying to use the new diff/long diff options.
	// Stop them from working, just to be safe.
	if(!strncmp_w(rbuf->buf, "delete "))
	{
		logp("old style delete from %s denied\n",
			get_string(cconfs[OPT_CNAME]));
		as->asfd->write_str(as->asfd, CMD_ERROR,
			"old style delete is not supported on this server");
		return -1;
	}

	return unknown_command(as->asfd);
}
Beispiel #20
0
int backup_phase4_server(const char *basedir, const char *working, const char *current, const char *currentdata, const char *finishing, struct config *cconf, const char *client, struct cntr *p1cntr, struct cntr *cntr)
{
	int ret=0;
	struct stat statp;
	char *manifest=NULL;
	char *datadir=NULL;
	char *datadirtmp=NULL;
	char *currentdup=NULL;
	char *currentduptmp=NULL;
	char *currentdupdata=NULL;
	char *forward=NULL;
	char *timestamp=NULL;
	char *fullrealcurrent=NULL;
	char *deleteme=NULL;
	char *logpath=NULL;
	char *hlinkedpath=NULL;
	int len=0;
	char realcurrent[256]="";
	FILE *logfp=NULL;

	if((len=readlink(current, realcurrent, sizeof(realcurrent)-1))<0)
		len=0;
	realcurrent[len]='\0';

	if(!(datadir=prepend_s(finishing, "data", strlen("data")))
	  || !(datadirtmp=prepend_s(finishing, "data.tmp", strlen("data.tmp")))
	  || !(manifest=prepend_s(finishing, "manifest.gz", strlen("manifest.gz")))
	  || !(currentdup=prepend_s(finishing, "currentdup", strlen("currentdup")))
	  || !(currentduptmp=prepend_s(finishing, "currentdup.tmp", strlen("currentdup.tmp")))
	  || !(currentdupdata=prepend_s(currentdup, "data", strlen("data")))
	  || !(forward=prepend_s(currentdup, "forward", strlen("forward")))
	  || !(timestamp=prepend_s(finishing, "timestamp", strlen("timestamp")))
	  || !(fullrealcurrent=prepend_s(basedir, realcurrent, strlen(realcurrent)))
	  || !(deleteme=prepend_s(basedir, "deleteme", strlen("deleteme")))
	  || !(logpath=prepend_s(finishing, "log", strlen("log")))
	  || !(hlinkedpath=prepend_s(currentdup, "hardlinked", strlen("hardlinked"))))
	{
		ret=-1;
		goto endfunc;
	}

	if(!(logfp=open_file(logpath, "ab")) || set_logfp(logfp, cconf))
	{
		ret=-1;
		goto endfunc;
	}

	logp("Begin phase4 (shuffle files)\n");

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

	if(!lstat(current, &statp)) // Had a previous backup
	{
		unsigned long bno=0;
		FILE *fwd=NULL;
		int hardlinked=0;
		char tstmp[64]="";
		int newdup=0;

		if(lstat(currentdup, &statp))
		{
			// Have not duplicated the current backup yet.
			if(!lstat(currentduptmp, &statp))
			{
				logp("Removing previous currentduptmp directory: %s\n", currentduptmp);
				if(recursive_delete(currentduptmp,
					NULL, TRUE /* del files */))
				{
					logp("Could not delete %s\n",
						currentduptmp);
					ret=-1;
					goto endfunc;
				}
			}
			logp("Duplicating current backup.\n");
			if(recursive_hardlink(current, currentduptmp, client,
				p1cntr, cntr, cconf)
			  || do_rename(currentduptmp, currentdup))
			{
				ret=-1;
				goto endfunc;
			}
			newdup++;
		}

		if(read_timestamp(timestamp, tstmp, sizeof(tstmp)))
		{
			logp("could not read timestamp file: %s\n", timestamp);
			ret=-1;
			goto endfunc;
		}
		// Get the backup number.
		bno=strtoul(tstmp, NULL, 10);

		// Put forward reference in, indicating the timestamp of
		// the working directory (which will soon become the current
		// directory).
		if(!(fwd=open_file(forward, "wb")))
		{
			log_and_send("could not create forward file");
			ret=-1;
			goto endfunc;
		}
		fprintf(fwd, "%s\n", tstmp);
		close_fp(&fwd);

		if(newdup)
		{
			// When we have just created currentdup, determine
			// hardlinked archive from the conf and the backup
			// number...
			hardlinked=do_hardlinked_archive(cconf, bno);
		}
		else
		{
			// ...if recovering, find out what currentdup started
			// out as.
			// Otherwise it is possible that things can be messed
			// up by somebody swapping between hardlinked and
			// not hardlinked at the same time as a resume happens.
			if(lstat(hlinkedpath, &statp))
			{
				logp("previous attempt started not hardlinked\n");
				hardlinked=0;
			}
			else
			{
				logp("previous attempt started hardlinked\n");
				hardlinked=1;
			}
		}

		if(hardlinked)
		{
			// Create a file to indicate that the previous backup
			// does not have others depending on it.
			FILE *hfp=NULL;
			if(!(hfp=open_file(hlinkedpath, "wb")))
			{
				ret=-1;
				goto endfunc;
			}
			// Stick the next backup timestamp in it. It might
			// be useful one day when wondering when the next
			// backup, now deleted, was made.
			fprintf(hfp, "%s\n", tstmp);
			close_fp(&hfp);
			logp(" doing hardlinked archive\n");
			logp(" will not generate reverse deltas\n");
		}
		else
		{
			logp(" not doing hardlinked archive\n");
			logp(" will generate reverse deltas\n");
			unlink(hlinkedpath);
		}

		if(atomic_data_jiggle(finishing,
			working, manifest, currentdup,
			currentdupdata,
			datadir, datadirtmp, cconf, client,
			hardlinked, bno, p1cntr, cntr))
		{
			logp("could not finish up backup.\n");
			ret=-1;
			goto endfunc;
		}

		write_status(client, STATUS_SHUFFLING,
			"deleting temporary files", p1cntr, cntr);

		// Remove the temporary data directory, we have now removed
		// everything useful from it.
		recursive_delete(datadirtmp, NULL, TRUE /* del files */);

		// Clean up the currentdata directory - this is now the 'old'
		// currentdata directory. Any files that were deleted from
		// the client will be left in there, so call recursive_delete
		// with the option that makes it not delete files.
		// This will have the effect of getting rid of unnecessary
		// directories.
		sync(); // try to help CIFS
		recursive_delete(currentdupdata, NULL, FALSE /* do not del files */);

		// Rename the old current to something that we know to
		// delete.
		if(do_rename(fullrealcurrent, deleteme))
		{
			ret=-1;
			goto endfunc;
		}
	}
	else
	{
		// No previous backup, just put datadirtmp in the right place.
		if(do_rename(datadirtmp, datadir))
		{
			ret=-1;
			goto endfunc;
		}
	}

	if(!lstat(deleteme, &statp))
	{
		// Rename the currentdup directory...
		// IMPORTANT TODO: read the path to fullrealcurrent
		// from the deleteme timestamp.
		do_rename(currentdup, fullrealcurrent);

		recursive_delete(deleteme, NULL, TRUE /* delete all */);
	}

	// Rename the finishing symlink so that it becomes the current symlink
	do_rename(finishing, current);

	print_filecounters(p1cntr, cntr, ACTION_BACKUP, 0);
	logp("Backup completed.\n");
	logp("End phase4 (shuffle files)\n");
	set_logfp(NULL, cconf); // will close logfp.

	compress_filename(current, "log", "log.gz", cconf);

endfunc:
	if(datadir) free(datadir);
	if(datadirtmp) free(datadirtmp);
	if(manifest) free(manifest);
	if(currentdup) free(currentdup);
	if(currentduptmp) free(currentduptmp);
	if(currentdupdata) free(currentdupdata);
	if(forward) free(forward);
	if(timestamp) free(timestamp);
	if(fullrealcurrent) free(fullrealcurrent);
	if(deleteme) free(deleteme);
	if(logpath) free(logpath);
	if(hlinkedpath) free(hlinkedpath);

	return ret;
}
Beispiel #21
0
int get_current_backups(const char *basedir, struct bu **arr, int *a, int log)
{
	int i=0;
	int j=0;
	int tr=0;
	int ret=0;
	DIR *d=NULL;
	char buf[32]="";
	char realwork[32]="";
	char realfinishing[32]="";
	struct dirent *dp=NULL;

	// Find out what certain directories really are, if they exist,
	// so they can be excluded.
	if(get_link(basedir, "working", realwork, sizeof(realwork))
	  || get_link(basedir, "finishing", realfinishing, sizeof(realfinishing)))
			return -1;
	if(!(d=opendir(basedir)))
	{
		if(log) log_and_send("could not open backup directory");
		return -1;
	}
	while((dp=readdir(d)))
	{
		int hardlinked=0;
		struct stat statp;
		char *fullpath=NULL;
		char *timestamp=NULL;
		char *timestampstr=NULL;
		char *hlinkedpath=NULL;

		if(dp->d_ino==0
		  || !strcmp(dp->d_name, ".")
		  || !strcmp(dp->d_name, "..")
		  || !strcmp(dp->d_name, realwork)
		  || !strcmp(dp->d_name, realfinishing))
			continue;
		if(!(fullpath=prepend_s(basedir,
			dp->d_name, strlen(dp->d_name)))
		 || !(timestamp=prepend_s(fullpath,
			"timestamp", strlen("timestamp")))
		 || !(hlinkedpath=prepend_s(fullpath,
			"hardlinked", strlen("hardlinked"))))
		{
			ret=-1;
			if(timestamp) free(timestamp);
			if(fullpath) free(fullpath);
			break;
		}
		if((!lstat(fullpath, &statp) && !S_ISDIR(statp.st_mode))
		  || lstat(timestamp, &statp) || !S_ISREG(statp.st_mode)
		  || read_timestamp(timestamp, buf, sizeof(buf))
		  || !(timestampstr=strdup(buf)))
		{
			free(fullpath);
			free(timestamp);
			free(hlinkedpath);
			continue;
		}
		free(timestamp);

		if(!lstat(hlinkedpath, &statp)) hardlinked++;

		if(!(*arr=(struct bu *)realloc(*arr,(i+1)*sizeof(struct bu)))
		  || !((*arr)[i].data=prepend_s(fullpath, "data", strlen("data")))
		  || !((*arr)[i].delta=prepend_s(fullpath, "deltas.reverse", strlen("deltas.reverse"))))
		{
			if(log) log_and_send_oom(__FUNCTION__);
			free(timestampstr);
			free(fullpath);
			free(hlinkedpath);
			break;
		}
		(*arr)[i].path=fullpath;
		(*arr)[i].timestamp=timestampstr;
		(*arr)[i].hardlinked=hardlinked;
		(*arr)[i].deletable=0;
		(*arr)[i].index=strtoul(timestampstr, NULL, 10);
		(*arr)[i].trindex=0;
		i++;
	}
	closedir(d);

	if(*arr) qsort(*arr, i, sizeof(struct bu), bu_cmp);

	if(i>1)
	{
		tr=(*arr)[i-1].index;
		// The oldest backup is deletable.
		(*arr)[0].deletable=1;
	}

	for(j=0; j<i-1; j++)
	{
		// Backups that come after hardlinked backups are deletable.
		if((*arr)[j].hardlinked) (*arr)[j+1].deletable=1;
	}
	if(!ret)
	{
		if(tr) for(j=0; j<i; j++)
		{
			// Transpose indexes so that the oldest index is set
			// to 1.
			(*arr)[j].trindex=tr-(*arr)[j].index+1;
			//printf("%lu: %lu\n",
			//	(*arr)[j].index, (*arr)[j].trindex);
		}
		*a=i;
	}
		  
	return ret;
}
Beispiel #22
0
static int run_child(int *cfd, SSL_CTX *ctx, struct sockaddr_storage *addr,
	int status_wfd, int status_rfd, const char *conffile, int forking)
{
	int ret=-1;
	int ca_ret=0;
	SSL *ssl=NULL;
	BIO *sbio=NULL;
	struct conf **confs=NULL;
	struct conf **cconfs=NULL;
	struct cntr *cntr=NULL;
	struct async *as=NULL;
	const char *cname=NULL;
	struct asfd *asfd=NULL;
	int is_status_server=0;

	if(!(confs=confs_alloc())
	  || !(cconfs=confs_alloc()))
		goto end;

	set_peer_env_vars(addr);

	// Reload global config, in case things have changed. This means that
	// the server does not need to be restarted for most conf changes.
	confs_init(confs);
	confs_init(cconfs);
	if(conf_load_global_only(conffile, confs)) goto end;

	// Hack to keep forking turned off if it was specified as off on the
	// command line.
	if(!forking) set_int(confs[OPT_FORK], 0);

	if(!(sbio=BIO_new_socket(*cfd, BIO_NOCLOSE))
	  || !(ssl=SSL_new(ctx)))
	{
		logp("There was a problem joining ssl to the socket\n");
		goto end;
	}
	SSL_set_bio(ssl, sbio, sbio);

	/* Do not try to check peer certificate straight away.
	   Clients can send a certificate signing request when they have
	   no certificate. */
	SSL_set_verify(ssl, SSL_VERIFY_PEER
		/* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */, 0);

	if(ssl_do_accept(ssl))
		goto end;
	if(!(as=async_alloc())
	  || as->init(as, 0)
	  || !(asfd=setup_asfd_ssl(as, "main socket", cfd, ssl)))
		goto end;
	asfd->set_timeout(asfd, get_int(confs[OPT_NETWORK_TIMEOUT]));
	asfd->ratelimit=get_float(confs[OPT_RATELIMIT]);

	if(authorise_server(as->asfd, confs, cconfs)
	  || !(cname=get_string(cconfs[OPT_CNAME])) || !*cname)
	{
		// Add an annoying delay in case they are tempted to
		// try repeatedly.
		log_and_send(as->asfd, "unable to authorise on server");
		sleep(1);
		goto end;
	}

	if(!get_int(cconfs[OPT_ENABLED]))
	{
		log_and_send(as->asfd, "client not enabled on server");
		sleep(1);
		goto end;
	}

	// Set up counters. Have to wait until here to get cname.
	if(!(cntr=cntr_alloc())
	  || cntr_init(cntr, cname))
		goto end;
	set_cntr(confs[OPT_CNTR], cntr);
	set_cntr(cconfs[OPT_CNTR], cntr);

	/* At this point, the client might want to get a new certificate
	   signed. Clients on 1.3.2 or newer can do this. */
	if((ca_ret=ca_server_maybe_sign_client_cert(as->asfd, confs, cconfs))<0)
	{
		logp("Error signing client certificate request for %s\n",
			cname);
		goto end;
	}
	else if(ca_ret>0)
	{
		// Certificate signed and sent back.
		// Everything is OK, but we will close this instance
		// so that the client can start again with a new
		// connection and its new certificates.
		logp("Signed and returned client certificate request for %s\n",
			cname);
		ret=0;
		goto end;
	}

	/* Now it is time to check the certificate. */
	if(ssl_check_cert(ssl, confs, cconfs))
	{
		log_and_send(as->asfd, "check cert failed on server");
		goto end;
	}

	if(status_rfd>=0)
	{
		is_status_server=1;
		if(!setup_asfd(as, "status server parent socket", &status_rfd))
			goto end;
	}

	ret=child(as, is_status_server, status_wfd, confs, cconfs);
end:
	*cfd=-1;
	if(as && asfd_flush_asio(as->asfd))
		ret=-1;
	async_asfd_free_all(&as); // This closes cfd for us.
	logp("exit child\n");
	if(cntr) cntr_free(&cntr);
	if(confs)
	{
		set_cntr(confs[OPT_CNTR], NULL);
		confs_free(&confs);
	}
	if(cconfs)
	{
		set_cntr(cconfs[OPT_CNTR], NULL);
		confs_free(&cconfs);
	}
	return ret;
}
Beispiel #23
0
Datei: child.c Projekt: vshn/burp
int child(struct async *as, int is_status_server,
	int status_wfd, struct conf **confs, struct conf **cconfs)
{
	int ret=-1;
	int srestore=0;
	int timer_ret=0;
	char *incexc=NULL;
	const char *confs_user;
	const char *cconfs_user;
	const char *confs_group;
	const char *cconfs_group;
	const char *s_script_pre;
	const char *s_script_post;

	// If we are not a status server, we are a normal child - set up the
	// parent socket to write status to.
	if(status_wfd>0)
	{
		if(!(wasfd=setup_asfd(as, "child status pipe", &status_wfd)))
			goto end;
		wasfd->attempt_reads=0;
	}

	/* Has to be before the chuser/chgrp stuff to allow clients to switch
	   to different clients when both clients have different user/group
	   settings. */
	if(extra_comms(as, &incexc, &srestore, confs, cconfs))
	{
		log_and_send(as->asfd, "running extra comms failed on server");
		goto end;
	}

	// Needs to happen after extra_comms, in case extra_comms resets them.
	confs_user=get_string(confs[OPT_USER]);
	cconfs_user=get_string(cconfs[OPT_USER]);
	confs_group=get_string(confs[OPT_GROUP]);
	cconfs_group=get_string(cconfs[OPT_GROUP]);

	/* Now that the client conf is loaded, we might want to chuser or
	   chgrp.
	   The main process could have already done this, so we don't want
	   to try doing it again if cconfs has the same values, because it
	   will fail. */
	if( (!confs_user  || (cconfs_user && strcmp(confs_user, cconfs_user)))
	  ||(!confs_group ||(cconfs_group && strcmp(confs_group,cconfs_group))))
	{
		if(chuser_and_or_chgrp(cconfs_user, cconfs_group))
		{
			log_and_send(as->asfd,
				"chuser_and_or_chgrp failed on server");
			goto end;
		}
	}

	if(as->asfd->read(as->asfd)) goto end;

	// If this is a status server, run the status server.
	if(is_status_server)
	{
		ret=status_server(as, cconfs);
		goto end;
	}

	ret=0;

	s_script_pre=get_string(cconfs[OPT_S_SCRIPT_PRE]);
	s_script_post=get_string(cconfs[OPT_S_SCRIPT_POST]);

	// FIX THIS: Make the script components part of a struct, and just
	// pass in the correct struct. Same below.
	if(s_script_pre)
		ret=run_server_script(as->asfd, "pre",
			s_script_pre,
			get_strlist(cconfs[OPT_S_SCRIPT_PRE_ARG]),
			get_int(cconfs[OPT_S_SCRIPT_PRE_NOTIFY]),
			cconfs, ret, timer_ret);

	if(!ret)
		ret=run_action_server(as, incexc, srestore, &timer_ret, cconfs);

	if((!ret || get_int(cconfs[OPT_S_SCRIPT_POST_RUN_ON_FAIL]))
	  && s_script_post)
		ret=run_server_script(as->asfd, "post",
			s_script_post,
			get_strlist(cconfs[OPT_S_SCRIPT_POST_ARG]),
			get_int(cconfs[OPT_S_SCRIPT_POST_NOTIFY]),
			cconfs, ret, timer_ret);

end:
	return ret;
}
Beispiel #24
0
// a = length of struct bu array
// i = position to restore from
static int restore_manifest(struct bu *arr, int a, int i, const char *tmppath1, const char *tmppath2, regex_t *regex, enum action act, const char *client, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf, bool all)
{
	int ret=0;
	gzFile zp=NULL;
	char *manifest=NULL;
	char *datadir=NULL;
	FILE *logfp=NULL;
	char *logpath=NULL;
	char *logpathz=NULL;
	// For sending status information up to the server.
	char status=STATUS_RESTORING;

	if(act==ACTION_RESTORE) status=STATUS_RESTORING;
	else if(act==ACTION_VERIFY) status=STATUS_VERIFYING;

	if(
	    (act==ACTION_RESTORE && !(logpath=prepend_s(arr[i].path, "restorelog", strlen("restorelog"))))
	 || (act==ACTION_RESTORE && !(logpathz=prepend_s(arr[i].path, "restorelog.gz", strlen("restorelog.gz"))))
	 || (act==ACTION_VERIFY && !(logpath=prepend_s(arr[i].path, "verifylog", strlen("verifylog"))))
	 || (act==ACTION_VERIFY && !(logpathz=prepend_s(arr[i].path, "verifylog.gz", strlen("verifylog.gz"))))
	 || !(manifest=prepend_s(arr[i].path, "manifest.gz", strlen("manifest.gz"))))
	{
		log_and_send("out of memory");
		ret=-1;
	}
	else if(!(logfp=open_file(logpath, "ab")) || set_logfp(logfp))
	{
		char msg[256]="";
		snprintf(msg, sizeof(msg),
			"could not open log file: %s", logpath);
		log_and_send(msg);
		ret=-1;
	}
	else if(!(zp=gzopen_file(manifest, "rb")))
	{
		log_and_send("could not open manifest");
		ret=-1;
	}
	else
	{
		char cmd;
		int quit=0;
		size_t len=0;
		struct sbuf sb;
		// For out-of-sequence directory restoring so that the
		// timestamps come out right:
		int s=0;
		int scount=0;
		struct sbuf **sblist=NULL;

		init_sbuf(&sb);

		while(!quit)
		{
			int ars=0;
			char *buf=NULL;
			if(async_read_quick(&cmd, &buf, &len))
			{
				logp("read quick error\n");
				ret=-1; quit++; break;
			}
			if(buf)
			{
				//logp("got read quick\n");
				if(cmd==CMD_WARNING)
				{
					logp("WARNING: %s\n", buf);
					do_filecounter(cntr, cmd, 0);
					free(buf); buf=NULL;
					continue;
				}
				else if(cmd==CMD_INTERRUPT)
				{
					// Client wanted to interrupt the
					// sending of a file. But if we are
					// here, we have already moved on.
					// Ignore.
					free(buf); buf=NULL;
					continue;
				}
				else
				{
					logp("unexpected cmd from client: %c:%s\n", cmd, buf);
					free(buf); buf=NULL;
					ret=-1; quit++; break;
				}
			}

			if((ars=sbuf_fill(NULL, zp, &sb, cntr)))
			{
				if(ars<0) ret=-1;
				// ars==1 means end ok
				quit++;
			}
			else
			{
				if(check_regex(regex, sb.path))
				{
				  // Check if we have any directories waiting
				  // to be restored.
				  for(s=scount-1; s>=0; s--)
				  {
					if(is_subdir(sblist[s]->path, sb.path))
					{
						// We are still in a subdir.
						//printf(" subdir (%s %s)\n", sblist[s]->path, sb.path);
						break;
					}
					else
					{
						// Can now restore sblist[s]
						// because nothing else is
						// fiddling in a subdirectory.
				  		if(restore_sbuf(sblist[s], arr,
						 a, i, tmppath1, tmppath2, act,
						 client, status,
						 p1cntr, cntr, cconf))
						{
							ret=-1; quit++;
							break;
						}
						else if(del_from_sbuf_arr(
							&sblist, &scount))
						{
							ret=-1; quit++;
							break;
						}
					}
				  }

				  /* If it is a directory, need to remember it
				     and restore it later, so that the
				     permissions come out right. */
				  /* Meta data of directories will also have
				     the stat stuff set to be a directory,
				     so will also come out at the end. */
				  if(!ret && S_ISDIR(sb.statp.st_mode))
				  {
					if(add_to_sbuf_arr(&sblist, &sb, &scount))
					{
						ret=-1; quit++;
					}

					// Wipe out sb, without freeing up
					// all the strings inside it, which
					// have been added to sblist.
					init_sbuf(&sb);
				  }
				  else if(!ret && restore_sbuf(&sb, arr, a, i,
				    tmppath1, tmppath2, act, client, status,
				    p1cntr, cntr, cconf))
				  {
					ret=-1; quit++;
				  }
				}
			}
			free_sbuf(&sb);
		}
		gzclose_fp(&zp);
		// Restore any directories that are left in the list.
		if(!ret) for(s=scount-1; s>=0; s--)
		{
			if(restore_sbuf(sblist[s], arr, a, i,
				tmppath1, tmppath2, act, client, status,
				p1cntr, cntr, cconf))
			{
				ret=-1;
				break;
			}
		}
		free_sbufs(sblist, scount);

		if(!ret && !all) ret=do_restore_end(act, cntr);

		print_endcounter(cntr);
		print_filecounters(p1cntr, cntr, act, 0);

		reset_filecounter(p1cntr);
		reset_filecounter(cntr);
	}
	set_logfp(NULL);
	compress_file(logpath, logpathz, cconf);
	if(manifest) free(manifest);
	if(datadir) free(datadir);
	if(logpath) free(logpath);
	if(logpathz) free(logpathz);
	return ret;
}
Beispiel #25
0
static int list_manifest(const char *fullpath, regex_t *regex, const char *browsedir, const char *client, struct cntr *p1cntr, struct cntr *cntr)
{
	int ars=0;
	int ret=0;
	int quit=0;
	gzFile zp=NULL;
	struct sbuf mb;
	char *manifest=NULL;
	size_t bdlen=0;

	init_sbuf(&mb);

	if(!(manifest=prepend_s(fullpath,
		"manifest.gz", strlen("manifest.gz"))))
	{
		log_and_send_oom(__FUNCTION__);
		return -1;
	}
	if(!(zp=gzopen_file(manifest, "rb")))
	{
		log_and_send("could not open manifest");
		free(manifest);
		return -1;
	}
	free(manifest);

	if(browsedir) bdlen=strlen(browsedir);

	while(!quit)
	{
		int show=0;
		//logp("list manifest loop\n");
		// Need to parse while sending, to take note of the regex.

		free_sbuf(&mb);
		if((ars=sbuf_fill(NULL, zp, &mb, cntr)))
		{
			if(ars<0) ret=-1;
			// ars==1 means it ended ok.
			break;
		}

		if(mb.cmd!=CMD_DIRECTORY
		 && mb.cmd!=CMD_FILE
		 && mb.cmd!=CMD_ENC_FILE
		 && mb.cmd!=CMD_EFS_FILE
		 && mb.cmd!=CMD_SPECIAL
		 && !cmd_is_link(mb.cmd))
			continue;

		//if(mb.path[mb.plen]=='\n') mb.path[mb.plen]='\0';
		write_status(client, STATUS_LISTING, mb.path, p1cntr, cntr);

		if(browsedir)
		{
			int r;
			if((r=check_browsedir(browsedir, &(mb.path), bdlen))<0)
			{
				quit++;
				ret=-1;
			}
			if(!r) continue;
			show++;
		}
		else
		{
			if(check_regex(regex, mb.path))
				show++;
		}
		if(show)
		{
			if(async_write(CMD_STAT, mb.statbuf, mb.slen)
			  || async_write(mb.cmd, mb.path, mb.plen))
			{ quit++; ret=-1; }
			else if(sbuf_is_link(&mb)
			  && async_write(mb.cmd, mb.linkto, mb.llen))
			{ quit++; ret=-1; }
		}
	}
	gzclose_fp(&zp);
	free_sbuf(&mb);
	return ret;
}
Beispiel #26
0
// a = length of struct bu array
// i = position to restore from
static int restore_file(struct bu *arr, int a, int i, const char *datapth, const char *fname, const char *tmppath1, const char *tmppath2, int act, const char *endfile, char cmd, int64_t winattr, int compression, struct cntr *cntr, struct config *cconf)
{
	int x=0;
	char msg[256]="";
	// Go up the array until we find the file in the data directory.
	for(x=i; x<a; x++)
	{
		char *path=NULL;
		struct stat statp;
		if(!(path=prepend_s(arr[x].data, datapth, strlen(datapth))))
		{
			log_and_send_oom(__FUNCTION__);
			return -1;
		}

		//logp("server file: %s\n", path);

		if(lstat(path, &statp) || !S_ISREG(statp.st_mode))
		{
			free(path);
			continue;
		}
		else
		{
			int patches=0;
			struct stat dstatp;
			const char *tmp=NULL;
			const char *best=NULL;
			unsigned long long bytes=0;

			best=path;
			tmp=tmppath1;
			// Now go down the array, applying any deltas.
			for(x-=1; x>=i; x--)
			{
				char *dpath=NULL;

				if(!(dpath=prepend_s(arr[x].delta,
						datapth, strlen(datapth))))
				{
					log_and_send_oom(__FUNCTION__);
					free(path);
					return -1;
				}

				if(lstat(dpath, &dstatp)
				  || !S_ISREG(dstatp.st_mode))
				{
					free(dpath);
					continue;
				}

				if(!patches)
				{
					// Need to gunzip the first one.
					if(inflate_or_link_oldfile(best, tmp,
						compression))
					{
						logp("error when inflating %s\n", best);
						free(path);
						free(dpath);
						return -1;
					}
					best=tmp;
					if(tmp==tmppath1) tmp=tmppath2;
					else tmp=tmppath1;
				}

				if(do_patch(best, dpath, tmp,
				  FALSE /* do not gzip the result */,
				  compression /* from the manifest */,
				  cntr, cconf))
				{
					char msg[256]="";
					snprintf(msg, sizeof(msg),
						"error when patching %s\n",
							path);
					log_and_send(msg);
					free(path);
					free(dpath);
					return -1;
				}

				best=tmp;
				if(tmp==tmppath1) tmp=tmppath2;
				else tmp=tmppath1;
				unlink(tmp);
				patches++;
			}


			if(act==ACTION_RESTORE)
			{
				if(send_file(fname, patches, best, datapth,
					&bytes, cmd, winattr, compression,
					cntr, cconf))
				{
					free(path);
					return -1;
				}
				else
				{
					do_filecounter(cntr, cmd, 0);
					do_filecounter_bytes(cntr,
                 			    strtoull(endfile, NULL, 10));
				}
			}
			else if(act==ACTION_VERIFY)
			{
				if(verify_file(fname, patches, best, datapth,
					&bytes, endfile, cmd, compression,
					cntr))
				{
					free(path);
					return -1;
				}
				else
				{
					do_filecounter(cntr, cmd, 0);
					do_filecounter_bytes(cntr,
                 			    strtoull(endfile, NULL, 10));
				}
			}
			do_filecounter_sentbytes(cntr, bytes);
			free(path);
			return 0;
		}
	}

	logw(cntr, "restore could not find %s (%s)\n", fname, datapth);
	//return -1;
	return 0;
}
Beispiel #27
0
static int recover_working(struct async *as,
	struct sdirs *sdirs, const char *incexc,
	int *resume, struct conf **cconfs)
{
	int ret=-1;
	char msg[256]="";
	char *logpath=NULL;
	struct stat statp;
	char *phase1datatmp=NULL;
	enum recovery_method recovery_method=get_e_recovery_method(
		cconfs[OPT_WORKING_DIR_RECOVERY_METHOD]);

	// The working directory has not finished being populated.
	// Check what to do.
	if(get_fullrealwork(as->asfd, sdirs, cconfs)) goto end;
	if(!sdirs->rworking) goto end;

	log_recovery_method(sdirs, recovery_method);

	if(!(phase1datatmp=get_tmp_filename(sdirs->phase1data)))
		goto end;
	// If there is still a phase1 tmp file...
	if(!lstat(phase1datatmp, &statp)
	  ||
		// ...or phase1 has not even got underway yet...
		(lstat(phase1datatmp, &statp)
		  && lstat(sdirs->phase1data, &statp)
		  && lstat(sdirs->changed, &statp)
		  && lstat(sdirs->unchanged, &statp)))
	{
		// ...phase 1 did not complete - delete everything.
		logp("Phase 1 has not completed.\n");
		recovery_method=RECOVERY_METHOD_DELETE;
	}

	if(recovery_method==RECOVERY_METHOD_DELETE)
	{
		ret=working_delete(as, sdirs, cconfs);
		goto end;
	}

	// We are not deleting the old working directory - open the log inside
	// for appending.
	if(!(logpath=prepend_s(sdirs->rworking, "log"))
	  || log_fzp_set(logpath, cconfs))
		goto end;

	switch(recovery_method)
	{
		case RECOVERY_METHOD_DELETE:
			// Dealt with above.
			break;
		case RECOVERY_METHOD_RESUME:
			ret=working_resume(as, sdirs, incexc, resume, cconfs);
			break;
		case RECOVERY_METHOD_UNSET:
		default:
			snprintf(msg, sizeof(msg),
				"Unknown working_dir_recovery_method: %d\n",
					(int)recovery_method);
			log_and_send(as->asfd, msg);
			break;
	}

end:
	free_w(&logpath);
	free_w(&phase1datatmp);
	log_fzp_set(NULL, cconfs); // fclose the logfzp
	return ret;
}
Beispiel #28
0
// a = length of struct bu array
// i = position to restore from
static int restore_manifest(struct bu *arr, int a, int i, const char *tmppath1, const char *tmppath2, regex_t *regex, int srestore, enum action act, const char *client, char **dir_for_notify, struct cntr *p1cntr, struct cntr *cntr, struct config *cconf)
{
	int ret=0;
	gzFile zp=NULL;
	char *manifest=NULL;
	char *datadir=NULL;
	FILE *logfp=NULL;
	char *logpath=NULL;
	char *logpathz=NULL;
	// For sending status information up to the server.
	char status=STATUS_RESTORING;

	if(act==ACTION_RESTORE) status=STATUS_RESTORING;
	else if(act==ACTION_VERIFY) status=STATUS_VERIFYING;

	if(
	    (act==ACTION_RESTORE && !(logpath=prepend_s(arr[i].path, "restorelog", strlen("restorelog"))))
	 || (act==ACTION_RESTORE && !(logpathz=prepend_s(arr[i].path, "restorelog.gz", strlen("restorelog.gz"))))
	 || (act==ACTION_VERIFY && !(logpath=prepend_s(arr[i].path, "verifylog", strlen("verifylog"))))
	 || (act==ACTION_VERIFY && !(logpathz=prepend_s(arr[i].path, "verifylog.gz", strlen("verifylog.gz"))))
	 || !(manifest=prepend_s(arr[i].path, "manifest.gz", strlen("manifest.gz"))))
	{
		log_and_send_oom(__FUNCTION__);
		ret=-1;
	}
	else if(!(logfp=open_file(logpath, "ab")) || set_logfp(logfp, cconf))
	{
		char msg[256]="";
		snprintf(msg, sizeof(msg),
			"could not open log file: %s", logpath);
		log_and_send(msg);
		ret=-1;
	}

	*dir_for_notify=strdup(arr[i].path);

	log_restore_settings(cconf, srestore);

	// First, do a pass through the manifest to set up the counters.
	// This is the equivalent of a phase1 scan during backup.
	if(!ret && !(zp=gzopen_file(manifest, "rb")))
	{
		log_and_send("could not open manifest");
		ret=-1;
	}
	else
	{
		int ars=0;
		int quit=0;
		struct sbuf sb;
		init_sbuf(&sb);
		while(!quit)
		{
			if((ars=sbuf_fill(NULL, zp, &sb, cntr)))
			{
				if(ars<0) ret=-1;
				// ars==1 means end ok
				quit++;
			}
			else
			{
				if((!srestore
				    || check_srestore(cconf, sb.path))
				  && check_regex(regex, sb.path))
				{
					do_filecounter(p1cntr, sb.cmd, 0);
					if(sb.endfile)
					  do_filecounter_bytes(p1cntr,
                 			    strtoull(sb.endfile, NULL, 10));
/*
					if(sb.cmd==CMD_FILE
					  || sb.cmd==CMD_ENC_FILE
					  || sb.cmd==CMD_METADATA
					  || sb.cmd==CMD_ENC_METADATA
					  || sb.cmd==CMD_VSS
					  || sb.cmd==CMD_ENC_VSS
					  || sb.cmd==CMD_VSS_T
					  || sb.cmd==CMD_ENC_VSS_T
					  || sb.cmd==CMD_EFS_FILE)
						do_filecounter_bytes(p1cntr,
							(unsigned long long)
							sb.statp.st_size);
*/
				}
			}
			free_sbuf(&sb);
		}
		free_sbuf(&sb);
		gzclose_fp(&zp);
	}

	if(cconf->send_client_counters)
	{
		if(send_counters(client, p1cntr, cntr))
		{
			ret=-1;
		}
	}

	// Now, do the actual restore.
	if(!ret && !(zp=gzopen_file(manifest, "rb")))
	{
		log_and_send("could not open manifest");
		ret=-1;
	}
	else
	{
		char cmd;
		int s=0;
		int quit=0;
		size_t len=0;
		struct sbuf sb;
		// For out-of-sequence directory restoring so that the
		// timestamps come out right:
		int scount=0;
		struct sbuf **sblist=NULL;

		init_sbuf(&sb);

		while(!quit)
		{
			int ars=0;
			char *buf=NULL;
			if(async_read_quick(&cmd, &buf, &len))
			{
				logp("read quick error\n");
				ret=-1; quit++; break;
			}
			if(buf)
			{
				//logp("got read quick\n");
				if(cmd==CMD_WARNING)
				{
					logp("WARNING: %s\n", buf);
					do_filecounter(cntr, cmd, 0);
					free(buf); buf=NULL;
					continue;
				}
				else if(cmd==CMD_INTERRUPT)
				{
					// Client wanted to interrupt the
					// sending of a file. But if we are
					// here, we have already moved on.
					// Ignore.
					free(buf); buf=NULL;
					continue;
				}
				else
				{
					logp("unexpected cmd from client: %c:%s\n", cmd, buf);
					free(buf); buf=NULL;
					ret=-1; quit++; break;
				}
			}

			if((ars=sbuf_fill(NULL, zp, &sb, cntr)))
			{
				if(ars<0) ret=-1;
				// ars==1 means end ok
				quit++;
			}
			else
			{
				if((!srestore
				    || check_srestore(cconf, sb.path))
				  && check_regex(regex, sb.path)
				  && restore_ent(client,
					&sb, &sblist, &scount,
					arr, a, i, tmppath1, tmppath2,
					act, status, cconf,
					cntr, p1cntr))
				{
					ret=-1;
					quit++;
				}
			}
			free_sbuf(&sb);
		}
		gzclose_fp(&zp);
		// Restore any directories that are left in the list.
		if(!ret) for(s=scount-1; s>=0; s--)
		{
			if(restore_sbuf(sblist[s], arr, a, i,
				tmppath1, tmppath2, act, client, status,
				p1cntr, cntr, cconf))
			{
				ret=-1;
				break;
			}
		}
		free_sbufs(sblist, scount);

		if(!ret) ret=do_restore_end(act, cntr);

		//print_endcounter(cntr);
		print_filecounters(p1cntr, cntr, act);

		reset_filecounter(p1cntr, time(NULL));
		reset_filecounter(cntr, time(NULL));
	}
	set_logfp(NULL, cconf);
	compress_file(logpath, logpathz, cconf);
	if(manifest) free(manifest);
	if(datadir) free(datadir);
	if(logpath) free(logpath);
	if(logpathz) free(logpathz);
	return ret;
}
Beispiel #29
0
int do_backup_server_burp1(struct async *as,
	struct sdirs *sdirs, struct conf *cconf,
	const char *incexc, int resume)
{
	int ret=0;
	char msg[256]="";
	gzFile mzp=NULL;
	// Real path to the working directory
	char *realworking=NULL;
	char tstmp[64]="";
	struct asfd *asfd=as->asfd;

	struct dpthl dpthl;

	gzFile cmanfp=NULL;
	struct stat statp;

	logp("in do_backup_server\n");

	if(init_dpthl(&dpthl, asfd, sdirs, cconf))
	{
		log_and_send(asfd, "could not init_dpthl\n");
		goto error;
	}

	if(resume)
	{
		ssize_t len=0;
		char real[256]="";
		if((len=readlink(sdirs->working, real, sizeof(real)-1))<0)
			len=0;
		real[len]='\0';
		if(!(realworking=prepend_s(sdirs->client, real)))
		{
			log_and_send_oom(asfd, __func__);
			goto error;
		}
		if(open_log(asfd, realworking, cconf)) goto error;
	}
	else
	{
		// Not resuming - need to set everything up fresh.

		if(get_new_timestamp(asfd, sdirs, cconf, tstmp, sizeof(tstmp)))
			goto error;
		if(!(realworking=prepend_s(sdirs->client, tstmp)))
		{
			log_and_send_oom(asfd, __func__);
			goto error;
		}
		// Add the working symlink before creating the directory.
		// This is because bedup checks the working symlink before
		// going into a directory. If the directory got created first,
		// bedup might go into it in the moment before the symlink
		// gets added.
		if(symlink(tstmp, sdirs->working)) // relative link to the real work dir
		{
			snprintf(msg, sizeof(msg),
			  "could not point working symlink to: %s",
			  realworking);
			log_and_send(asfd, msg);
			goto error;
		}
		else if(mkdir(realworking, 0777))
		{
			snprintf(msg, sizeof(msg),
				"could not mkdir for next backup: %s",
				sdirs->working);
			log_and_send(asfd, msg);
			unlink(sdirs->working);
			goto error;
		}
		else if(open_log(asfd, realworking, cconf))
		{
			goto error;
		}
		else if(mkdir(sdirs->datadirtmp, 0777))
		{
			snprintf(msg, sizeof(msg),
			  "could not mkdir for datadir: %s", sdirs->datadirtmp);
			log_and_send(asfd, msg);
			goto error;
		}
		else if(write_timestamp(sdirs->timestamp, tstmp))
		{
			snprintf(msg, sizeof(msg),
			  "unable to write timestamp %s", sdirs->timestamp);
			log_and_send(asfd, msg);
			goto error;
		}
		else if(incexc && *incexc && write_incexc(realworking, incexc))
		{
			snprintf(msg, sizeof(msg), "unable to write incexc");
			log_and_send(asfd, msg);
			goto error;
		}

		if(backup_phase1_server(asfd, sdirs, cconf))
		{
			logp("error in phase 1\n");
			goto error;
		}
	}

	// Open the previous (current) manifest.
	// If the split_vss setting changed between the previous backup
	// and the new backup, do not open the previous manifest.
	// This will have the effect of making the client back up everything
	// fresh. Need to do this, otherwise toggling split_vss on and off
	// will result in backups that do not work.
	if(!lstat(sdirs->cmanifest, &statp)
	  && !vss_opts_changed(sdirs, cconf, incexc))
	{
		if(!(cmanfp=gzopen_file(sdirs->cmanifest, "rb")))
		{
			if(!lstat(sdirs->cmanifest, &statp))
			{
				logp("could not open old manifest %s\n",
					sdirs->cmanifest);
				goto error;
			}
		}
	}

	//if(cmanfp) logp("Current manifest: %s\n", sdirs->cmanifest);

	if(backup_phase2_server(asfd, sdirs, cconf, &cmanfp, &dpthl, resume))
	{
		logp("error in backup phase 2\n");
		goto error;
	}

	if(backup_phase3_server(sdirs, cconf,
		0 /* not recovery mode */, 1 /* compress */))
	{
		logp("error in backup phase 3\n");
		goto error;
	}

	// will not write anything more to
	// the new manifest
	// finish_backup will open it again
	// for reading
	if(gzclose_fp(&mzp))
	{
		logp("Error closing manifest after phase3\n");
		goto error;
	}

	asfd->write_str(asfd, CMD_GEN, "okbackupend");
	logp("Backup ending - disconnect from client.\n");

	// Close the connection with the client, the rest of the job
	// we can do by ourselves.
	asfd_free(&as->asfd);

	// Move the symlink to indicate that we are now in the end
	// phase. 
	if(do_rename(sdirs->working, sdirs->finishing))
		goto error;

	set_logfp(NULL, cconf); // does an fclose on logfp.
	// finish_backup will open logfp again
	ret=backup_phase4_server(sdirs, cconf);
	if(!ret && cconf->keep>0)
		ret=remove_old_backups(asfd, sdirs, cconf);

	goto end;
error:
	ret=-1;
end:
	gzclose_fp(&cmanfp);
	gzclose_fp(&mzp);
	set_logfp(NULL, cconf); // does an fclose on logfp.
	return ret;
}
Beispiel #30
0
int check_for_rubble_burp1(struct asfd *asfd,
	struct sdirs *sdirs, struct conf *cconf,
	const char *incexc, int *resume)
{
	int ret=0;
	ssize_t len=0;
	char msg[256]="";
	char realwork[256]="";
	struct stat statp;
	char *logpath=NULL;
	char *fullrealwork=NULL;
	char *phase1datatmp=NULL;
	const char *wdrm=cconf->recovery_method;

	// If there is a 'finishing' symlink, we need to
	// run the finish_backup stuff.
	if(!lstat(sdirs->finishing, &statp))
	{
		logp("Found finishing symlink - attempting to complete prior backup!\n");
		ret=backup_phase4_server(sdirs, cconf);
		if(!ret) logp("Prior backup completed OK.\n");
		else log_and_send(asfd, "Problem with prior backup. Please check the client log on the server.");
		goto end;
	}

	if(lstat(sdirs->working, &statp))
	{
		// No working directory - that is good.
		goto end;
	}
	if(!S_ISLNK(statp.st_mode))
	{
		log_and_send(asfd, "Working directory is not a symlink.\n");
		ret=-1;
		goto end;
	}

	// The working directory has not finished being populated.
	// Check what to do.
	if((len=readlink(sdirs->working, realwork, sizeof(realwork)-1))<0)
	{
		snprintf(msg, sizeof(msg), "Could not readlink on old working directory: %s\n", strerror(errno));
		log_and_send(asfd, msg);
		ret=-1;
		goto end;
	}
	realwork[len]='\0';
	if(!(fullrealwork=prepend_s(sdirs->client, realwork)))
	{
		ret=-1;
		goto end;
	}

	if(lstat(fullrealwork, &statp))
	{
		logp("removing dangling working symlink -> %s\n", realwork);
		unlink(sdirs->working);
		goto end;
	}

	if(!(phase1datatmp=get_tmp_filename(sdirs->phase1data)))
		goto end;

	// We have found an old working directory - open the log inside
	// for appending.
	if(!(logpath=prepend_s(fullrealwork, "log")))
	{
		ret=-1;
		goto end;
	}
	if(set_logfp(logpath, cconf))
	{
		ret=-1;
		goto end;
	}

	logp("found old working directory: %s\n", fullrealwork);
	logp("working_dir_recovery_method: %s\n", wdrm);

	if(!lstat(phase1datatmp, &statp))
	{
		// Phase 1 did not complete - delete everything.
		logp("Phase 1 has not completed.\n");
		wdrm="delete";
	}

	if(!strcmp(wdrm, "delete"))
	{
		// Try to remove it and start again.
		logp("deleting old working directory\n");
		if(recursive_delete(fullrealwork, NULL, 1 /* delete files */))
		{
			log_and_send(asfd,
				"Old working directory is in the way.\n");
			ret=-1;
			goto end;
		}
		unlink(sdirs->working); // get rid of the symlink.
		goto end;
	}
	if(!strcmp(wdrm, "resume"))
	{
		if(cconf->restore_client)
		{
			// This client is not the original client, resuming	
			// might cause all sorts of trouble.
			log_and_send(asfd, "Found interrupted backup - not resuming because the connected client is not the original");
			ret=-1;
			goto end;
		}

		logp("Found interrupted backup.\n");

		// Check that the current incexc configuration is the same
		// as before.
		if((ret=incexc_matches(fullrealwork, incexc))<0)
			goto end;
		if(ret)
		{
			// Attempt to resume on the next backup.
			logp("Will resume on the next backup request.\n");
			*resume=1;
			ret=0;
			goto end;
		}
		logp("Includes/excludes have changed since the last backup.\n");
		logp("Will treat last backup as finished.\n");
		wdrm="use";
	}
	if(!strcmp(wdrm, "use"))
	{
		// Use it as it is.
		logp("converting old working directory into the latest backup\n");
		free(fullrealwork); fullrealwork=NULL;

		// TODO: There might be a partial file written that is not
		// yet logged to the manifest. It does no harm other than
		// taking up some disk space. Detect this and remove it.

		// Get us a partial manifest from the files lying around.
		if(maybe_rebuild_manifest(sdirs, cconf, 1 /* compress */))
		{
			ret=-1;
			goto end;
		}

		// Now just rename the working link to be a finishing link,
		// then run this function again.
		if(do_rename(sdirs->working, sdirs->finishing))
		{
			ret=-1;
			goto end;
		}
		ret=check_for_rubble_burp1(asfd, sdirs, cconf, incexc, resume);
		goto end;
	}

	snprintf(msg, sizeof(msg),
		"Unknown working_dir_recovery_method: %s\n", wdrm);
	log_and_send(asfd, msg);
	ret=-1;

end:
	if(fullrealwork) free(fullrealwork);
	if(logpath) free(logpath);
	if(phase1datatmp) free(phase1datatmp);
	set_logfp(NULL, cconf); // fclose the logfp
	return ret;
}