Пример #1
0
void
ct_prompt_for_login_password(struct ct_config *conf)
{
	char	answer[1024];

	if (conf->ct_username == NULL) {
		if (ct_get_answer("Login username: "******"invalid username");
		} else if (!strlen(answer)) {
			CFATALX("username must not be empty");
		}
		conf->ct_username = e_strdup(answer);
		bzero(answer, sizeof answer);
	}
	ct_normalize_username(conf->ct_username);

	if (conf->ct_password == NULL) {
		if (ct_get_answer("Login password: "******"invalid password");
		} else if (!strlen(answer)) {
			CFATALX("password must not be empty");
		}
		conf->ct_password = e_strdup(answer);
		bzero(answer, sizeof answer);
	}

}
Пример #2
0
/*
 * now the operation has completed we can kick off the next operation knowing
 * that everything has been set up for it.
 */
int
ctfile_extract_nextop(struct ct_global_state *state, struct ct_op *op)
{
	struct ct_ctfile_find_fileop_args	*ccffa = op->op_args;
	struct ct_ctfileop_args			*cca;
	char					*cachename;
	int					 ret = 0;

	/*
	 * If this is an operation that needs the full incremental chain
	 * recursively fetch the next one in the chain till done.
	 */
	if (ccffa->ccffa_download_chain) {
		/*
		 * download_next takes ownership of the pointers it is given,
		 * duplicate our copy.
		 */
		cca = e_calloc(1, sizeof(*cca));
		if (ccffa->ccffa_base.cca_localname)
			cca->cca_localname =
			    e_strdup(ccffa->ccffa_base.cca_localname);
		if (ccffa->ccffa_base.cca_remotename)
			cca->cca_remotename =
			    e_strdup(ccffa->ccffa_base.cca_remotename);
		cca->cca_tdir = ccffa->ccffa_base.cca_tdir;
		cca->cca_ctfile = ccffa->ccffa_base.cca_ctfile;
		op->op_args = cca;
		/* we give up ownership of cca here */
		if ((ret = ctfile_download_next(state, op)) != 0)
			goto out;
	}

	/*
	 * We now have the name of the file we wish to perform the main
	 * operation on, the nextop callback will add this operation
	 * to the operation list. Ownership of the allocated pointer
	 * passes to the child.
	 */
	if (ccffa->ccffa_base.cca_localname != NULL) {
		cachename =
		    ctfile_get_cachename(ccffa->ccffa_base.cca_localname,
		    ccffa->ccffa_base.cca_tdir);
	} else {
		cachename = NULL;
	}
	ret = ccffa->ccffa_nextop(state, cachename, ccffa->ccffa_nextop_args);
	
out:
	if (ccffa->ccffa_base.cca_localname)
		e_free(&ccffa->ccffa_base.cca_localname);
	if (ccffa->ccffa_base.cca_remotename)
		e_free(&ccffa->ccffa_base.cca_remotename);
	e_free(&ccffa);

	return (ret);
}
Пример #3
0
char *
ct_getloginbyuid(uid_t uid)
{
	struct passwd *passwd;
	struct ct_login_cache *entry, search;

	search.lc_uid = uid;

	entry = RB_FIND(ct_login_cache_tree, &ct_login_cache, &search);

	if (entry != NULL) {
		return entry->lc_name;
	}

	/* if the cache gets too big, dump all entries and refill. */
	if (ct_login_cache_size > MAX_LC_CACHE_SIZE) {
		ct_cleanup_login_cache();
	}

	/* yes, this even caches negative entries */
	ct_login_cache_size++;

	entry = e_calloc(1, sizeof(*entry));
	entry->lc_uid = uid;

	passwd = getpwuid(uid);
	if (passwd)
		entry->lc_name = e_strdup(passwd->pw_name);
	else
		entry->lc_name = NULL; /* entry not found cache NULL */

	RB_INSERT(ct_login_cache_tree, &ct_login_cache, entry);

	return entry->lc_name;
}
Пример #4
0
int
main(int argc, char **argv)
{
	struct ct_global_state	*state = NULL;
	char			*config_file = NULL;
	uint32_t		 cflags = CLOG_F_ENABLE | CLOG_F_STDERR;
	uint64_t		 debug_mask = 0;
	int			 ret;
	char                    *ctfile;

	/* setup arguments */
	ct_setup_preinit(CT_INIT_ASSL | CT_INIT_CLOG | CT_INIT_EXUDE,
	    cflags, debug_mask);

	if (argc < 2) {
		CFATALX("usage: %s <metadata file tag>", __progname);
	}
	ctfile = e_strdup(argv[1]); /* metadata file tag */

	ct_setup_config(config_file, &state);

	ret = ct_do_delete(state, ctfile, CT_MATCH_GLOB);

	ct_cleanup_all(state, config_file);

	if (ctfile)
		e_free(&ctfile);

	return (ret);
}
Пример #5
0
int
ct_extract_setup(struct ct_extract_head *extract_head,
    struct ctfile_parse_state *ctx, const char *file,
    const char *ctfile_basedir, int *is_allfiles)
{
	struct ct_extract_stack	*nfile;
	char			*prevlvl;
	int			 ret;

	if ((ret = ctfile_parse_init(ctx, file, ctfile_basedir)) != 0)
		return (ret);

	*is_allfiles = (ctx->xs_gh.cmg_flags & CT_MD_MLB_ALLFILES);

	if (ctx->xs_gh.cmg_prevlvl_filename) {
		nfile = e_malloc(sizeof(*nfile));
		nfile->filename = e_strdup(file);
		TAILQ_INSERT_HEAD(extract_head, nfile, next);

		prevlvl = e_strdup(ctx->xs_gh.cmg_prevlvl_filename);

		ctfile_parse_close(ctx);
		if ((ret = ct_extract_setup_queue(extract_head, ctx, prevlvl,
		    ctfile_basedir, *is_allfiles)) != 0) {
			int s_errno = errno;

			/* unwind */
			e_free(&prevlvl);
			ct_extract_cleanup_queue(extract_head);

			errno = s_errno;
			return (ret);
		}

		e_free(&prevlvl);

		if (*is_allfiles) {
			ctfile_parse_close(ctx);
			/* reopen first file */
			ret = ct_extract_open_next(extract_head, ctx);
		}
	}

	return (ret);
}
Пример #6
0
static int
ct_extract_setup_queue(struct ct_extract_head *extract_head,
    struct ctfile_parse_state *ctx, const char *file,
    const char *ctfile_basedir, int is_allfiles)
{
	char			*prevlvl;
	struct ct_extract_stack	*nfile;
	int			 ret;

	if ((ret = ctfile_parse_init(ctx, file, ctfile_basedir)) != 0)
		return (ret);

	if (ctx->xs_gh.cmg_prevlvl_filename) {
		/* need to nest another level deep.*/
		nfile = e_malloc(sizeof(*nfile));
		nfile->filename = e_strdup(file);

		if (is_allfiles)
			TAILQ_INSERT_TAIL(extract_head, nfile, next);
		else
			TAILQ_INSERT_HEAD(extract_head, nfile, next);

		prevlvl = e_strdup(ctx->xs_gh.cmg_prevlvl_filename);
		ctfile_parse_close(ctx);

		ct_extract_setup_queue(extract_head, ctx, prevlvl,
		    ctfile_basedir, is_allfiles);
		e_free(&prevlvl);

	} else if (is_allfiles) {
		/*
		 * Allfiles we work backwards down the chain, without it
		 * we work at the end and go backwards. Since this is the last
		 * entry we only need it for allfiles mode.
		 */
		nfile = e_malloc(sizeof(*nfile));
		nfile->filename = e_strdup(file);
		TAILQ_INSERT_TAIL(extract_head, nfile, next);
	}

	return (0);
}
Пример #7
0
char *
e_file_get_dir(char *file)
{
   char *p;
   char *f;
   char buf[PATH_MAX];
   
   D_ENTER;
   
   strcpy(buf, file);
   p = strrchr(buf, '/');
   if (!p) 
     {
	e_strdup(f, file);
	D_RETURN_(f);
     }
   *p = 0;
   e_strdup(f, buf);

   D_RETURN_(f);
}
Пример #8
0
Evas_List * 
e_file_ls(char *dir)
{
   DIR                *dirp;
   struct dirent      *dp;
   Evas_List *           list;
   
   D_ENTER;
   
   dirp = opendir(dir);
   if (!dirp) D_RETURN_(NULL);
   list = NULL;
   while ((dp = readdir(dirp)))
     {
	if ((strcmp(dp->d_name, ".")) &&
	    (strcmp(dp->d_name, "..")))
	  {
	     Evas_List * l;
	     char *f;
	     
	     /* insertion sort */
	     for (l = list; l; l = l->next)
	       {
		  if (strcmp(l->data, dp->d_name) > 0)
		    {
		       e_strdup(f, dp->d_name);
		       list = evas_list_prepend_relative(list, f, l->data);
		       break;
		    }
	       }
	     /* nowhwre to go? just append it */
	     e_strdup(f, dp->d_name);
	     if (!l) list = evas_list_append(list, f);
	  }
     }
   closedir(dirp);

   D_RETURN_(list);
}
Пример #9
0
char *
e_file_realpath(char *file)
{
   char buf[PATH_MAX];
   char *f;
   
   D_ENTER;
   
   if (!realpath(file, buf)) D_RETURN_(strdup(""));
   e_strdup(f, buf);

   D_RETURN_(f);
}
Пример #10
0
void
ct_match_insert_rb(struct ct_match *match, char *string)
{
	struct ct_match_node	*n;

	if (match->cm_mode != CT_MATCH_RB)
		CABORTX("match mode %d is not rb", match->cm_mode);
	n = e_calloc(1, sizeof(struct ct_match_node));
	n->cmn_string = e_strdup(string);
	if (RB_INSERT(ct_match_tree, match->cm_rb_head, n)) {
		/* pattern already exists free it */
		e_free(&n->cmn_string);
		e_free(&n);
	}
}
Пример #11
0
char *
e_file_readlink(char *link)
{
   char buf[PATH_MAX];
   char *f;
   int count;
   
   D_ENTER;
   
   if ((count = readlink(link, buf, sizeof(buf))) < 0) D_RETURN_(NULL);
   buf[count] = 0;
   e_strdup(f, buf);

   D_RETURN_(f);
}
Пример #12
0
/*
 * filenames passed in remote mode are opaque tags for the backup.
 * they are stored on the server and in remote mode in the form
 * YYYYMMDD-HHMMSS-<strnvis(mname)>
 */
void
ctfile_find_for_extract(struct ct_global_state *state, struct ct_op *op)
{
	struct ct_ctfile_find_args	*ccfa = op->op_args;
	const char			*ctfile = ccfa->ccfa_tag;
	struct ct_op			*list_fakeop;
	struct ct_ctfile_list_args	*ccla;

	if (state->ct_dying != 0) {
		/* nothing to clean up */
		return;
	}

	/* cook the ctfile so we only search for the actual tag */
	if ((ctfile = ctfile_cook_name(ctfile)) == NULL) {
		ct_fatal(state, ccfa->ccfa_tag, CTE_INVALID_CTFILE_NAME);
		return;
	}

	list_fakeop = e_calloc(1, sizeof(*list_fakeop));
	ccla = e_calloc(1, sizeof(*ccla));
	list_fakeop->op_args = ccla;
	ccla->ccla_search = e_calloc(2, sizeof(char **));
	if (ctfile_is_fullname(ctfile)) {
		/* use list as stat() for now */
		*ccla->ccla_search = e_strdup(ctfile);
		ccla->ccla_matchmode = CT_MATCH_GLOB;
	} else {
		e_asprintf(ccla->ccla_search,
		    "^[[:digit:]]{8}-[[:digit:]]{6}-%s$", ctfile);

		ccla->ccla_matchmode = CT_MATCH_REGEX;
		/*
		 * get the list of files matching this tag from the server.
		 * list returns an empty list if it found
		 * nothing and NULL upon failure.
		 */
	}
	e_free(&ctfile);

	CNDBG(CT_LOG_CTFILE, "looking for %s", ccla->ccla_search[0]);

	op->op_priv = list_fakeop;
	ctfile_list_start(state, list_fakeop);

	return;
}
Пример #13
0
int
ct_match_compile(struct ct_match **matchp, int mode, char **flist)
{
	struct ct_match	*match;
	int		 i, ret;

	match = e_calloc(1, sizeof(*match));
	match->cm_mode = mode;

	switch (mode) {
	case CT_MATCH_EVERYTHING:
		ret = 0;
		break;
	case CT_MATCH_REGEX:
		match->cm_regex = e_calloc(1, sizeof(regex_t));
		ret = ct_regex_comp(match->cm_regex, flist);
		break;
	case CT_MATCH_RB:
		match->cm_rb_head = e_calloc(1, sizeof(*match->cm_rb_head));
		ret = ct_rb_comp(match->cm_rb_head, flist);
		break;
	case CT_MATCH_GLOB:
		for (i = 0; flist[i] != NULL; i++)
			if (flist[i] == NULL)
				break;
		if (i == 0) {
			ret = 0;
			break;
		}
		i++; /* extra NULL */
		match->cm_glob = e_calloc(i, sizeof(char *));

		for (i = 0; flist[i] != NULL; i++) {
			if (flist[i] == NULL)
				break;
			match->cm_glob[i] = e_strdup(flist[i]);
		}
		ret = 0;
		break;
	default:
		CABORTX("invalid match mode");
	}

	*matchp = match;
	return (ret);
}
Пример #14
0
void
ct_extract_insert_entry(struct ct_pending_files *head, struct fnode *fnode)
{
	struct ct_pending_file	*cpf;

	CNDBG(CT_LOG_FILE, "%s: inserting %s", __func__, fnode->fn_fullname);
	cpf = e_calloc(1, sizeof(*cpf));
	cpf->cpf_name = e_strdup(fnode->fn_fullname);
	cpf->cpf_uid = fnode->fn_uid;
	cpf->cpf_gid = fnode->fn_gid;
	cpf->cpf_mode = fnode->fn_mode;
	cpf->cpf_mtime = fnode->fn_mtime;
	cpf->cpf_atime = fnode->fn_atime;

	TAILQ_INIT(&cpf->cpf_links);
	RB_INSERT(ct_pending_files, head, cpf);
}
Пример #15
0
struct ctdb_state *
ctdb_setup(const char *path, int crypt_enabled)
{
	struct ctdb_state	*state;
	if (path == NULL)
		return (NULL);
	state = e_calloc(1, sizeof(*state));

	state->ctdb_genid = -1;
	state->ctdb_crypt = crypt_enabled;
	state->ctdb_dbfile = e_strdup(path);
	if (ctdb_open(state) != 0) {
		e_free(&state->ctdb_dbfile);
		e_free(&state);
	}
	return (state);
}
Пример #16
0
int
ct_rb_comp(struct ct_match_tree *head, char **flist)
{
	int			i;
	struct ct_match_node	*n;

	for (i = 0; flist[i] != NULL; i++) {
		if (flist[i] == NULL)
			break;
		n = e_calloc(1, sizeof(struct ct_match_node));
		n->cmn_string = e_strdup(flist[i]);
		if (RB_INSERT(ct_match_tree, head, n)) {
			/* pattern already exists free it */
			e_free(&n->cmn_string);
			e_free(&n);
			continue;
		}
	}

	return (0);
}
Пример #17
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);
}
Пример #18
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);
}
Пример #19
0
/*
 * Extract an individual file that has been passed into the op by op_priv.
 */
void
ct_extract_file(struct ct_global_state *state, struct ct_op *op)
{
	struct ct_extract_file_args	*cefa = op->op_args;
	struct ct_file_extract_priv	*ex_priv = op->op_priv;
	const char			*localfile = cefa->cefa_filename;
	struct ct_trans			*trans;
	int				 ret;
	char				 shat[SHA_DIGEST_STRING_LENGTH];

	if (state->ct_dying != 0)
		goto dying;

	CNDBG(CT_LOG_TRANS, "entry");
	switch (ct_get_file_state(state)) {
	case CT_S_STARTING:
		CNDBG(CT_LOG_TRANS, "starting");
		ex_priv = e_calloc(1, sizeof(*ex_priv));
		/* open file and seek to beginning of file */
		if ((ret = ctfile_parse_init_at(&ex_priv->xdr_ctx,
		    cefa->cefa_ctfile, NULL, cefa->cefa_ctfile_off)) != 0) {
			/* XXX add pathname */
			ct_fatal(state, "Can't open ctfile", ret);
			e_free(&ex_priv);
			goto dying;
		}
		 /* 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);
		if ((ret = ct_file_extract_init(&state->extract_state,
		    NULL, 0, 0, 0, NULL, NULL)) != 0) {
			ct_fatal(state, "Can not initialise extract state",
			    ret);
			e_free(&ex_priv);
			goto dying;
		}
		op->op_priv = ex_priv;
		break;
	case CT_S_FINISHED:
		return;
	default:
		break;
	}

	ct_set_file_state(state, CT_S_RUNNING);
	while (1) {
		if ((trans = ct_trans_alloc(state)) == NULL) {
			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;

		if (ex_priv->done) {
			CNDBG(CT_LOG_CTFILE, "Hit end of ctfile");
			ctfile_parse_close(&ex_priv->xdr_ctx);
			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;
			ct_queue_first(state, trans);
			CNDBG(CT_LOG_TRANS, "extract finished");
			ct_set_file_state(state, CT_S_FINISHED);
			return;
		}

		/* unless start of file this is right */
		trans->tr_fl_node = ex_priv->fl_ex_node;

		switch ((ret = ctfile_parse(&ex_priv->xdr_ctx))) {
		case XS_RET_FILE:
			CNDBG(CT_LOG_CTFILE, "opening file");
			if (ex_priv->xdr_ctx.xs_hdr.cmh_nr_shas == -1)
				CABORTX("can't extract file with -1 shas");

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

			/* Make it local directory, it won't be set up right. */
			ex_priv->xdr_ctx.xs_hdr.cmh_parent_dir = -1;
			/*
			 * Allfiles doesn't matter, only processing one file.
			 * We have a full path to extract to so always strip
			 * slash.
			 */
			ct_populate_fnode(state->extract_state,
			    &ex_priv->xdr_ctx, trans->tr_fl_node,
			    &trans->tr_state, 0, 1);
			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;

			e_free(&trans->tr_fl_node->fn_fullname);
			trans->tr_fl_node->fn_fullname = e_strdup(localfile);
			e_free(&trans->tr_fl_node->fn_name);
			trans->tr_fl_node->fn_name = e_strdup(localfile);
			/* Set name pointer to something else passed in */

			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;
			}
			break;
		case XS_RET_SHA:
			CNDBG(CT_LOG_SHA, "sha!");
			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_cleanup = ct_extract_cleanup_fnode;
			trans->tr_dataslot = 0;
			ct_ref_fnode(trans->tr_fl_node);
			break;
		case XS_RET_FILE_END:
			trans = ct_trans_realloc_local(state, trans);
			trans->tr_fl_node = ex_priv->fl_ex_node; /* reload */

			CNDBG(CT_LOG_CTFILE, "file end!");
			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;
			/* Done now, don't parse further. */
			ex_priv->done = 1;
			/*
			 * no reference here since we give our reference to the
			 * last transaction on that file.
			 */
			ex_priv->fl_ex_node = NULL;

			break;
		case XS_RET_FAIL:
			ct_fatal(state, "Failed to parse ctfile",
			    ex_priv->xdr_ctx.xs_errno);
			goto dying;
			break;
		default:
			CABORTX("%s: invalid state %d", __func__, ret);
		}
		ct_queue_first(state, trans);
	}
	return;

dying:
	if (ex_priv) {
		ctfile_parse_close(&ex_priv->xdr_ctx);
		if (ex_priv->fl_ex_node != NULL) {
			ct_free_fnode(ex_priv->fl_ex_node);
		}
		e_free(&ex_priv);
		/* will be cleaned up by trans if ex_priv already gone */
		if (state->extract_state)
			ct_file_extract_cleanup(state->extract_state);	
	}
	return;
}
Пример #20
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);
}
Пример #21
0
static void
read_config( char* filename )
    {
    FILE* fp;
    char line[10000];
    char* cp;
    char* cp2;
    char* name;
    char* value;

    fp = fopen( filename, "r" );
    if ( fp == (FILE*) 0 )
	{
	perror( filename );
	exit( 1 );
	}

    while ( fgets( line, sizeof(line), fp ) != (char*) 0 )
	{
	/* Trim comments. */
	if ( ( cp = strchr( line, '#' ) ) != (char*) 0 )
	    *cp = '\0';

	/* Split line into words. */
	for ( cp = line; *cp != '\0'; cp = cp2 )
	    {
	    /* Skip leading whitespace. */
	    cp += strspn( cp, " \t\n\r" );
	    /* Find next whitespace. */
	    cp2 = cp + strcspn( cp, " \t\n\r" );
	    /* Insert EOS and advance next-word pointer. */
	    while ( *cp2 == ' ' || *cp2 == '\t' || *cp2 == '\n' || *cp2 == '\r' )
		*cp2++ = '\0';
	    /* Split into name and value. */
	    name = cp;
	    value = strchr( name, '=' );
	    if ( value != (char*) 0 )
		*value++ = '\0';
	    /* Interpret. */
	    if ( strcasecmp( name, "debug" ) == 0 )
		{
		no_value_required( name, value );
		debug = 1;
		}
	    else if ( strcasecmp( name, "port" ) == 0 )
		{
		value_required( name, value );
		port = atoi( value );
		}
	    else if ( strcasecmp( name, "dir" ) == 0 )
		{
		value_required( name, value );
		dir = e_strdup( value );
		}
	    else if ( strcasecmp( name, "chroot" ) == 0 )
		{
		no_value_required( name, value );
		do_chroot = 1;
		no_symlink = 1;
		}
	    else if ( strcasecmp( name, "nochroot" ) == 0 )
		{
		no_value_required( name, value );
		do_chroot = 0;
		no_symlink = 0;
		}
	    else if ( strcasecmp( name, "symlink" ) == 0 )
		{
		no_value_required( name, value );
		no_symlink = 0;
		}
	    else if ( strcasecmp( name, "nosymlink" ) == 0 )
		{
		no_value_required( name, value );
		no_symlink = 1;
		}
	    else if ( strcasecmp( name, "symlinks" ) == 0 )
		{
		no_value_required( name, value );
		no_symlink = 0;
		}
	    else if ( strcasecmp( name, "nosymlinks" ) == 0 )
		{
		no_value_required( name, value );
		no_symlink = 1;
		}
	    else if ( strcasecmp( name, "user" ) == 0 )
		{
		value_required( name, value );
		user = e_strdup( value );
		}
	    else if ( strcasecmp( name, "cgipat" ) == 0 )
		{
		value_required( name, value );
		cgi_pattern = e_strdup( value );
		}
	    else if ( strcasecmp( name, "urlpat" ) == 0 )
		{
		value_required( name, value );
		url_pattern = e_strdup( value );
		}
	    else if ( strcasecmp( name, "noemptyreferers" ) == 0 )
		{
		no_value_required( name, value );
		no_empty_referers = 1;
		}
	    else if ( strcasecmp( name, "localpat" ) == 0 )
		{
		value_required( name, value );
		local_pattern = e_strdup( value );
		}
	    else if ( strcasecmp( name, "throttles" ) == 0 )
		{
		value_required( name, value );
		throttlefile = e_strdup( value );
		}
	    else if ( strcasecmp( name, "host" ) == 0 )
		{
		value_required( name, value );
		hostname = e_strdup( value );
		}
	    else if ( strcasecmp( name, "logfile" ) == 0 )
		{
		value_required( name, value );
		logfile = e_strdup( value );
		}
	    else if ( strcasecmp( name, "vhost" ) == 0 )
		{
		no_value_required( name, value );
		do_vhost = 1;
		}
	    else if ( strcasecmp( name, "novhost" ) == 0 )
		{
		no_value_required( name, value );
		do_vhost = 0;
		}
	    else if ( strcasecmp( name, "globalpasswd" ) == 0 )
		{
		no_value_required( name, value );
		do_global_passwd = 1;
		}
	    else if ( strcasecmp( name, "noglobalpasswd" ) == 0 )
		{
		no_value_required( name, value );
		do_global_passwd = 0;
		}
	    else if ( strcasecmp( name, "pidfile" ) == 0 )
		{
		value_required( name, value );
		pidfile = e_strdup( value );
		}
	    else if ( strcasecmp( name, "charset" ) == 0 )
		{
		value_required( name, value );
		charset = e_strdup( value );
		}
	    else
		{
		(void) fprintf(
		    stderr, "%s: unknown config option '%s'\n", argv0, name );
		exit( 1 );
		}
	    }
	}

    (void) fclose( fp );
    }
Пример #22
0
/*
 * Main guts of  ctd_build_version_tree. Factored out to avoid deep nesting.
 * Insert or update an entry in the tree with the information received from
 * the ctfile.
 */
static int
ct_vertree_add(struct ct_vertree_dnode_cache *dnode_cache,
               struct ct_vertree_entry *head, struct ctfile_parse_state *parse_state,
               struct ct_vertree_ctfile *ctfile, off_t fileoffset, int allfiles)
{
    struct ctfile_header		*hdr = &parse_state->xs_hdr;
    struct ctfile_header		*hdrlnk= &parse_state->xs_lnkhdr;
    struct dnode 			*dnode;
    struct ct_vertree_dnode		*fb_dnode;
    struct ct_vertree_entry		*parent = NULL, sentry, *entry;
    struct ct_vertree_ver		*lastver, *ver;
    struct ct_vertree_file		*file;
    struct ct_vertree_spec		*spec;
    struct ct_vertree_link		*linkver;
    size_t				 sz;
    bool				 root_dnode = false;

    entry = NULL;

    /* First find parent directory if any */
    if (hdr->cmh_parent_dir != -1 && hdr->cmh_parent_dir != -2) {
        if ((dnode = ctfile_parse_finddir(parse_state,
                                          hdr->cmh_parent_dir)) == NULL) {
            CNDBG(CT_LOG_VERTREE, "can't find dir %" PRId64,
                  hdr->cmh_parent_dir);
            return (CTE_CTFILE_CORRUPT);
        }
        fb_dnode = (struct ct_vertree_dnode *)dnode;
        if (fb_dnode == dnode_cache->root_dnode) {
            // If we have the root dnode, store in head.
            parent = head;
        } else {
            parent = fb_dnode->cvd_dir;
        }

    } else {
        parent = head;
    }

    if (parent == head && strcmp(hdr->cmh_filename, CT_PATHSEP_STR) == 0) {
        root_dnode = true;
    }
    /*
     * Have parent node, search children to see if we already exist.
     * Else make a new one and insert.
     */
    sentry.cve_name = hdr->cmh_filename;
    if ((entry = RB_FIND(ct_vertree_entries, &parent->cve_children,
                         &sentry)) == NULL) {
        /* new name, insert node */
        entry = e_calloc(1, sizeof(*entry));

        TAILQ_INIT(&entry->cve_versions);
        RB_INIT(&entry->cve_children);
        entry->cve_parent = parent;
        entry->cve_name = e_strdup(sentry.cve_name);

        /* don't insert root dnodes, just do dnode dance */
        if (root_dnode) {
            goto rootdir;
        }

        if (RB_INSERT(ct_vertree_entries, &parent->cve_children,
                      entry) != NULL) {
            CNDBG(CT_LOG_VERTREE, "entry %s already exists",
                  sentry.cve_name);
            e_free(&sentry.cve_name);
            goto err;
        }
    }

    /*
     * then check version tags -> head/tail if mtime and type match, we're
     * good else prepare version entry.
     */
    if (allfiles) {
        lastver = TAILQ_FIRST(&entry->cve_versions);
    } else {
        lastver = TAILQ_LAST(&entry->cve_versions, ct_vertree_vers);
    }
    /* Don't check atime, it doesn't matter */
    if (lastver != NULL && lastver->cvv_type == hdr->cmh_type &&
            lastver->cvv_mtime == hdr->cmh_mtime &&
            lastver->cvv_uid == hdr->cmh_uid &&
            lastver->cvv_gid == hdr->cmh_gid &&
            lastver->cvv_mode == hdr->cmh_mode) {
        ver = lastver;
    } else { /* something changed. make a new one */
        if (C_ISDIR(hdr->cmh_type)) {
            sz = sizeof(struct ct_vertree_dir);
        } else if (C_ISBLK(hdr->cmh_type) ||
                   C_ISCHR(hdr->cmh_type)) {
            sz = sizeof(struct ct_vertree_spec);
        } else  if (C_ISLINK(hdr->cmh_type)) {
            sz = sizeof(struct ct_vertree_link);
        } else if (C_ISREG(hdr->cmh_type)) {
            sz = sizeof(struct ct_vertree_file);
        } else {
            CNDBG(CT_LOG_VERTREE, "invalid type %d", hdr->cmh_type);
            goto err;
        }
        ver = e_calloc(1, sz);
        ver->cvv_type = hdr->cmh_type;
        ver->cvv_mtime = hdr->cmh_mtime;
        ver->cvv_atime = hdr->cmh_atime;
        ver->cvv_uid = hdr->cmh_uid;
        ver->cvv_gid = hdr->cmh_gid;
        ver->cvv_mode = hdr->cmh_mode;
        /* dir handled below */
        if (C_ISBLK(hdr->cmh_type) || C_ISCHR(hdr->cmh_type))  {
            spec = (struct ct_vertree_spec *)ver;
            spec->cvs_rdev = hdr->cmh_rdev;
        } else if (C_ISLINK(hdr->cmh_type)) {
            /* hardlink/symlink */
            linkver = (struct ct_vertree_link *)ver;
            linkver->cvl_linkname = e_strdup(hdrlnk->cmh_filename);
            linkver->cvl_hardlink = !C_ISLINK(hdrlnk->cmh_type);
        } else if (C_ISREG(hdr->cmh_type)) {
            file = (struct ct_vertree_file *)ver;
            file->cvf_nr_shas = -1;
        }
        if (allfiles) {
            TAILQ_INSERT_HEAD(&entry->cve_versions, ver, cvv_link);
        } else {
            TAILQ_INSERT_TAIL(&entry->cve_versions, ver, cvv_link);
        }
    }


    /*
     * Each ctfile only has each directory referenced once, so put it
     * in the cache regardless of whether it was known of before, that
     * will be a previous run and the cache will have been wiped since
     * then.
     */
    if (C_ISDIR(hdr->cmh_type)) {
rootdir:
        fb_dnode = e_calloc(1, sizeof(*fb_dnode));
        fb_dnode->cvd_dnode.d_name = e_strdup(entry->cve_name);
        /*
         * in the root_dnode case this will be a bad pointer but it
         * will never be derefed.
         */
        fb_dnode->cvd_dir = entry;
        if ((dnode = ctfile_parse_insertdir(parse_state,
                                            &fb_dnode->cvd_dnode)) != NULL)
            CABORTX("duplicate dentry");
        TAILQ_INSERT_TAIL(&dnode_cache->cache, fb_dnode, cvd_link);
        if (root_dnode) {
            dnode_cache->root_dnode = fb_dnode;
        }
    } else if (C_ISREG(hdr->cmh_type)) {
        /*
         * Allfiles ctfiles may have shas == -1, so in some cases we
         * may wish to update an existing file when we find the actual
         * shas. It is an error to have a file node with -1 for shas
         * after all metadata have been parsed. it means one was
         * missing.
         */
        file = (struct ct_vertree_file *)ver;

        /*
         * bugs in previous editions with incremental selection and
         * off_t on linux mean that there are ctfiles in the wild which
         * provide a list of shas in a later level when the file is
         * defined in an earlier level file, also. For example for the
         * same filename and date we have level 0: 3 shas, level 1: -1
         * shas (i.e. in a previous level), level 2: 3 shas (same as
         * level * 0). In that case we just assume that if we already
         * have sha data for a file * then it is correct and we skip
         * previous versions.
         */
        if (file->cvf_nr_shas != -1) {
            goto out;
        }

        /*
         * previous linux off_t bugs with files over 2gb mean that there
         * are sign extended ctfiles in the wild, so we count those as
         * zero length for purposes of the version tree.
         */
        if (hdr->cmh_nr_shas < -1) {
            hdr->cmh_nr_shas = 0;
        }
        if (hdr->cmh_nr_shas != -1)  {
            file->cvf_nr_shas = hdr->cmh_nr_shas;
            file->cvf_sha_offs = fileoffset;
            file->cvf_file = ctfile;
            if (ctfile_parse_seek(parse_state)) {
                CNDBG(CT_LOG_VERTREE,
                      "failed to skip shas in %s",
                      ctfile->cvc_path);
                goto err;
            }
        }
        if (ctfile_parse(parse_state) != XS_RET_FILE_END) {
            CNDBG(CT_LOG_VERTREE, "no file trailer found");
            goto err;
        }

        file->cvf_file_size = parse_state->xs_trl.cmt_orig_size;
    }

out:
    /*
     * If we're an explicit "/" entry then we don't want to be added to
     * the tree. all our children will be added to the root entry.
     */
    if (root_dnode) {
        e_free(&entry);
    }
    return (0);

err:
    if (entry != NULL)
        e_free(&entry);
    return (CTE_CTFILE_CORRUPT);
}
Пример #23
0
int
ct_version_tree_build(const char *filename, const char *ctfile_basedir,
                      struct ct_version_tree **version_tree)
{
    struct ct_version_tree		*tree = NULL;
    struct ct_extract_head		 extract_head;
    struct ctfile_parse_state	 parse_state;
    struct ct_vertree_dnode_cache	 dnode_cache;
    struct ct_vertree_dnode		*dnode_entry;
    struct ct_vertree_ctfile	*ctfile = NULL;
    struct ct_vertree_dir		*root_dir;
    struct ct_vertree_ver		*root_version;
    off_t				 offset;
    int				 allfiles;
    int				 rv = 0;

    TAILQ_INIT(&extract_head);
    TAILQ_INIT(&dnode_cache.cache);
    dnode_cache.root_dnode = NULL;

    if ((rv = ct_extract_setup(&extract_head, &parse_state, filename,
                               ctfile_basedir, &allfiles))) {
        CNDBG(CT_LOG_VERTREE,
              "failed to setup extract for filename %s: %s",
              filename, ct_strerror(rv));
        goto out;
    }


    /* Create and init ctfile cache */
    tree = e_calloc(1, sizeof(*tree));
    TAILQ_INIT(&tree->cvt_ctfiles);
    TAILQ_INIT(&tree->cvt_head.cve_versions);
    RB_INIT(&tree->cvt_head.cve_children);
    tree->cvt_head.cve_name = e_strdup("/");

nextfile:
    root_dir = e_calloc(1, sizeof(*root_dir));
    root_version = &root_dir->cvd_base;
    root_version->cvv_type = C_TY_DIR;
    root_version->cvv_uid = 0;
    root_version->cvv_gid = 0;
    root_version->cvv_mode = 0777;
    root_version->cvv_atime = parse_state.xs_gh.cmg_created;
    root_version->cvv_mtime = parse_state.xs_gh.cmg_created;
    TAILQ_INSERT_HEAD(&tree->cvt_head.cve_versions, root_version, cvv_link);

    /*
     * Create only one struct for each ctfile.  Each entry in the version
     * tree references the appropriate one.  These are added to a cache list
     * so they can be freed during tree cleanup.
     */
    ctfile = e_calloc(1, sizeof(*ctfile));
    strlcpy(ctfile->cvc_path, parse_state.xs_filename,
            sizeof(ctfile->cvc_path));
    offset = ctfile_parse_tell(&parse_state);
    TAILQ_INSERT_TAIL(&tree->cvt_ctfiles, ctfile, cvc_link);

    while (((rv = ctfile_parse(&parse_state)) != XS_RET_EOF) &&
            (rv != XS_RET_FAIL)) {
        switch(rv) {
        case XS_RET_FILE:
            if ((rv = ct_vertree_add(&dnode_cache, &tree->cvt_head,
                                     &parse_state, ctfile, offset, allfiles)) != 0) {
                goto out;
            }
            break;
        case XS_RET_FILE_END:
            break;
        case XS_RET_SHA:
            if ((rv = ctfile_parse_seek(&parse_state))) {
                goto out;
            }
            break;
        default:
            rv = CTE_CTFILE_CORRUPT;
            goto out;
        }
        offset = ctfile_parse_tell(&parse_state);
    }
    if (rv == XS_RET_EOF) {
        ctfile_parse_close(&parse_state);
        if (!TAILQ_EMPTY(&extract_head)) {
            /* XXX do we need to zero root dnode? */
            ct_extract_open_next(&extract_head, &parse_state);
            goto nextfile;
        }
        rv = 0;
        /* free state */
    } else {
        rv = CTE_CTFILE_CORRUPT;
        goto out;
    }

    *version_tree = tree;

out:
    /* Free dnode_cache entries. */
    while ((dnode_entry = TAILQ_FIRST(&dnode_cache.cache)) != NULL) {
        TAILQ_REMOVE(&dnode_cache.cache, dnode_entry, cvd_link);
        if (dnode_entry->cvd_dnode.d_name != NULL)
            e_free(&dnode_entry->cvd_dnode.d_name);
        e_free(&dnode_entry);
    }

    return rv;
}
Пример #24
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);
}
Пример #25
0
_IMPEXP_ETK void*
etk_create_area(const char *name, void **start_addr, size_t size, euint32 protection, const char *domain, etk_area_access area_access)
{
	if(size <= 0) return NULL;

	char *ipc_name = etk_area_ipc_name(name, domain);
	if(!ipc_name) return NULL;

	etk_win32_area_t *area = new etk_win32_area_t();
	if(!area)
	{
		free(ipc_name);
		return NULL;
	}

	area->prot = protection;

#if 0
	SECURITY_ATTRIBUTES sa;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	EString szStr;
	szStr << "D:";				// Discretionary ACL
	szStr << "(D;OICI;GA;;;BG)";		// Deny access to built-in guests
	szStr << "(D;OICI;GA;;;AN)";		// Deny access to anonymous logon
	szStr << "(A;OICI;GA;;;BA)";		// Allow full control to administrators
	szStr << "(A;OICI;GA;;;CO)";		// Allow full control to creator owner

	if((area_access & ETK_AREA_ACCESS_GROUP_READ) || (area_access & ETK_AREA_ACCESS_GROUP_WRITE))
	{
		if(area_access & ETK_AREA_ACCESS_GROUP_WRITE)
			szStr << "(A;OICI;GA;;;CG)";	// Allow full control to creator group
		else
			szStr << "(A;OICI;GR;;;CG)";	// Allow read control to creator group
	}

	if((area_access & ETK_AREA_ACCESS_OTHERS_READ) || (area_access & ETK_AREA_ACCESS_OTHERS_WRITE))
	{
		if(area_access & ETK_AREA_ACCESS_OTHERS_WRITE)
			szStr << "(A;OICI;GA;;;BU)";	// Allow full control to others
		else
			szStr << "(A;OICI;GR;;;BU)";	// Allow read control to others
	}

	if(!ConvertStringSecurityDescriptorToSecurityDescriptor(szStr.String(), SDDL_REVISION_1, (PSECURITY_DESCRIPTOR*)&(sa.lpSecurityDescriptor), NULL))
	{
		delete area;
		free(ipc_name);
		return NULL;
	}
#endif

	HANDLE handler;

	_ETK_LOCK_AREA_();
	if((handler = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT, 0, size + sizeof(etk_win32_area_info_t), ipc_name)) == NULL)
	{
		_ETK_UNLOCK_AREA_();
		ETK_DEBUG("[KERNEL]: %s --- Can't create area : CreateFileMapping failed.", __PRETTY_FUNCTION__);
		free(ipc_name);
		delete area;
		return NULL;
	}

//	if(sa.lpSecurityDescriptor != NULL) LocalFree(sa.lpSecurityDescriptor);

	DWORD prot = (protection & E_WRITE_AREA ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ);

	if((area->addr = MapViewOfFile(handler, prot, 0, 0, 0)) == NULL)
	{
		ETK_DEBUG("[KERNEL]: %s --- Can't create area : MapViewOfFile failed.", __PRETTY_FUNCTION__);
		CloseHandle(handler);
		_ETK_UNLOCK_AREA_();
		free(ipc_name);
		delete area;
		return NULL;
	}

	etk_win32_area_info_t area_info;
	area_info.magic = WIN32_AREA_INFO_MAGIC;
	area_info.closed = false;
	area_info.length = size;
	memcpy(area->addr, &area_info, sizeof(etk_win32_area_info_t));

	area->length = size;
	area->mapping = handler;
	area->name = e_strdup(name);
	area->domain = e_strdup(domain);
	area->ipc_name = ipc_name;
	area->created = true;

	_ETK_UNLOCK_AREA_();

	if(start_addr) *start_addr = (void*)((char*)area->addr + sizeof(etk_win32_area_info_t));
	return area;
}
Пример #26
0
_IMPEXP_ETK void*
etk_clone_area(const char *name, void **dest_addr, euint32 protection, const char *domain)
{
	char *ipc_name = etk_area_ipc_name(name, domain);
	if(!ipc_name) return NULL;

	etk_win32_area_t *area = new etk_win32_area_t();
	if(!area)
	{
		free(ipc_name);
		return NULL;
	}

	area->prot = protection;

	DWORD prot = (protection & E_WRITE_AREA ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ);

	HANDLE handler;

	_ETK_LOCK_AREA_();
	if((handler = OpenFileMapping(prot, FALSE, ipc_name)) == NULL)
	{
//		ETK_DEBUG("[KERNEL]: %s --- Can't clone area : open file mapping failed."", __PRETTY_FUNCTION__);
		_ETK_UNLOCK_AREA_();
		free(ipc_name);
		delete area;
		return NULL;
	}

	if((area->addr = MapViewOfFile(handler, prot, 0, 0, 0)) == NULL)
	{
		ETK_DEBUG("[KERNEL]: %s --- Can't clone area : MapViewOfFile failed.", __PRETTY_FUNCTION__);
		CloseHandle(handler);
		_ETK_UNLOCK_AREA_();
		free(ipc_name);
		delete area;
		return NULL;
	}

	etk_win32_area_info_t area_info;
	bzero(&area_info, sizeof(etk_win32_area_info_t));
	memcpy(&area_info, area->addr, sizeof(etk_win32_area_info_t));
	if(area_info.magic != WIN32_AREA_INFO_MAGIC || area_info.closed)
	{
		ETK_WARNING("[KERNEL]: %s --- FileMapping(%s) seem not created by ETK", __PRETTY_FUNCTION__, ipc_name);
		UnmapViewOfFile(area->addr);
		CloseHandle(handler);
		_ETK_UNLOCK_AREA_();
		free(ipc_name);
		delete area;
		return NULL;
	}

	area->length = area_info.length;
	area->mapping = handler;
	area->name = e_strdup(name);
	area->domain = e_strdup(domain);
	area->ipc_name = ipc_name;
	area->openedIPC = true;
	area->created = true;

	_ETK_UNLOCK_AREA_();

	if(dest_addr) *dest_addr = (void*)((char*)area->addr + sizeof(etk_win32_area_info_t));
	return area;
}