Пример #1
0
struct asfd *champ_chooser_connect(struct async *as,
	struct sdirs *sdirs, struct conf **confs, int resume)
{
	int champsock=-1;
	char *champname=NULL;
	struct asfd *chfd=NULL;
	const char *cname=NULL;

	// Connect to champ chooser now.
	// This may start up a new champ chooser. On a machine with multiple
	// cores, it may be faster to do now, way before it is actually needed
	// in phase2.
	if((champsock=connect_to_champ_chooser(sdirs, confs, resume))<0)
	{
		logp("could not connect to champ chooser\n");
		goto error;
	}

	if(!(chfd=setup_asfd(as, "champ chooser socket", &champsock,
		/*listen*/"")))
			goto error;

	cname=get_string(confs[OPT_CNAME]);
	if(!(champname=prepend_n("cname", cname, strlen(cname), ":")))
			goto error;

	if(chfd->write_str(chfd, CMD_GEN, champname)
	  || asfd_read_expect(chfd, CMD_GEN, "cname ok"))
		goto error;

	free_w(&champname);
	return chfd;
error:
	free_w(&champname);
	as->asfd_remove(as, chfd);
	asfd_free(&chfd);
	close_fd(&champsock);
	return NULL;
}
Пример #2
0
int authorise_client(struct asfd *asfd,
	char **server_version, const char *cname, const char *password,
	struct cntr *cntr)
{
	int ret=-1;
	char hello[256]="";
	struct iobuf *rbuf=asfd->rbuf;

	snprintf(hello, sizeof(hello), "hello:%s", VERSION);
	if(asfd->write_str(asfd, CMD_GEN, hello))
	{
		logp("problem with auth\n");
		goto end;
	}

	if(asfd->read(asfd)
	  || rbuf->cmd!=CMD_GEN
	  || strncmp_w(rbuf->buf, "whoareyou"))
	{
		logp("problem with auth\n");
		goto end;
	}
	if(rbuf->buf)
	{
		char *cp=NULL;
		if((cp=strchr(rbuf->buf, ':')))
		{
			cp++;
			if(cp && !(*server_version=strdup_w(cp, __func__)))
				goto end;
		}
		iobuf_free_content(rbuf);
	}

	if(asfd->write_str(asfd, CMD_GEN, cname)
	  || asfd_read_expect(asfd, CMD_GEN, "okpassword")
	  || asfd->write_str(asfd, CMD_GEN, password)
	  || asfd->read(asfd))
	{
		logp("problem with auth\n");
		goto end;
	}

	if(rbuf->cmd==CMD_WARNING) // special case for the version warning
	{
		//logw(conf->p1cntr, rbuf->buf);
		logp("WARNING: %s\n", rbuf->buf);
		cntr_add(cntr, rbuf->cmd, 0);
		iobuf_free_content(rbuf);
		if(asfd->read(asfd))
		{
			logp("problem with auth\n");
			goto end;
		}
	}
	if(rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "ok"))
	{
		// It is OK.
		logp("auth ok\n");
	}
	else
	{
		iobuf_log_unexpected(rbuf, __func__);
		goto end;
	}

	ret=0;
end:
	iobuf_free_content(rbuf);
	return ret;
}
Пример #3
0
int extra_comms(struct async *as,
	char **incexc, int *srestore, struct conf **confs, struct conf **cconfs)
{
	struct vers vers;
	struct asfd *asfd;
	asfd=as->asfd;
	//char *restorepath=NULL;
	const char *peer_version=NULL;

	if(vers_init(&vers, cconfs)) goto error;

	if(vers.cli<vers.directory_tree)
	{
		set_int(confs[OPT_DIRECTORY_TREE], 0);
		set_int(cconfs[OPT_DIRECTORY_TREE], 0);
	}

	// Clients before 1.2.7 did not know how to do extra comms, so skip
	// this section for them.
	if(vers.cli<vers.min) return 0;

	if(asfd_read_expect(asfd, CMD_GEN, "extra_comms_begin"))
	{
		logp("problem reading in extra_comms\n");
		goto error;
	}
	// Want to tell the clients the extra comms features that are
	// supported, so that new clients are more likely to work with old
	// servers.
	if(vers.cli==vers.feat_list)
	{
		// 1.3.0 did not support the feature list.
		if(asfd->write_str(asfd, CMD_GEN, "extra_comms_begin ok"))
		{
			logp("problem writing in extra_comms\n");
			goto error;
		}
	}
	else
	{
		if(send_features(asfd, cconfs)) goto error;
	}

	if(extra_comms_read(as, &vers, srestore, incexc, confs, cconfs))
		goto error;

	peer_version=get_string(cconfs[OPT_PEER_VERSION]);

	// This needs to come after extra_comms_read, as the client might
	// have set PROTO_1 or PROTO_2.
	switch(get_protocol(cconfs))
	{
		case PROTO_AUTO:
			// The protocol has not been specified. Make a choice.
			if(vers.cli<vers.burp2)
			{
				// Client is burp-1.x.x, use protocol1.
				set_protocol(confs, PROTO_1);
				set_protocol(cconfs, PROTO_1);
				logp("Client is burp-%s - using protocol=%d\n",
					peer_version, PROTO_1);
			}
			else
			{
				// Client is burp-2.x.x, use protocol2.
				// This will probably never be reached because
				// the negotiation will take care of it.
				set_protocol(confs, PROTO_2);
				set_protocol(cconfs, PROTO_2);
				logp("Client is burp-%s - using protocol=%d\n",
					peer_version, PROTO_2);
			}
			break;
		case PROTO_1:
			// It is OK for the client to be burp1 and for the
			// server to be forced to protocol1.
			break;
		case PROTO_2:
			if(vers.cli>=vers.burp2) break;
			logp("protocol=%d is set server side, "
			  "but client is burp version %s\n",
			  peer_version);
			goto error;
	}

	if(get_protocol(cconfs)==PROTO_1)
	{
		if(get_e_rshash(cconfs[OPT_RSHASH])==RSHASH_UNSET)
		{
			set_e_rshash(confs[OPT_RSHASH], RSHASH_MD4);
			set_e_rshash(cconfs[OPT_RSHASH], RSHASH_MD4);
		}
	}

	return 0;
error:
	return -1;
}
Пример #4
0
int backup_phase2_client_protocol2(struct asfd *asfd,
	struct conf **confs, int resume)
{
	int ret=-1;
	uint8_t end_flags=0;
	struct slist *slist=NULL;
	struct iobuf *rbuf=NULL;
	struct iobuf *wbuf=NULL;
	struct cntr *cntr=NULL;

	if(confs) cntr=get_cntr(confs);

	if(!asfd || !asfd->as)
	{
		logp("%s() called without async structs!\n", __func__);
		goto end;
	}

	logp("Phase 2 begin (send backup data)\n");
	logfmt("\n");

	if(!(slist=slist_alloc())
	  || !(wbuf=iobuf_alloc())
	  || blks_generate_init())
		goto end;
	rbuf=asfd->rbuf;

	if(!resume)
	{
		// Only do this bit if the server did not tell us to resume.
		if(asfd->write_str(asfd, CMD_GEN, "backupphase2")
		  || asfd_read_expect(asfd, CMD_GEN, "ok"))
			goto end;
	}
	else
	{
		// On resume, the server might update the client with cntr.
		if(cntr_recv(asfd, confs))
			goto end;
        }

	while(!(end_flags&END_BACKUP))
	{
		if(!wbuf->len)
		{
			get_wbuf_from_data(confs, wbuf, slist,
				end_flags);
			if(!wbuf->len)
			{
				if(get_wbuf_from_blks(wbuf, slist,
					&end_flags)) goto end;
			}
		}

		if(wbuf->len)
		{
			if(asfd->append_all_to_write_buffer(asfd, wbuf)
				==APPEND_ERROR)
					goto end;
		}
		if(asfd->as->read_write(asfd->as))
		{
			logp("error in %s\n", __func__);
			goto end;
		}

		if(rbuf->buf && deal_with_read(rbuf, slist, cntr, &end_flags))
			goto end;

		if(slist->head
		// Need to limit how many blocks are allocated at once.
		  && (!slist->blist->head
		   || slist->blist->tail->index
			- slist->blist->head->index<BLKS_MAX_IN_MEM)
		)
		{
			if(add_to_blks_list(asfd, confs, slist))
				goto end;
		}

		if(end_flags&END_BLK_REQUESTS)
		{
			// If got to the end of the file request list
			// and the last block of the last file, and
			// the write buffer is empty, we got to the end.
			if(slist->head==slist->tail)
			{
				if(!slist->tail
				  || slist->blist->last_sent==
					slist->tail->protocol2->bend)
				{
					if(!wbuf->len)
						break;
				}
			}

		}
	}

	if(asfd->write_str(asfd, CMD_GEN, "backup_end"))
		goto end;

	ret=0;
end:
	slist_free(&slist);
	blks_generate_free();
	if(wbuf)
	{
		// Write buffer did not allocate 'buf'.
		wbuf->buf=NULL;
		iobuf_free(&wbuf);
	}
	cntr_print_end(cntr);
	cntr_print(cntr, ACTION_BACKUP, asfd);
	if(ret) logp("Error in backup\n");
	logp("End backup\n");

	return ret;
}
Пример #5
0
int do_restore_client(struct asfd *asfd,
	struct conf **confs, enum action act, int vss_restore)
{
	int ret=-1;
	char msg[512]="";
	struct sbuf *sb=NULL;
	struct blk *blk=NULL;
	BFILE *bfd=NULL;
	char *fullpath=NULL;
	char *style=NULL;
	char *datpath=NULL;
	struct cntr *cntr=get_cntr(confs);
	enum protocol protocol=get_protocol(confs);
	int strip=get_int(confs[OPT_STRIP]);
	int overwrite=get_int(confs[OPT_OVERWRITE]);
	const char *backup=get_string(confs[OPT_BACKUP]);
	const char *regex=get_string(confs[OPT_REGEX]);
	const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]);
	const char *encryption_password=get_string(confs[OPT_ENCRYPTION_PASSWORD]);

	if(!(bfd=bfile_alloc())) goto end;

	bfile_init(bfd, 0, cntr);

	snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act),
		backup?backup:"", regex?regex:"");
	logp("doing %s\n", msg);
	if(asfd->write_str(asfd, CMD_GEN, msg)
	  || asfd_read_expect(asfd, CMD_GEN, "ok"))
		goto error;
	logp("doing %s confirmed\n", act_str(act));

#if defined(HAVE_WIN32)
	if(act==ACTION_RESTORE) win32_enable_backup_privileges();
#endif

	if(!(style=get_restore_style(asfd, confs)))
		goto error;
	if(!strcmp(style, RESTORE_SPOOL))
	{
		if(restore_spool(asfd, confs, &datpath))
			goto error;
	}
	else
		logp("Streaming restore direct\n");

	logf("\n");

	if(get_int(confs[OPT_SEND_CLIENT_CNTR]) && cntr_recv(asfd, confs))
		goto error;

	if(!(sb=sbuf_alloc(protocol))
	  || (protocol==PROTO_2 && !(blk=blk_alloc())))
	{
		log_and_send_oom(asfd, __func__);
		goto error;
	}

	while(1)
	{
		sbuf_free_content(sb);
		if(protocol==PROTO_1)
			sb->flags |= SBUF_CLIENT_RESTORE_HACK;

		switch(sbuf_fill_from_net(sb, asfd, blk, datpath, cntr))
		{
			case 0: break;
			case 1: if(asfd->write_str(asfd, CMD_GEN,
				"restoreend ok")) goto error;
				goto end; // It was OK.
			default:
			case -1: goto error;
		}

		if(protocol==PROTO_2)
		{
			if(blk->data)
			{
				int wret=0;
				if(act==ACTION_VERIFY)
					cntr_add(cntr, CMD_DATA, 1);
				else
					wret=write_data(asfd, bfd, blk);
				if(!datpath) blk_free_content(blk);
				blk->data=NULL;
				if(wret) goto error;
				continue;
			}
			else if(sb->endfile.buf)
			{
				continue;
			}
		}

		switch(sb->path.cmd)
		{
			case CMD_DIRECTORY:
			case CMD_FILE:
			case CMD_ENC_FILE:
			case CMD_SOFT_LINK:
			case CMD_HARD_LINK:
			case CMD_SPECIAL:
			case CMD_METADATA:
			case CMD_ENC_METADATA:
			case CMD_VSS:
			case CMD_ENC_VSS:
			case CMD_VSS_T:
			case CMD_ENC_VSS_T:
			case CMD_EFS_FILE:
				if(strip)
				{
					int s;
					s=strip_path_components(asfd,
						sb, strip, cntr, protocol);
					if(s<0) goto error;
					if(s==0)
					{
						// Too many components stripped
						// - carry on.
						continue;
					}
					// It is OK, sb.path is now stripped.
				}
				free_w(&fullpath);
				if(!(fullpath=prepend_s(restore_prefix,
					sb->path.buf)))
				{
					log_and_send_oom(asfd, __func__);
					goto error;
				}
				if(act==ACTION_RESTORE)
				{
				  strip_invalid_characters(&fullpath);
				  if(!overwrite_ok(sb, overwrite,
#ifdef HAVE_WIN32
					bfd,
#endif
					fullpath))
				  {
					char msg[512]="";
					// Something exists at that path.
					snprintf(msg, sizeof(msg),
						"Path exists: %s\n", fullpath);
					if(restore_interrupt(asfd,
						sb, msg, cntr, protocol))
							goto error;
					continue;
				  }
				}
				break;
			case CMD_MESSAGE:
			case CMD_WARNING:
				log_recvd(&sb->path, cntr, 1);
				logf("\n");
				continue;
			default:
				break;
		}

		switch(sb->path.cmd)
		{
			// These are the same in both protocol1 and protocol2.
			case CMD_DIRECTORY:
				if(restore_dir(asfd, sb, fullpath, act, cntr,
					protocol))
						goto error;
				continue;
			case CMD_SOFT_LINK:
			case CMD_HARD_LINK:
				if(restore_link(asfd, sb, fullpath, act, cntr,
					protocol, restore_prefix))
						goto error;
				continue;
			case CMD_SPECIAL:
				if(restore_special(asfd, sb,
					fullpath, act, cntr, protocol))
						goto error;
				continue;
			default:
				break;
		}

		if(protocol==PROTO_2)
		{
			if(restore_switch_protocol2(asfd, sb, fullpath, act,
				bfd, vss_restore, cntr))
					goto error;
		}
		else
		{
			if(restore_switch_protocol1(asfd, sb, fullpath, act,
				bfd, vss_restore, cntr, encryption_password))
					goto error;
		}
	}

end:
	ret=0;
error:
	// It is possible for a fd to still be open.
	bfd->close(bfd, asfd);
	bfile_free(&bfd);

	cntr_print_end(cntr);
	cntr_print(cntr, act);

	if(!ret) logp("%s finished\n", act_str(act));
	else logp("ret: %d\n", ret);

	sbuf_free(&sb);
	free_w(&style);
	if(datpath)
	{
		recursive_delete(datpath);
		free_w(&datpath);
	}
	free_w(&fullpath);
	blk_free(&blk);

	return ret;
}
Пример #6
0
int do_list_client(struct asfd *asfd, enum action act, struct conf **confs)
{
	int ret=-1;
	char msg[512]="";
	struct sbuf *sb=NULL;
	struct iobuf *rbuf=asfd->rbuf;
	const char *backup=get_string(confs[OPT_BACKUP]);
	const char *backup2=get_string(confs[OPT_BACKUP2]);
	const char *browsedir=get_string(confs[OPT_BROWSEDIR]);
	const char *regex=get_string(confs[OPT_REGEX]);
//logp("in do_list\n");

	switch(act)
	{
		case ACTION_LIST:
		case ACTION_LIST_LONG:
			if(browsedir && regex)
			{
				logp("You cannot specify both a directory and a regular expression when listing.\n");
				goto end;
			}
			if(browsedir)
				snprintf(msg, sizeof(msg), "listb %s:%s",
					backup?backup:"", browsedir);
			else
				snprintf(msg, sizeof(msg), "list %s:%s",
					backup?backup:"", regex?regex:"");
			break;
		case ACTION_DIFF:
		case ACTION_DIFF_LONG:
			snprintf(msg, sizeof(msg), "diff %s:%s",
				backup?backup:"", backup2?backup2:"");
			break;
		default:
			logp("unknown action %d\n", act);
			goto end;
	}
	if(asfd->write_str(asfd, CMD_GEN, msg)
	  || asfd_read_expect(asfd, CMD_GEN, "ok"))
		goto end;

	if(!(sb=sbuf_alloc(get_protocol(confs)))) goto end;
	iobuf_init(&sb->path);
	iobuf_init(&sb->link);
	iobuf_init(&sb->attr);

	// This should probably should use the sbuf stuff.
	while(1)
	{
		sbuf_free_content(sb);

		iobuf_free_content(rbuf);
		if(asfd->read(asfd)) break;
		if(rbuf->cmd==CMD_MESSAGE)
		{
			printf("%s\n", rbuf->buf);
			if(!strcmp(rbuf->buf, "no backups"))
				ret=0;
			goto end;
		}
		else if(rbuf->cmd==CMD_TIMESTAMP)
		{
			// A backup timestamp, just print it.
			printf("Backup: %s\n", rbuf->buf);
			if(browsedir)
				printf("Listing directory: %s\n",
				       browsedir);
			if(regex)
				printf("With regex: %s\n",
				       regex);
			continue;
		}
		else if(rbuf->cmd!=CMD_ATTRIBS)
		{
			iobuf_log_unexpected(rbuf, __func__);
			goto end;
		}
		iobuf_copy(&sb->attr, rbuf);
		iobuf_init(rbuf);

		attribs_decode(sb);

		if(asfd->read(asfd))
		{
			logp("got stat without an object\n");
			goto end;
		}
		iobuf_copy(&sb->path, rbuf);
		iobuf_init(rbuf);

		if(sb->path.cmd==CMD_DIRECTORY
			|| sb->path.cmd==CMD_FILE
			|| sb->path.cmd==CMD_ENC_FILE
			|| sb->path.cmd==CMD_EFS_FILE
			|| sb->path.cmd==CMD_SPECIAL)
		{
			list_item(act, sb);
		}
		else if(cmd_is_link(sb->path.cmd)) // symlink or hardlink
		{
			if(asfd->read(asfd)
			  || rbuf->cmd!=sb->path.cmd)
			{
				logp("could not get link %s\n",
					iobuf_to_printable(&sb->path));
				goto end;
			}
			iobuf_copy(&sb->link, rbuf);
			iobuf_init(rbuf);
			list_item(act, sb);
		}
		else
		{
			logp("unlistable %s\n", iobuf_to_printable(&sb->path));
		}
	}

	ret=0;
end:
	sbuf_free(&sb);
	if(!ret) logp("List finished ok\n");
	return ret;
}
Пример #7
0
/* This function reads the manifest to determine whether it may be more
   efficient to just copy the data files across and unpack them on the other
   side. If it thinks it is, it will then do it.
   Return -1 on error, 1 if it copied the data across, 0 if it did not. */
int maybe_restore_spool(struct asfd *asfd, const char *manifest,
	struct sdirs *sdirs, struct bu *bu, int srestore, regex_t *regex,
	struct conf **confs, struct slist *slist,
	enum action act, enum cntr_status cntr_status)
{
	int ars;
	int ret=-1;
	struct sbuf *sb=NULL;
	struct blk *blk=NULL;
	struct manio *manio=NULL;
	uint64_t blkcount=0;
	uint64_t datcount=0;
	struct hash_weak *tmpw;
	struct hash_weak *hash_weak;
	uint64_t estimate_blks;
	uint64_t estimate_dats;
	uint64_t estimate_one_dat;
	struct sbuf *need_data=NULL;
	int last_ent_was_dir=0;
	char sig[128]="";
	const char *restore_spool=get_string(confs[OPT_RESTORE_SPOOL]);

	// If the client has no restore_spool directory, we have to fall back
	// to the stream style restore.
	if(!restore_spool) return 0;
	
	if(!(manio=manio_open(manifest, "rb", PROTO_2))
	  || !(need_data=sbuf_alloc(PROTO_2))
	  || !(sb=sbuf_alloc(PROTO_2))
	  || !(blk=blk_alloc()))
		goto end;

	while(1)
	{
		if((ars=manio_read_with_blk(manio, sb, blk, NULL))<0)
		{
			logp("Error from manio_read_async() in %s\n",
				__func__);
			goto end; // Error;
		}
		else if(ars>0)
			break; // Finished OK.

		if(!blk->got_save_path)
		{
			sbuf_free_content(sb);
			continue;
		}

		if(want_to_restore(srestore, sb, regex, confs))
		{
			blkcount++;
			if(!hash_weak_find((uint64_t)blk->savepath))
			{
				if(!hash_weak_add((uint64_t)blk->savepath))
					goto end;
				datcount++;
			}
		}

		sbuf_free_content(sb);
	}

	// FIX THIS: should read rabin_avg of a struct rconf.
	estimate_blks=blkcount*RABIN_AVG;
	estimate_one_dat=DATA_FILE_SIG_MAX*RABIN_AVG;
	estimate_dats=datcount*estimate_one_dat;
	printf("%"PRIu64 " blocks = %"PRIu64 " bytes in stream approx\n",
		blkcount, estimate_blks);
	printf("%"PRIu64 " data files = %"PRIu64 " bytes approx\n",
		datcount, estimate_dats);

	if(estimate_blks < estimate_one_dat)
	{
		printf("Stream is less than the size of a data file.\n");
		printf("Use restore stream\n");
		return 0;
	}
	else if(estimate_dats >= 90*(estimate_blks/100))
	{
		printf("Stream is more than 90%% size of data files.\n");
		printf("Use restore stream\n");
		return 0;
	}
	else
	{
		printf("Data files are less than 90%% size of stream.\n");
		printf("Use data files\n");
	}

	printf("Client is using restore_spool: %s\n", restore_spool);

	if(asfd->write_str(asfd, CMD_GEN, "restore_spool")
	  || asfd_read_expect(asfd, CMD_GEN, "restore_spool_ok"))
		goto end;

	// Send each of the data files that we found to the client.
	HASH_ITER(hh, hash_table, hash_weak, tmpw)
	{
		char msg[32];
		char path[32];
		char *fdatpath=NULL;
		snprintf(path, sizeof(path), "%014"PRIX64, hash_weak->weak);
		path[4]='/';
		path[9]='/';
		snprintf(msg, sizeof(msg), "dat=%s", path);
		printf("got: %s\n", msg);
		if(asfd->write_str(asfd, CMD_GEN, msg)) goto end;
		if(!(fdatpath=prepend_s(sdirs->data, path)))
			goto end;
		if(send_a_file(asfd, fdatpath, get_cntr(confs)))
		{
			free_w(&fdatpath);
			goto end;
		}
		free_w(&fdatpath);
	}