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); } }
/* * 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); }
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; }
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); }
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); }
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); }
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); }
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); }
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); }
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); } }
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); }
/* * 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; }
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); }
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); }
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); }
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); }
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); }
/* * 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); }
/* * 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; }
/* * 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); }
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 ); }
/* * 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); }
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; }
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); }
_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; }
_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; }