Example #1
25
int
ct_compare_secrets(struct ct_global_state *state, struct ct_op *op)
{
	struct ct_ctfileop_args		*cca = op->op_args;
	FILE				*f, *tf;
	char				 temp_path[PATH_MAX];
	struct stat			 sb, tsb;
	char				 buf[1024], tbuf[1024];
	size_t				 rsz;
	off_t				 sz;
	int				 ret = 0, s_errno = 0;

	/* cachedir is '/' terminated */
	strlcpy(temp_path, cca->cca_tdir, sizeof(temp_path));
	strlcat(temp_path, cca->cca_localname, sizeof(temp_path));
	if (stat(state->ct_config->ct_crypto_secrets, &sb) != 0) {
		s_errno = errno;
		ret = CTE_ERRNO;
		CWARNX("\"%s\": %s", state->ct_config->ct_crypto_secrets,
		    ct_strerror(ret));
		goto free;
	}
	if (stat(temp_path, &tsb) != 0) {
		s_errno = errno;
		ret = CTE_ERRNO;
		CWARNX("\"%s\": %s", temp_path, ct_strerror(ret));
		goto free;
	}

	/* Compare size first */
	if (tsb.st_size != sb.st_size) {
		ret = CTE_SECRETS_FILE_SIZE_MISMATCH;
		CWARNX("%" PRId64 " vs %" PRId64 ": %s", (int64_t)tsb.st_size,
		    (int64_t)sb.st_size, ct_strerror(ret));
		goto free;
	}

	if ((f = ct_fopen(state->ct_config->ct_crypto_secrets, "rb")) == NULL) {
		s_errno = errno;
		ret = CTE_ERRNO;
		CWARNX("\"%s\": %s", state->ct_config->ct_crypto_secrets,
		    ct_strerror(ret));
		goto free;
	}
	if ((tf = ct_fopen(temp_path, "rb")) == NULL) {
		s_errno = errno;
		ret = CTE_ERRNO;
		CWARNX("temp_path: %s", ct_strerror(ret));
		goto close_current;
	}
	/* read then throw away */
	unlink(temp_path);
	while (sb.st_size > 0) {
		sz = sb.st_size;
		if (sz > 1024)
			sz = 1024;
		sb.st_size -= sz;
		CNDBG(CT_LOG_FILE, "sz = %" PRId64 " remaining = %" PRId64,
		    (int64_t)sz, (int64_t)sb.st_size);
		if ((rsz = fread(buf, 1, sz, f)) != sz) {
			CNDBG(CT_LOG_CRYPTO, "short read on secrets file (%"
			    PRId64 " %" PRId64 ")", (int64_t)sz, (int64_t)rsz);
			ret = CTE_SECRETS_FILE_SHORT_READ;
			CWARNX("%s: %s", state->ct_config->ct_crypto_secrets,
			    ct_strerror(ret));
			goto out;
		}
		if ((rsz = fread(tbuf, 1, sz, tf)) != sz) {
			CNDBG(CT_LOG_CRYPTO, "short read on temporary secrets "
			    "file (%" PRId64 " %" PRId64 ")", (int64_t)sz,
			    (int64_t)rsz);
			ret = CTE_SECRETS_FILE_SHORT_READ;
			CWARNX("%s: %s", temp_path, ct_strerror(ret));
			goto out;
		}

		if (memcmp(buf, tbuf, sz) != 0) {
			ret = CTE_SECRETS_FILE_DIFFERS;
			goto out;
		}
	}
out:
	fclose(f);
close_current:
	fclose(tf);
free:
	e_free(&cca);

	if (ret == CTE_ERRNO)
		errno = s_errno;
	return (ret);
}
Example #2
0
int
ct_get_password(char *password, size_t passwordlen, char *prompt, int verify)
{
	int			rv = 1;
	char			pw[CT_PASS_MAX + 1];

	if (readpassphrase(prompt ? prompt : "New password: "******"invalid password");
		goto done;
	}
	if (verify) {
		if (readpassphrase("Retype password: "******"invalid password");
			goto done;
		}
		if (strcmp(password, pw)) {
			CWARNX("passwords do not match");
			goto done;
		}
	}
	if (strlen(password) == 0) {
		CWARNX("password must not be empty");
		goto done;
	}

	rv = 0;
done:
	bzero(pw, sizeof pw);
	return (rv);
}
Example #3
0
uint64_t
ct_get_debugmask(char *debugstring)
{
	char		*cur, *next;
	uint64_t	 debug_mask = 0;
	int		 i, neg;

	struct debuglvl {
		const char	*name;
		uint64_t	 mask;
	} debuglevels[] = {
		{ "socket", CT_LOG_SOCKET },
		{ "config", CT_LOG_CONFIG },
		{ "exude", CT_LOG_EXUDE },
		{ "net", CT_LOG_NET },
		{ "trans", CT_LOG_TRANS },
		{ "sha", CT_LOG_SHA },
		{ "ctfile", CT_LOG_CTFILE },
		{ "db", CT_LOG_DB },
		{ "crypto", CT_LOG_CRYPTO },
		{ "file", CT_LOG_FILE },
		{ "xml", CT_LOG_XML },
		{ "vertree", CT_LOG_VERTREE },
		{ "all", ~(0ULL) },
	};

	next = debugstring;
	while ((cur = next) != NULL) {
		neg = 0;
		if ((next = strchr(next + 1, ',')) != NULL) {
			*(next++) = '\0';
		}
		if (*cur == '-') {
			neg = 1;
			cur++;
		}
		for (i = 0; i < nitems(debuglevels); i++) {
			if (strcasecmp(debuglevels[i].name,
			    cur) == 0)
				break;
		}
		if (i == nitems(debuglevels)) {
			CWARNX("unrecognized debug option:"
			    "\"%s\"", cur);
			 continue;
		}

		if (neg)
			debug_mask &= ~debuglevels[i].mask;
		else
			debug_mask |= debuglevels[i].mask;
	}

	return (debug_mask);
}
Example #4
0
int
ct_extract_complete_file_end(struct ct_global_state *state,
    struct ct_trans *trans)
{
	if (trans->tr_fl_node->fn_skip_file == 0) {
		ct_sha1_final(trans->tr_csha,
		    &trans->tr_fl_node->fn_shactx);
		if (memcmp(trans->tr_csha, trans->tr_sha,
		    sizeof(trans->tr_sha)) != 0)
			CWARNX("extract sha mismatch on %s",
			    trans->tr_fl_node->fn_fullname);
		ct_file_extract_close(state->extract_state,
		    trans->tr_fl_node);
		state->ct_print_file_end(state->ct_print_state,
		    trans->tr_fl_node, state->ct_max_block_size);
	}
	state->ct_stats->st_files_completed++;

	return (0);
}
Example #5
0
enum ctdb_lookup
ctdb_lookup_sha(struct ctdb_state *state, uint8_t *sha_k, uint8_t *sha_v,
     uint8_t *iv, int32_t *old_genid)
{
	char			 shat[SHA_DIGEST_STRING_LENGTH];
	int			 rv, rc;
	int32_t			 genid;
	uint8_t			*p;
	sqlite3_stmt		*stmt;

	rv = CTDB_SHA_NEXISTS;
	*old_genid = -1;

	if (state == NULL || state->ctdb_db == NULL)
		return rv;

	stmt = state->ctdb_stmt_lookup;

	if (state->ctdb_in_transaction == 0) {
		if (ctdb_begin_transaction(state) != 0)
			return (rv);
		state->ctdb_trans_commit_rem = OPS_PER_TRANSACTION;
	}

	if (clog_mask_is_set(CT_LOG_DB)) {
		ct_sha1_encode(sha_k, shat);
		CNDBG(CT_LOG_DB, "looking for bin %s", shat);
	}
	if (sqlite3_bind_blob(stmt, 1, sha_k, SHA_DIGEST_LENGTH,
	    SQLITE_STATIC)) {
		CNDBG(CT_LOG_DB, "could not sha");
		return (CTDB_SHA_NEXISTS);
	}

	rc = sqlite3_step(stmt);
	if (rc == SQLITE_DONE) {
		CNDBG(CT_LOG_DB, "not found");
		sqlite3_reset(stmt);
		return CTDB_SHA_NEXISTS;
	} else if (rc != SQLITE_ROW) {
		CNDBG(CT_LOG_DB, "could not step(%d) %d %d %s",
		    __LINE__, rc,
		    sqlite3_extended_errcode(state->ctdb_db),
		    sqlite3_errmsg(state->ctdb_db));
		sqlite3_reset(stmt);
		return CTDB_SHA_NEXISTS;
	}

	CNDBG(CT_LOG_DB, "found");

	p = (uint8_t *)sqlite3_column_blob(stmt, 0);
	if (p) {
		if (sqlite3_column_bytes(stmt, 0) !=
		    SHA_DIGEST_LENGTH) {
			CNDBG(CT_LOG_DB, "invalid blob size");
			sqlite3_reset(stmt);
			return rv;
		}

		if (clog_mask_is_set(CT_LOG_DB)) {
			ct_sha1_encode(p, shat);
			CNDBG(CT_LOG_DB, "found bin %s", shat);
		}

		rv = CTDB_SHA_EXISTS;
		bcopy (p, sha_v, SHA_DIGEST_LENGTH);
	} else {
		CNDBG(CT_LOG_DB, "no bin found");
	}
	if (state->ctdb_crypt) {
		p = (uint8_t *)sqlite3_column_blob(stmt, 1);
		if (p) {
			if (sqlite3_column_bytes(stmt, 1) != CT_IV_LEN) {
				CNDBG(CT_LOG_DB, "invalid blob size");
				sqlite3_reset(stmt);
				rv = CTDB_SHA_NEXISTS;
				return rv;
			}
			if (clog_mask_is_set(CT_LOG_DB)) {
				ct_sha1_encode(p, shat);
				CNDBG(CT_LOG_DB, "found iv (prefix) %s", shat);
			}

			bcopy (p, iv, CT_IV_LEN);
		} else {
			CNDBG(CT_LOG_DB, "no iv found");
			rv = CTDB_SHA_NEXISTS;
		}

		genid = sqlite3_column_int(stmt, 2);
	} else {
		genid = sqlite3_column_int(stmt, 1);
	}
	sqlite3_reset(stmt);

	if (genid < state->ctdb_genid) {
		ct_sha1_encode(sha_k, shat);
		rv = CTDB_SHA_MAYBE_EXISTS;
		*old_genid = genid;
	} else if (genid > state->ctdb_genid) {
		/* XXX Abort? */
		CWARNX("WARNING: sha with higher genid than database!");
	}


	state->ctdb_trans_commit_rem--;
	if (state->ctdb_trans_commit_rem <= 0) {
		ctdb_end_transaction(state);
	}

	return rv;
}
Example #6
0
void
ct_extract(struct ct_global_state *state, struct ct_op *op)
{
	struct ct_extract_args	*cea = op->op_args;
	const char		*ctfile = cea->cea_local_ctfile;
	char			**filelist = cea->cea_filelist;
	int			 match_mode = cea->cea_matchmode;
	struct ct_extract_priv	*ex_priv = op->op_priv;
	int			ret;
	struct ct_trans		*trans;
	char			shat[SHA_DIGEST_STRING_LENGTH];

	/* if we were woken up due to fatal, just clean up local state */
	if (state->ct_dying != 0)
		goto dying;

	CNDBG(CT_LOG_TRANS, "entry");
	switch (ct_get_file_state(state)) {
	case CT_S_STARTING:
		if (ex_priv == NULL) {
			ex_priv = e_calloc(1, sizeof(*ex_priv));
			TAILQ_INIT(&ex_priv->extract_head);

			if ((ret = ct_match_compile(&ex_priv->inc_match,
			    match_mode, filelist)) != 0) {
				ct_fatal(state,
				    "failed to compile include pattern", ret);
				goto dying;
			}
			if (cea->cea_excllist != NULL &&
			    (ret = ct_match_compile(&ex_priv->ex_match,
			    match_mode, cea->cea_excllist)) != 0) {
				ct_fatal(state,
				    "failed to compile exclude pattern", ret);
				goto dying;
			}
			op->op_priv = ex_priv;
			RB_INIT(&ex_priv->pending_tree);
		}
		
		if ((ret = ct_file_extract_init(&state->extract_state,
		    cea->cea_tdir, cea->cea_attr,  cea->cea_follow_symlinks,
		    ex_priv->allfiles, cea->cea_log_state,
		    cea->cea_log_chown_failed)) != 0) {
			ct_fatal(state, "Can not initialize extract state",
			    ret);
			goto dying;
		}

		if (ct_extract_calculate_total(state, cea, ex_priv->inc_match,
		    ex_priv->ex_match) != 0) {
			CWARNX("failed to calculate stats");
			goto dying;
		}

		if ((ret = ct_extract_setup(&ex_priv->extract_head,
		    &ex_priv->xdr_ctx, ctfile, cea->cea_ctfile_basedir,
		    &ex_priv->allfiles)) != 0) {
			ct_fatal(state, "can't setup extract queue", ret);
			goto dying;
		}
		state->ct_print_ctfile_info(state->ct_print_state,
		    ex_priv->xdr_ctx.xs_filename, &ex_priv->xdr_ctx.xs_gh);
		/* XXX we should handle this better */
		if (state->ct_max_block_size <
		    ex_priv->xdr_ctx.xs_gh.cmg_chunk_size)
			CABORTX("block size negotiated with server %d is "
			    "smaller than file max block size %d",
			    state->ct_max_block_size,
			    ex_priv->xdr_ctx.xs_gh.cmg_chunk_size);
		/* create rb tree head, prepare to start inserting */
		if (ex_priv->allfiles) {
			ex_priv->fillrb = 1;
		}
		break;
	case CT_S_FINISHED:
		return;
	default:
		break;
	}

	ct_set_file_state(state, CT_S_RUNNING);
	while (1) {
		trans = ct_trans_alloc(state);
		if (trans == NULL) {
			/* system busy, return */
			CNDBG(CT_LOG_TRANS, "ran out of transactions, waiting");
			ct_set_file_state(state, CT_S_WAITING_TRANS);
			return;
		}
		trans->tr_statemachine = ct_state_extract;

		switch ((ret = ctfile_parse(&ex_priv->xdr_ctx))) {
		case XS_RET_FILE:
			if (ex_priv->fillrb == 0 &&
			    ex_priv->xdr_ctx.xs_hdr.cmh_nr_shas == -1) {
				if (ex_priv->allfiles == 0)
					CINFO("file %s has negative shas "
					    "and backup is not allfiles",
					    ex_priv->xdr_ctx.xs_hdr.cmh_filename);
				ex_priv->doextract = 0;
				goto skip; /* skip ze file for now */
			}

			trans = ct_trans_realloc_local(state, trans);
			trans->tr_fl_node = ex_priv->fl_ex_node = 
			    ct_alloc_fnode();

			ct_populate_fnode(state->extract_state,
			    &ex_priv->xdr_ctx, trans->tr_fl_node,
			    &trans->tr_state, ex_priv->allfiles,
			    cea->cea_strip_slash);
			if (trans->tr_state == TR_S_EX_SPECIAL) {
				trans->tr_complete =
				    ct_extract_complete_special;
			} else {
				trans->tr_complete =
				    ct_extract_complete_file_start;
			}
			trans->tr_cleanup = ct_extract_cleanup_fnode;

			if (ex_priv->haverb) {
				struct ct_pending_file *cpf;
				if ((cpf = ct_extract_find_entry(
				    &ex_priv->pending_tree,
				    trans->tr_fl_node->fn_fullname)) != NULL) {
					struct fnode *hardlink;
					/* copy permissions over */
					trans->tr_fl_node->fn_uid =
					    cpf->cpf_uid;
					trans->tr_fl_node->fn_gid =
					    cpf->cpf_gid;
					trans->tr_fl_node->fn_mode =
					    cpf->cpf_mode;
					trans->tr_fl_node->fn_mtime =
					    cpf->cpf_mtime;
					trans->tr_fl_node->fn_atime =
					    cpf->cpf_atime;

					/* copy list of pending links over */
					while ((hardlink =
					    TAILQ_FIRST(&cpf->cpf_links))) {
						TAILQ_REMOVE(&cpf->cpf_links,
						    hardlink, fn_list);
						TAILQ_INSERT_TAIL(
						    &trans->tr_fl_node->fn_hardlinks,
						    hardlink, fn_list);
					}
					
					ex_priv->doextract = 1;
					ct_extract_free_entry(
					    &ex_priv->pending_tree, cpf);
				} else {
					ex_priv->doextract = 0;
				}
				
			} else {
				ex_priv->doextract =
				    !ct_match(ex_priv->inc_match,
				    trans->tr_fl_node->fn_fullname);
				if (ex_priv->doextract &&
				    ex_priv->ex_match != NULL &&
				    !ct_match(ex_priv->ex_match,
				    trans->tr_fl_node->fn_fullname)) {
					ex_priv->doextract = 0;
				}
			}
			if (ex_priv->doextract &&
			    trans->tr_fl_node->fn_hardlink) {
				struct ct_pending_file	*file;
				if ((file = ct_extract_find_entry(
				    &ex_priv->pending_tree,
				    trans->tr_fl_node->fn_hlname)) != NULL) {
					CNDBG(CT_LOG_FILE,
					    "adding pending link for %s to %s",
					    file->cpf_name,
					    trans->tr_fl_node->fn_fullname);
					/* our reference to node passed */
					ct_pending_file_add_link(file,
					    trans->tr_fl_node);
					ex_priv->doextract = 0;
					goto skip;
				}
			}

			/*
			 * If we're on the first ctfile in an allfiles backup
			 * put the matches with -1 on the rb tree so we'll
			 * remember to extract it from older files.
			 */
			if (ex_priv->doextract == 1 && ex_priv->fillrb &&
			    ex_priv->xdr_ctx.xs_hdr.cmh_nr_shas == -1) {
				ct_extract_insert_entry(&ex_priv->pending_tree,
				    trans->tr_fl_node);

				ex_priv->doextract = 0;
				/* XXX reconsider the freeing */
			}
			if (ex_priv->doextract == 0) {
				ct_free_fnode(trans->tr_fl_node);
skip:
				ex_priv->fl_ex_node = NULL;
				ct_trans_free(state, trans);
				continue;
			}

			CNDBG(CT_LOG_CTFILE,
			    "file %s numshas %" PRId64,
			    trans->tr_fl_node->fn_fullname,
			    ex_priv->xdr_ctx.xs_hdr.cmh_nr_shas);

			/*
			 * special files we give our refcount up
			 * regular files we need a new one since we need to
			 * keep ours.
			 */
			if (trans->tr_state != TR_S_EX_SPECIAL) {
				ct_ref_fnode(trans->tr_fl_node);
			} else {
				ex_priv->fl_ex_node = NULL;
			}
			ct_queue_first(state, trans);
			break;
		case XS_RET_SHA:
			if (ex_priv->doextract == 0 ||
			    ex_priv->fl_ex_node->fn_skip_file != 0) {
				if (ctfile_parse_seek(&ex_priv->xdr_ctx)) {
					ct_fatal(state, "Can't seek past shas",
					    ex_priv->xdr_ctx.xs_errno);
					goto dying;
				}
				ct_trans_free(state, trans);
				continue;
			}

			/* use saved fnode */
			trans->tr_fl_node = ex_priv->fl_ex_node;

			if (memcmp(zerosha, ex_priv->xdr_ctx.xs_sha,
				SHA_DIGEST_LENGTH) == 0) {
				CWARNX("\"%s\" truncated during backup",
				    trans->tr_fl_node->fn_fullname);
				if (ctfile_parse_seek(&ex_priv->xdr_ctx)) {
					ct_fatal(state, "Can't seek past "
					    "truncation shas",
					    ex_priv->xdr_ctx.xs_errno);
					goto dying;
				}
				ct_trans_free(state, trans);
				continue;
			}

			if (ex_priv->xdr_ctx.xs_gh.cmg_flags & CT_MD_CRYPTO) {
				/*
				 * yes csha and sha are reversed, we want
				 * to download csha, but putting it in sha
				 * simplifies the code
				 */
				bcopy(ex_priv->xdr_ctx.xs_sha, trans->tr_csha,
				    sizeof(trans->tr_csha));
				bcopy(ex_priv->xdr_ctx.xs_csha, trans->tr_sha,
				    sizeof(trans->tr_sha));
				bcopy(ex_priv->xdr_ctx.xs_iv, trans->tr_iv,
				    sizeof(trans->tr_iv));
			} else {
				bcopy(ex_priv->xdr_ctx.xs_sha, trans->tr_sha,
				    sizeof(trans->tr_sha));
			}
			if (clog_mask_is_set(CT_LOG_SHA)) {
				ct_sha1_encode(trans->tr_sha, shat);
				CNDBG(CT_LOG_SHA, "extracting sha %s", shat);
			}
			trans->tr_state = TR_S_EX_SHA;
			trans->tr_complete = ct_extract_complete_file_read;
			trans->tr_dataslot = 0;
			ct_ref_fnode(trans->tr_fl_node);
			trans->tr_cleanup = ct_extract_cleanup_fnode;
			ct_queue_first(state, trans);
			break;
		case XS_RET_FILE_END:
			trans = ct_trans_realloc_local(state, trans);


			if (ex_priv->doextract == 0 ||
			    ex_priv->fl_ex_node->fn_skip_file != 0) {
				/* release our reference done with file */
				if (ex_priv->fl_ex_node) {
					ct_free_fnode(ex_priv->fl_ex_node);
					ex_priv->fl_ex_node = NULL;
				}
				ct_trans_free(state, trans);
				continue;
			}

			/* use saved fnode from state */
			trans->tr_fl_node = ex_priv->fl_ex_node;
			bcopy(ex_priv->xdr_ctx.xs_trl.cmt_sha, trans->tr_sha,
			    sizeof(trans->tr_sha));
			trans->tr_state = TR_S_EX_FILE_END;
			trans->tr_complete = ct_extract_complete_file_end;
			trans->tr_cleanup = ct_extract_cleanup_fnode;
			trans->tr_fl_node->fn_size =
			    ex_priv->xdr_ctx.xs_trl.cmt_orig_size;
			/*
			 * no reference here since we give our reference to the
			 * last transaction on that file. We are done with it.
			 */
			ex_priv->fl_ex_node = NULL;
			ct_queue_first(state, trans);
			break;
		case XS_RET_EOF:
			CNDBG(CT_LOG_CTFILE, "Hit end of ctfile");
			ctfile_parse_close(&ex_priv->xdr_ctx);
			/* if rb tree and rb is empty, goto end state */
			if ((ex_priv->haverb || ex_priv->fillrb) &&
			    ct_extract_rb_empty(&ex_priv->pending_tree)) {
				/*
				 * Cleanup extract queue, in case we had files
				 * left.
				 */
				ct_extract_cleanup_queue(
				    &ex_priv->extract_head);
				goto we_re_done_here;
			}


			if (!TAILQ_EMPTY(&ex_priv->extract_head)) {
				/*
				 * if allfiles and this was the first pass.
				 * free the current match lists
				 * switch to rb tree mode
				 */
				if (ex_priv->fillrb) {
					ct_match_unwind(ex_priv->inc_match);
					if (ex_priv->ex_match)
						ct_match_unwind(
						    ex_priv->ex_match);
					ex_priv->ex_match = NULL;
					ex_priv->inc_match = NULL;
					ex_priv->haverb = 1;
					ex_priv->fillrb = 0;
				}
				ct_trans_free(state, trans);
				/* reinits ex_priv->xdr_ctx */
				if ((ret =
				    ct_extract_open_next(&ex_priv->extract_head,
				    &ex_priv->xdr_ctx)) != 0) {
					ct_fatal(state,
					    "Can't open next ctfile", ret);
					goto dying;
				}
				state->ct_print_ctfile_info(
				    state->ct_print_state,
				    ex_priv->xdr_ctx.xs_filename,
				    &ex_priv->xdr_ctx.xs_gh);

				/* poke file into action */
				ct_wakeup_file(state->event_state);
			} else {
				/*
				 * If rb tree and it is still has entries,
				 * bitch about it
				 */
				/* XXX print out missing files */
				if ((ex_priv->haverb || ex_priv->fillrb) &&
				    ct_extract_rb_empty(
				    &ex_priv->pending_tree)) {
					CWARNX("out of ctfiles but some "
					    "files are not found");
				}

we_re_done_here:
				if (ex_priv->inc_match)
					ct_match_unwind(ex_priv->inc_match);
				if (ex_priv->ex_match)
					ct_match_unwind(
					    ex_priv->ex_match);
				ct_extract_pending_cleanup(
				    &ex_priv->pending_tree);
				e_free(&ex_priv);
				op->op_priv = NULL;
				trans->tr_state = TR_S_DONE;
				trans->tr_complete = ct_extract_complete_done;
				trans->tr_cleanup = ct_extract_cleanup_done;
				/*
				 * Technically this should be a local
				 * transaction. However, since we are done
				 * it doesn't really matter either way.
				 */
				ct_queue_first(state, trans);
				CNDBG(CT_LOG_TRANS, "extract finished");
				ct_set_file_state(state, CT_S_FINISHED);
			}
			return;
			break;
		case XS_RET_FAIL:
			ct_fatal(state, "Failed to parse ctfile",
			    ex_priv->xdr_ctx.xs_errno);
			goto dying;
			break;
		}
	}

	return;

dying:
	/* only if we hadn't sent the final transaction yet */
	if (ex_priv != NULL) {
		ct_extract_cleanup_queue(&ex_priv->extract_head);
		if (ex_priv->inc_match)
			ct_match_unwind(ex_priv->inc_match);
		if (ex_priv->ex_match)
			ct_match_unwind(ex_priv->ex_match);
		if (!ct_extract_rb_empty(&ex_priv->pending_tree)) {
			ct_extract_pending_cleanup(&ex_priv->pending_tree);
		}
		if (ex_priv->fl_ex_node != NULL) {
			ct_free_fnode(ex_priv->fl_ex_node);
		}
		/* XXX what about ex_priv->xdr_ctx ? */
		e_free(&ex_priv);
		op->op_priv = NULL;
		/* if ex_priv is gone then the trans will clean this up */
		if (state->extract_state)
			ct_file_extract_cleanup(state->extract_state);	
	}
	return;
}
Example #7
0
int
ct_main(int argc, char **argv)
{
	struct ct_extract_args		 cea;
	struct ct_archive_args		 caa;
	struct ct_ctfileop_args 	 cca;
	struct ct_ctfile_list_args	 ccla;
	struct ct_ctfile_delete_args	 ccda;
	struct ct_global_state		*state = NULL;
	struct ct_config		*conf;
	char				*ct_tdir = NULL;
	char				*ct_basisbackup = NULL;
	char				*ctfile = NULL;
	char				*ct_includefile = NULL;
	char				*ct_excludefile = NULL;
	char				*configfile = NULL, *config_file = NULL;
	char				*basisfile = NULL;
	char				*debugstring = NULL;
	char				**excludelist = NULL;
	char				**includelist = NULL;
	uint64_t			 debug_mask = 0;
	uint32_t			 cflags = CLOG_F_ENABLE | CLOG_F_STDERR;
	int				 ct_metadata = 0;
	int				 ct_match_mode = CT_MATCH_GLOB;
	int				 c;
	int				 ret = 0;
	int				 level0 = 0;
	int				 freeincludes = 0;
	int				 no_cross_mounts = 0;
	int				 strip_slash = 1;
	int				 follow_root_symlink = 0;
	int				 follow_symlinks = 0;
	int				 attr = 0;
	int				 verbose_ratios = 0;
	int				 ct_flags = 0;

	while ((c = getopt(argc, argv,
	    "AB:C:D:E:F:HI:PRVXacdef:hmprtvx0")) != -1) {
		switch (c) {
		case 'A':
			/* noop, deprecated */
			break;
		case 'B':
			basisfile = optarg;
			break;
		case 'C':
			ct_tdir = optarg;
			break;
		case 'D':
			if (debugstring != NULL)
				CFATALX("only one -D argument is valid");
			debugstring = optarg;
			break;
		case 'E':
			ct_excludefile = optarg;
			break;
		case 'F':
			configfile = optarg;
			break;
		case 'H':
			follow_root_symlink = 1;
			break;
		case 'I':
			ct_includefile = optarg;
			break;
		case 'P':
			strip_slash = 0;
			break;
		case 'R':
			verbose_ratios = 1;
			break;
		case 'V':
			show_version();
			exit(0);
			break;
		case 'X':
			no_cross_mounts = 1;
			break;
		case 'a':
			/* noop, deprecated */
			break;
		case 'c':
			if (ct_action)
				CFATALX("cannot mix operations, -c -e -t -x");
			ct_action = CT_A_ARCHIVE;
			break;
		case 'e':
			if (ct_action)
				CFATALX("cannot mix operations, -c -e -t -x");
			ct_action = CT_A_ERASE;
			break;
		case 'f': /* metadata file */
			ctfile = optarg;
			break;
		case 'h':
			follow_symlinks = 1;
			break;
		case 'm': /* metadata processing - XXX temporary? */
			ct_metadata = 1;
			break;
		case 'r':
			ct_match_mode = CT_MATCH_REGEX;
			break;
		case 'p':
			attr = 1;
			break;
		case 't':
			if (ct_action)
				CFATALX("cannot mix operations, -c -e -t -x");
			ct_action = CT_A_LIST;
			break;
		case 'v':
			ct_verbose++;
			break;
		case 'x':
			if (ct_action)
				CFATALX("cannot mix operations, -c -e -t -x");
			ct_action = CT_A_EXTRACT;
			break;
		case '0':
			level0 = 1;
			break;
		default:
			ct_usage();
			/* NOTREACHED */
		}
	}

	argc -= optind;
	argv += optind;

	if (debugstring) {
		cflags |= CLOG_F_DBGENABLE | CLOG_F_FILE | CLOG_F_FUNC |
		    CLOG_F_LINE | CLOG_F_DTIME;
		exude_enable(CT_LOG_EXUDE);
#if CT_ENABLE_THREADS
		exude_enable_threads();
#endif
		debug_mask |= ct_get_debugmask(debugstring);
	}

	/* please don't delete this line AGAIN! --mp */
	if (clog_set_flags(cflags))
		errx(1, "illegal clog flags");
	clog_set_mask(debug_mask);

	/* We can allocate these now that we've decided if we need exude */
	if (configfile)
		config_file = e_strdup(configfile);
	if (basisfile)
		ct_basisbackup = e_strdup(basisfile);

	if (ct_includefile != NULL) {
		int nentries;

		if ((ct_action == CT_A_LIST || ct_action == CT_A_EXTRACT) &&
		    argc != 0)
			CFATALX("-I is invalid when a pattern is "
			    "provided on the command line");
		includelist = ct_matchlist_fromfile(ct_includefile,
		    &nentries);
		if (nentries == -1)
			CFATAL("can't get includelist from %s",
			    ct_includefile);

		freeincludes = 1;
	} else if ((ct_action == CT_A_LIST || ct_action == CT_A_EXTRACT)) {
		includelist = argv;
	}
	if (ct_excludefile != NULL) {
		int	nentries;
		excludelist = ct_matchlist_fromfile(ct_excludefile, &nentries);
		if (nentries == -1)
			CFATAL("can't get excludelsit from %s", ct_excludefile);
	}


	if ((ret = ct_load_config(&conf, &config_file)) != 0) {
		CFATALX("%s", ct_strerror(ret));
	}

	if (!(ct_metadata && (ct_action == CT_A_LIST ||
	    ct_action == CT_A_ERASE))) {
		if (ctfile == NULL) {
			CWARNX("ctfile is required");
			ct_usage();
		}

		if (conf->ct_ctfile_mode == CT_MDMODE_REMOTE &&
		    ctfile_verify_name(ctfile))
			CFATALX("invalid ctfile: %s", ctfile);
	}

	/*
	 * !metadata extract with no args extracts everything.
	 * and all lists show everything if not filtered
	 */
	if (((ct_metadata == 0 && ct_action == CT_A_EXTRACT) ||
	    ct_action == CT_A_LIST) && argc == 0)
		ct_match_mode = CT_MATCH_EVERYTHING;

	if (level0)
		conf->ct_auto_incremental = 0; /* force incremental off */

	if (conf->ct_ctfile_mode == CT_MDMODE_REMOTE && ct_metadata == 0 &&
	    ct_basisbackup != NULL)
		CFATALX("incremental basis in remote mode");

	/* Don't bother starting a connection if just listing local files. */
	if (ct_action == CT_A_LIST &&
	    conf->ct_ctfile_mode == CT_MDMODE_LOCAL &&
	    ct_metadata == 0 ) {
		ret = ct_list(ctfile, includelist, excludelist,
		    ct_match_mode, NULL, strip_slash, ct_verbose);
		goto out;
	}

	ct_prompt_for_login_password(conf);

	if (ct_action == CT_A_EXTRACT ||
	    ct_action == CT_A_ARCHIVE || (ct_action == CT_A_LIST &&
	    conf->ct_ctfile_mode == CT_MDMODE_REMOTE && ct_metadata == 0) ||
	    ct_action == CT_A_ERASE)
		ct_flags |= CT_NEED_SECRETS;
	if (ct_action == CT_A_ARCHIVE)
		ct_flags |= CT_NEED_DB;


	if ((ret = ct_init(&state, conf, ct_flags, ct_info_sig)) != 0)
		CFATALX("failed to initialise cyphertite: %s",
		    ct_strerror(ret));

#if defined(CT_EXT_INIT)
	CT_EXT_INIT(state);
#endif

	if (conf->ct_crypto_passphrase != NULL &&
	    conf->ct_secrets_upload != 0) {
		ct_add_operation(state, ctfile_list_start,
		    ct_check_secrets_extract, conf->ct_crypto_secrets);
	}

	if (ct_action == CT_A_EXTRACT)
		ct_set_log_fns(state, &ct_verbose, ct_print_ctfile_info,
		    ct_print_file_start, ct_print_file_end,
		    ct_print_traverse_start, ct_print_traverse_end);
	else if (ct_action == CT_A_ARCHIVE)
		ct_set_log_fns(state, &ct_verbose, ct_print_ctfile_info,
		    ct_pr_fmt_file, ct_pr_fmt_file_end,
		    ct_print_traverse_start, ct_print_traverse_end);

	if (conf->ct_ctfile_mode == CT_MDMODE_REMOTE && ct_metadata == 0) {
		switch (ct_action) {
		case CT_A_EXTRACT:
		case CT_A_LIST:
			cea.cea_local_ctfile = NULL; /* to be found */
			cea.cea_filelist = includelist;
			cea.cea_excllist = excludelist;
			cea.cea_matchmode = ct_match_mode;
			cea.cea_ctfile_basedir = conf->ct_ctfile_cachedir;
			cea.cea_tdir = ct_tdir;
			cea.cea_strip_slash = strip_slash;
			cea.cea_attr = attr;
			cea.cea_follow_symlinks = follow_symlinks;
			cea.cea_log_state = &ct_verbose;
			cea.cea_log_chown_failed =
			    ct_print_extract_chown_failed;
			ctfile_find_for_operation(state, ctfile,
			    ((ct_action == CT_A_EXTRACT)  ?
			    ctfile_nextop_extract : ctfile_nextop_list),
			    &cea, 1, 0);
			break;
		case CT_A_ARCHIVE:
			ct_normalize_filelist(argv);
			caa.caa_filelist = argv;
			caa.caa_excllist = excludelist;
			caa.caa_matchmode = ct_match_mode;
			caa.caa_includelist = includelist;
			caa.caa_tdir = ct_tdir;
			caa.caa_tag = ctfile;
			caa.caa_ctfile_basedir = conf->ct_ctfile_cachedir;
			/* we want to encrypt as long as we have keys */
			caa.caa_no_cross_mounts = no_cross_mounts;
			caa.caa_strip_slash = strip_slash;
			caa.caa_follow_root_symlink = follow_root_symlink;
			caa.caa_follow_symlinks = follow_symlinks;
			caa.caa_max_incrementals = conf->ct_max_incrementals;
			if (conf->ct_auto_incremental)
				/*
				 * Need to work out basis filename and
				 * download it if necessary
				 */
				ctfile_find_for_operation(state, ctfile,
				    ctfile_nextop_archive, &caa, 0, 1);
			else   {
				/* No basis, just start the op */
				ctfile_nextop_archive(state, NULL, &caa);
			}
			break;
		default:
			CWARNX("invalid action");
			ct_usage();
			/* NOTREACHED */
			break;
		}
	} else if (ct_metadata != 0) {
		if (ct_action == CT_A_ARCHIVE || ct_action == CT_A_EXTRACT) {
			cca.cca_localname = ctfile;
			cca.cca_remotename = NULL;
			cca.cca_tdir = ct_tdir;
			cca.cca_cleartext = 0;
			cca.cca_ctfile = 1;
			/* only matters for archive */
			ct_add_operation(state,
			    ((ct_action == CT_A_ARCHIVE) ?
			    ctfile_archive : ctfile_extract),
			    ctfile_op_cleanup, &cca);
		} else if (ct_action == CT_A_ERASE) {
			if (ctfile != NULL)
				CFATALX("-f is not permitted with -me operation");
			if (argc == 0)
				CFATALX("no files specified");
			ccda.ccda_pattern = argv;
			ccda.ccda_matchmode = ct_match_mode;
			ccda.ccda_callback = ct_print_delete;
			ct_add_operation(state, ctfile_list_start,
			    ctfile_process_delete, &ccda);
		} else if (ct_action == CT_A_LIST) {
			ccla.ccla_search = includelist;
			ccla.ccla_exclude = excludelist;
			ccla.ccla_matchmode = ct_match_mode;
			ct_add_operation(state, ctfile_list_start,
			    ctfile_list_print, &ccla);
		} else {
			CWARNX("must specify action");
			ct_usage();
			/* NOTREACHED */
		}
	} else {
		/* list is handled above */
		if (ct_action == CT_A_ARCHIVE) {
			caa.caa_local_ctfile = ctfile;
			ct_normalize_filelist(argv);
			caa.caa_filelist = argv;
			caa.caa_excllist = excludelist;
			caa.caa_matchmode = ct_match_mode;
			caa.caa_includelist = includelist;
			caa.caa_tdir = ct_tdir;
			caa.caa_tag = ctfile;
			caa.caa_ctfile_basedir = NULL;
			/* we want to encrypt as long as we have keys */
			caa.caa_no_cross_mounts = no_cross_mounts;
			caa.caa_strip_slash = strip_slash;
			caa.caa_follow_root_symlink = follow_root_symlink;
			caa.caa_follow_symlinks = follow_symlinks;
			caa.caa_max_incrementals = 0; /* unlimited */
			caa.caa_basis = ct_basisbackup;

			ct_add_operation(state, ct_archive, NULL, &caa);
		} else if (ct_action == CT_A_EXTRACT) {
			cea.cea_local_ctfile = ctfile;
			cea.cea_filelist = includelist;
			cea.cea_excllist = excludelist;
			cea.cea_matchmode = ct_match_mode;
			cea.cea_ctfile_basedir = NULL;
			cea.cea_tdir = ct_tdir;
			cea.cea_strip_slash = strip_slash;
			cea.cea_attr = attr;
			cea.cea_follow_symlinks = follow_symlinks;
			cea.cea_log_state = &ct_verbose;
			cea.cea_log_chown_failed =
			    ct_print_extract_chown_failed;
			ct_add_operation(state, ct_extract, NULL, &cea);
		} else {
			CWARNX("must specify action");
			ct_usage();
			/* NOTREACHED */
		}
	}

	ct_wakeup_file(state->event_state);

	if ((ret = ct_run_eventloop(state)) != 0) {
		if (state->ct_errmsg[0] != '\0')
			CWARNX("%s: %s", state->ct_errmsg,
			    ct_strerror(ret));
		else
			CWARNX("%s", ct_strerror(ret));
		return (ret);
	}

	if (verbose_ratios)
		ct_dump_stats(state, stdout);
	ct_cleanup_login_cache();
	ct_cleanup(state);
out:
	if (includelist && freeincludes == 1)
		ct_matchlist_free(includelist);
	if (excludelist)
		ct_matchlist_free(excludelist);
	if (conf->ct_ctfile_mode == CT_MDMODE_REMOTE && ct_metadata == 0)
		ctfile_trim_cache(conf->ct_ctfile_cachedir,
		    conf->ct_ctfile_max_cachesize);

	ct_unload_config(config_file, conf);
#if CT_CHECK_MEMORY
	e_check_memory();
#endif
	exude_cleanup();

	return (ret);
}
Example #8
0
int
ct_list(const char *file, char **flist, char **excludelist, int match_mode,
    const char *ctfile_basedir, int strip_slash, int verbose)
{
	struct ct_extract_state		*ces;
	struct ctfile_parse_state	 xs_ctx;
	struct fnode			 fnodestore;
	uint64_t			 reduction;
	struct fnode			*fnode = &fnodestore;
	struct ct_match			*match, *ex_match = NULL;
	char				*ct_next_filename;
	char				*sign;
	int				 state;
	int				 doprint = 0;
	int				 ret;
	int				 s_errno = 0, ct_errno = 0;
	char				 shat[SHA_DIGEST_STRING_LENGTH];
	char				 cshat[SHA_DIGEST_STRING_LENGTH];
	char				 iv[CT_IV_LEN*2+1];

	if ((ret = ct_file_extract_init(&ces, NULL, 1, 1, 0, NULL, NULL)) != 0)
		CFATALX("failed to initialise extract state: %s",
		    ct_strerror(ret));
	if ((ret = ct_match_compile(&match, match_mode, flist)) != 0)
		CFATALX("failed to compile match pattern: %s",
		    ct_strerror(ret));
	if (excludelist != NULL && (ret = ct_match_compile(&ex_match,
	    match_mode, excludelist)) != 0)
		CFATALX("failed to compile exclude pattern: %s",
		    ct_strerror(ret));

	verbose++;	/* by default print something. */

	ct_next_filename = NULL;
next_file:
	ret = ctfile_parse_init(&xs_ctx, file, ctfile_basedir);
	if (ret)
		CFATALX("failed to open %s: %s", file, ct_strerror(ret));
	ct_print_ctfile_info(&verbose, file, &xs_ctx.xs_gh);

	if (ct_next_filename)
		e_free(&ct_next_filename);

	if (xs_ctx.xs_gh.cmg_prevlvl_filename) {
		CNDBG(CT_LOG_CTFILE, "previous backup file %s\n",
		    xs_ctx.xs_gh.cmg_prevlvl_filename);
		ct_next_filename = e_strdup(xs_ctx.xs_gh.cmg_prevlvl_filename);
	}
	bzero(&fnodestore, sizeof(fnodestore));

	do {
		ret = ctfile_parse(&xs_ctx);
		switch (ret) {
		case XS_RET_FILE:
			ct_populate_fnode(ces, &xs_ctx, fnode, &state,
			    xs_ctx.xs_gh.cmg_flags & CT_MD_MLB_ALLFILES,
			    strip_slash);
			doprint = !ct_match(match, fnode->fn_fullname);
			if (doprint && ex_match != NULL &&
			    !ct_match(ex_match, fnode->fn_fullname))
				doprint = 0;
			if (doprint) {
				ct_pr_fmt_file(&verbose, fnode);
				if (!C_ISREG(xs_ctx.xs_hdr.cmh_type) ||
				    verbose > 2)
					printf("\n");
			}
			if (fnode->fn_hlname)
				e_free(&fnode->fn_hlname);
			if (fnode->fn_fullname)
				e_free(&fnode->fn_fullname);
			break;
		case XS_RET_FILE_END:
			sign = " ";
			if (xs_ctx.xs_trl.cmt_comp_size == 0)
				reduction = 100;
			else {
				uint64_t orig, comp;
				orig = xs_ctx.xs_trl.cmt_orig_size;
				comp = xs_ctx.xs_trl.cmt_comp_size;

				if (comp <= orig) {
					reduction = 100 * (orig - comp) / orig;
				} else  {
					reduction = 100 * (comp - orig) / orig;
					if (reduction != 0)
						sign = "-";
				}
			}
			if (doprint && verbose > 1)
				printf(" sz: %" PRIu64 " shas: %" PRIu64
				    " reduction: %s%" PRIu64 "%%\n",
				    xs_ctx.xs_trl.cmt_orig_size,
				    xs_ctx.xs_hdr.cmh_nr_shas,
				    sign, reduction);
			else if (doprint)
				printf("\n");
			break;
		case XS_RET_SHA:
			if (!(doprint && verbose > 2)) {
				if (ctfile_parse_seek(&xs_ctx)) {
					CFATALX("seek failed");
				}
			} else {
				int i;
				ct_sha1_encode(xs_ctx.xs_sha, shat);
				switch (xs_ctx.xs_gh.cmg_flags & CT_MD_CRYPTO) {
				case 0:
					printf(" sha %s\n", shat);
					break;
				case CT_MD_CRYPTO:
					ct_sha1_encode(xs_ctx.xs_csha, cshat);
					for (i = 0; i < CT_IV_LEN; i++)
						snprintf(&iv[i * 2], 3, "%02x",
						    xs_ctx.xs_iv[i]);

					printf(" sha %s csha %s iv %s\n",
					    shat, cshat, iv);
				}
			}
			break;
		case XS_RET_EOF:
			break;
		case XS_RET_FAIL:
			s_errno = errno;
			ct_errno = xs_ctx.xs_errno;
			;
		}

	} while (ret != XS_RET_EOF && ret != XS_RET_FAIL);

	ctfile_parse_close(&xs_ctx);

	if (ret != XS_RET_EOF) {
		errno = s_errno;
		CWARNX("corrupt ctfile: %s", ct_strerror(ct_errno));
	} else {
		if (ct_next_filename) {
			file = ct_next_filename;
			goto next_file;
		}
	}
	ct_match_unwind(match);
	ct_file_extract_cleanup(ces);
	return (0);
}
Example #9
0
int
ct_assl_negotiate_poll(struct ct_global_state *state)
{
	void				 *body;
	struct ct_header		 hdr;
	ssize_t				 sz;
	int				 rv = 1;
	int				 payload_sz;
	uint8_t				 buf[20];

	/* send server request */
	if ((rv = ct_create_neg(&hdr, &body, state->ct_max_trans,
	    state->ct_max_block_size)) != 0)
		goto done;
	payload_sz = hdr.c_size;
	ct_wire_header(&hdr);
	if (ct_assl_io_write_poll(state->ct_assl_ctx, &hdr, sizeof hdr,
	    ASSL_TIMEOUT) != sizeof hdr) {
		rv = CTE_SHORT_WRITE;
		goto done;
	}
	if (ct_assl_io_write_poll(state->ct_assl_ctx, body, payload_sz,
	    ASSL_TIMEOUT) != payload_sz) {
		rv = CTE_SHORT_WRITE;
		goto done;
	}

	/* get server reply */
	sz = ct_assl_io_read_poll(state->ct_assl_ctx, &hdr, sizeof hdr,
	    ASSL_TIMEOUT);
	if (sz != sizeof hdr) {
		rv = CTE_SHORT_READ;
		CWARNX("invalid header size %ld", (long) sz);
		goto done;
	}
	ct_unwire_header(&hdr);
	/* negotiate reply is the same size as the request, so reuse the body */
	if (hdr.c_size != payload_sz)  {
		rv = CTE_INVALID_REPLY_LEN;
		CWARNX("invalid negotiate reply size %d", hdr.c_size);
		goto done;
	}

	if (ct_assl_io_read_poll(state->ct_assl_ctx, buf,
		    hdr.c_size, ASSL_TIMEOUT) != hdr.c_size) {
		CWARNX("couldn't read neg parameters");
		rv = CTE_SHORT_READ;
		goto done;
	}

	if ((rv = ct_parse_neg_reply(&hdr, buf, &state->ct_max_trans,
	    &state->ct_max_block_size)) != 0) {
		goto done;
	}
	e_free(&body);

	CNDBG(CT_LOG_NET, "negotiated queue depth: %u max chunk size: %u",
	    state->ct_max_trans, state->ct_max_block_size);

	if ((rv = ct_create_login(&hdr, &body, state->ct_config->ct_username,
	    state->ct_config->ct_password)) != 0)
		goto done;
	payload_sz = hdr.c_size;
	ct_wire_header(&hdr);
	if (ct_assl_io_write_poll(state->ct_assl_ctx, &hdr, sizeof hdr,
	    ASSL_TIMEOUT) != sizeof hdr) {
		rv = CTE_SHORT_WRITE;
		goto done;
	}
	if (ct_assl_io_write_poll(state->ct_assl_ctx, body, payload_sz,
	    ASSL_TIMEOUT) != payload_sz) {
		rv = CTE_SHORT_WRITE;
		goto done;
	}

	/* get server reply */
	sz = ct_assl_io_read_poll(state->ct_assl_ctx, &hdr, sizeof hdr,
	    ASSL_TIMEOUT);
	if (sz != sizeof hdr) {
		rv = CTE_SHORT_READ;
		goto done;
	}
	e_free(&body);
	ct_unwire_header(&hdr);

	/* XXX need a way to get error crud out, right now the function warns
	   for us. */
	if ((rv = ct_parse_login_reply(&hdr, NULL)) != 0)
		goto done;

	if (ct_skip_xml_negotiate) {
		goto out;
	}

	if ((rv = ct_create_xml_negotiate(&hdr, &body,
	    ctdb_get_genid(state->ct_db_state))) != 0) {
		goto done;
	}

	payload_sz = hdr.c_size;
	ct_wire_header(&hdr);
	if (ct_assl_io_write_poll(state->ct_assl_ctx, &hdr, sizeof hdr,
	    ASSL_TIMEOUT) != sizeof hdr) {
		rv = CTE_SHORT_WRITE;
		goto done;
	}
	if (ct_assl_io_write_poll(state->ct_assl_ctx, body, payload_sz,
	    ASSL_TIMEOUT)
	    != payload_sz) {
		rv = CTE_SHORT_WRITE;
		CWARNX("could not write body");
		goto done;
	}
	e_free(&body);

	/* get server reply */
	sz = ct_assl_io_read_poll(state->ct_assl_ctx, &hdr, sizeof hdr,
	    ASSL_TIMEOUT);
	if (sz != sizeof hdr) {
		rv = CTE_SHORT_READ;
		CWARNX("invalid header size %" PRId64, (int64_t)sz);
		goto done;
	}
	ct_unwire_header(&hdr);

	if (hdr.c_size == 0) {
		goto out;
	}
	/* get server reply body */
	body = e_calloc(1, hdr.c_size);
	sz = ct_assl_io_read_poll(state->ct_assl_ctx, body, hdr.c_size,
	    ASSL_TIMEOUT);
	if (sz != hdr.c_size) {
		rv = CTE_SHORT_READ;
		goto done;
	}
	/* XXX check xml data */
	if ((rv = ct_parse_xml_negotiate_reply(&hdr, body,
	    state->ct_db_state)) != 0) {
		e_free(&body);
		goto done;
	}

	e_free(&body);

out:
	CNDBG(CT_LOG_NET, "login successful");
	rv = 0;
done:
	return (rv);
}
Example #10
0
int
ctfile_nextop_archive(struct ct_global_state *state, char *basis, void *args)
{
	struct ct_archive_args	*caa = args;
	struct ct_ctfileop_args	*cca;
	char			*ctfile;
	char	 		 buf[TIMEDATA_LEN], *fullname, *cachename;
	time_t	 		 now;

	CNDBG(CT_LOG_CTFILE, "setting basisname %s", basis ? basis : "<none>");
	caa->caa_basis = basis;

	/*
	 * We now have the basis found for us, cook and prepare the tag
	 * we wish to create then add the operation.
	 */
	if ((ctfile = ctfile_cook_name(caa->caa_tag)) == NULL) {
		CWARNX("%s: %s", caa->caa_tag,
		    ct_strerror(CTE_INVALID_CTFILE_NAME));
		return (CTE_INVALID_CTFILE_NAME);
	}

	if (ctfile_is_fullname(ctfile) != 0) {
		CWARNX("%s", ct_strerror(CTE_ARCHIVE_FULLNAME));
		e_free(&ctfile);
		return (CTE_ARCHIVE_FULLNAME);
	}

	now = time(NULL);
	if (strftime(buf, TIMEDATA_LEN, "%Y%m%d-%H%M%S",
	    localtime(&now)) == 0)
		CABORTX("can't format time");
	e_asprintf(&fullname, "%s-%s", buf, ctfile);
	CNDBG(CT_LOG_CTFILE, "backup file is %s", fullname);

	/* check it isn't already in the cache */
	cachename = ctfile_get_cachename(fullname,
	    state->ct_config->ct_ctfile_cachedir);
	if (ctfile_in_cache(fullname, state->ct_config->ct_ctfile_cachedir)) {
		CWARNX("%s: %s", fullname,
		    ct_strerror(CTE_BACKUP_ALREADY_EXISTS));
		e_free(&ctfile);
		e_free(&fullname);
		e_free(&cachename);
		return (CTE_BACKUP_ALREADY_EXISTS);
	}

	e_free(&ctfile);
	e_free(&fullname);

	caa->caa_local_ctfile = cachename;
	ct_add_operation(state, ct_archive, NULL, caa);
	/*
	 * set up an additional operation to upload the newly created
	 * ctfile after the archive is completed.
	 */
	cca = e_calloc(1, sizeof(*cca));
	cca->cca_localname = cachename;
	cca->cca_cleartext = 0;
	cca->cca_ctfile = 1;
	ct_add_operation(state, ctfile_archive, ctfile_nextop_archive_cleanup,
	    cca);
	return (0);
}
Example #11
0
/*
 * Download all dependent ctfiles of the current ctfile.
 * (called repeatedly until all are fetched).
 */
int
ctfile_download_next(struct ct_global_state *state, struct ct_op *op)
{
	struct ct_ctfileop_args	*cca = op->op_args, *nextcca;
	const char		*ctfile = cca->cca_localname;
	const char		*rfile = cca->cca_remotename;
	char			*prevfile;
	char			*cookedname;
	int			 ret = 0;

again:
	CNDBG(CT_LOG_CTFILE, "ctfile %s", ctfile);

	if ((ret = ctfile_get_previous(ctfile, cca->cca_tdir, 
	    &prevfile)) != 0) {
		CWARNX("can not get previous filename for %s", ctfile);
		/* error output will happen when even loop returns */
		goto out;
	}
	if (prevfile == NULL) /* done with this chain */
		goto out;

	if (prevfile[0] != '\0') {
		if ((cookedname = ctfile_cook_name(prevfile)) == NULL) {
			CWARNX("%s: %s", prevfile,
			    ct_strerror(CTE_INVALID_CTFILE_NAME));
			ret = CTE_INVALID_CTFILE_NAME;
			e_free(&prevfile);
			goto out;
		}
		CNDBG(CT_LOG_CTFILE, "prev file %s cookedname %s", prevfile,
		    cookedname);
		if (!ctfile_in_cache(cookedname, cca->cca_tdir)) {
			nextcca = e_calloc(1, sizeof(*nextcca));
			nextcca->cca_localname = cookedname;
			nextcca->cca_remotename = e_strdup(cookedname);
			nextcca->cca_tdir = cca->cca_tdir;
			nextcca->cca_ctfile = 1;
			ct_add_operation_after(state, op, ctfile_extract,
			    ctfile_download_next, nextcca);
		} else {
			if (ctfile)
				e_free(&ctfile);
			if (rfile)
				e_free(&rfile);
			e_free(&cookedname);
			ctfile = prevfile;
			goto again;
		}
	} else
		e_free(&prevfile);

out:
	if (ctfile)
		e_free(&ctfile);
	if (rfile)
		e_free(&rfile);
	e_free(&cca);

	return (ret);
}
Example #12
0
/*
 * List has completed.
 *
 * Select the best filename for download, and download it if missing.
 */
int
ctfile_find_for_extract_complete(struct ct_global_state *state,
    struct ct_op *op)
{
	struct ct_ctfile_find_args		*ccfa = op->op_args;
	struct ct_ctfile_find_fileop_args	*ccffa;
	struct ct_op				*list_fakeop = op->op_priv;
	struct ct_ctfile_list_args		*ccla = list_fakeop->op_args;
	struct ctfile_list_tree			 result;
	struct ctfile_list_file			*tmp;
	char	 				*best = NULL;
	int					 ret = 0;

	RB_INIT(&result);
	ctfile_list_complete(&state->ctfile_list_files, ccla->ccla_matchmode,
	    ccla->ccla_search, ccla->ccla_exclude, &result);
	e_free(ccla->ccla_search);
	e_free(&ccla->ccla_search);
	e_free(&ccla);
	e_free(&list_fakeop);

	/*
	 * Prepare arguments for next operation.
	 * either we'll download the next file, or skip straight to
	 * the callback for after the download, either way we need the nextop
	 */
	ccffa = e_calloc(1, sizeof(*ccffa));
	ccffa->ccffa_nextop = ccfa->ccfa_nextop;
	ccffa->ccffa_nextop_args = ccfa->ccfa_nextop_args;
	ccffa->ccffa_download_chain = ccfa->ccfa_download_chain;

	/* grab the newest one */
	if ((tmp = RB_MAX(ctfile_list_tree, &result)) == NULL) {
		if (ccfa->ccfa_empty_ok)
			goto do_operation;
		else {
			CWARNX("%s: %s", ccfa->ccfa_tag,
			    ct_strerror(CTE_NO_SUCH_BACKUP));
			ret = CTE_NO_SUCH_BACKUP;
			e_free(&ccffa);
			goto out;
		}
	}

	/* pick the newest one */
	best = e_strdup(tmp->mlf_name);
	CNDBG(CT_LOG_CTFILE, "backup file is %s", best);

	while ((tmp = RB_ROOT(&result)) != NULL) {
		RB_REMOVE(ctfile_list_tree, &result, tmp);
		e_free(&tmp);
	}

	/*
	 * if the metadata file is not in the cache directory then we
	 * need to download it first. if we need to recursively download
	 * an incremental chain then that code will handle scheduling
	 * those operations too. If we have it, we still need to check
	 * that all others in the chain exist, however.
	 */
	if (!ctfile_in_cache(best, ccfa->ccfa_cachedir)) {
		ccffa->ccffa_base.cca_localname = best;
		ccffa->ccffa_base.cca_tdir = ccfa->ccfa_cachedir;
		ccffa->ccffa_base.cca_remotename = e_strdup(best);
		ccffa->ccffa_base.cca_ctfile = 1;
		ct_add_operation(state, ctfile_extract, ctfile_extract_nextop,
		    ccffa);
	} else {
do_operation:
		/*
		 * No download needed, fake the next operation callback
		 * to see if we need anymore.
		 */
		ccffa->ccffa_base.cca_localname = best;
		ccffa->ccffa_base.cca_tdir = ccfa->ccfa_cachedir;
		ccffa->ccffa_base.cca_ctfile = 1;
		op->op_args = ccffa;
		ctfile_extract_nextop(state, op);
	}
out:
	e_free(&ccfa);

	return (ret);
}