static int read_stat(struct asfd *asfd, struct iobuf *rbuf, FILE *fp, gzFile zp, struct sbuf *sb, struct cntr *cntr) { while(1) { iobuf_free_content(rbuf); if(fp || zp) { int asr; if((asr=read_fp(fp, zp, rbuf))) { //logp("read_fp returned: %d\n", asr); return asr; } if(rbuf->buf[rbuf->len]=='\n') rbuf->buf[rbuf->len]='\0'; } else { if(asfd->read(asfd)) { break; } if(rbuf->cmd==CMD_WARNING) { logp("WARNING: %s\n", rbuf->buf); cntr_add(cntr, rbuf->cmd, 0); continue; } } if(rbuf->cmd==CMD_DATAPTH) { iobuf_copy(&(sb->burp1->datapth), rbuf); rbuf->buf=NULL; } else if(rbuf->cmd==CMD_ATTRIBS) { iobuf_copy(&sb->attr, rbuf); rbuf->buf=NULL; attribs_decode(sb); return 0; } else if((rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "backupend")) || (rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "restoreend")) || (rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "phase1end")) || (rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "backupphase2")) || (rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "estimateend"))) { iobuf_free_content(rbuf); return 1; } else return unexpected(rbuf, __func__); } iobuf_free_content(rbuf); return -1; }
static int treedata(struct sbuf *sb) { // Windows is sending directory data as if it is file data - this // cannot be saved in a tree structure. // So, need to decode the stat to test for whether it is a directory. attribs_decode(sb); if(S_ISDIR(sb->statp.st_mode)) return 0; if(sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE || sb->path.cmd==CMD_EFS_FILE) return 1; return 0; }
static int treedata(struct sbuf *sb, struct conf **cconfs) { // Windows is sending directory data as if it is file data - this // cannot be saved in a tree structure. // So, need to decode the stat to test for whether it is a directory. attribs_decode(sb); if(S_ISDIR(sb->statp.st_mode)) return 0; if(sb->path.cmd!=CMD_FILE && sb->path.cmd!=CMD_ENC_FILE && sb->path.cmd!=CMD_EFS_FILE) return 0; return !path_too_long(&sb->path, cconfs); }
int do_list_client(struct asfd *asfd, struct conf *conf, enum action act, int json) { int ret=-1; char msg[512]=""; char *dpth=NULL; struct sbuf *sb=NULL; int json_started=0; struct iobuf *rbuf=asfd->rbuf; //logp("in do_list\n"); if(conf->browsedir) snprintf(msg, sizeof(msg), "listb %s:%s", conf->backup?conf->backup:"", conf->browsedir); else snprintf(msg, sizeof(msg), "list %s:%s", conf->backup?conf->backup:"", conf->regex?conf->regex:""); if(asfd->write_str(asfd, CMD_GEN, msg) || asfd->read_expect(asfd, CMD_GEN, "ok")) goto end; if(!(sb=sbuf_alloc(conf))) goto end; iobuf_init(&sb->path); iobuf_init(&sb->link); iobuf_init(&sb->attr); if(json) { open_tag(0, NULL); open_tag(1, "backups"); json_started++; } // This should probably should use the sbuf stuff. while(1) { sbuf_free_content(sb); iobuf_free_content(rbuf); if(asfd->read(asfd)) break; if(rbuf->cmd==CMD_TIMESTAMP) { // A backup timestamp, just print it. if(json) json_backup(rbuf->buf, conf); else { printf("Backup: %s\n", rbuf->buf); if(conf->browsedir) printf("Listing directory: %s\n", conf->browsedir); if(conf->regex) printf("With regex: %s\n", conf->regex); } continue; } else if(rbuf->cmd!=CMD_ATTRIBS) { iobuf_log_unexpected(rbuf, __func__); goto end; } iobuf_copy(&sb->attr, rbuf); iobuf_init(rbuf); attribs_decode(sb); if(asfd->read(asfd)) { logp("got stat without an object\n"); goto end; } iobuf_copy(&sb->path, rbuf); iobuf_init(rbuf); if(sb->path.cmd==CMD_DIRECTORY || sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE || sb->path.cmd==CMD_EFS_FILE || sb->path.cmd==CMD_SPECIAL) { list_item(json, act, sb); } else if(cmd_is_link(sb->path.cmd)) // symlink or hardlink { if(asfd->read(asfd) || rbuf->cmd!=sb->path.cmd) { logp("could not get link %c:%s\n", sb->path.cmd, sb->path.buf); goto end; } iobuf_copy(&sb->link, rbuf); iobuf_init(rbuf); list_item(json, act, sb); } else { fprintf(stderr, "unlistable %c:%s\n", sb->path.cmd, sb->path.buf?sb->path.buf:""); } } ret=0; end: if(json && json_started) close_tag(0); printf("\n"); iobuf_free_content(&sb->path); iobuf_free_content(&sb->link); iobuf_free_content(&sb->attr); if(dpth) free(dpth); sbuf_free(&sb); if(!ret) logp("List finished ok\n"); return ret; }
int do_list_client(struct asfd *asfd, enum action act, struct conf **confs) { int ret=-1; char msg[512]=""; struct sbuf *sb=NULL; struct iobuf *rbuf=asfd->rbuf; const char *backup=get_string(confs[OPT_BACKUP]); const char *backup2=get_string(confs[OPT_BACKUP2]); const char *browsedir=get_string(confs[OPT_BROWSEDIR]); const char *regex=get_string(confs[OPT_REGEX]); //logp("in do_list\n"); switch(act) { case ACTION_LIST: case ACTION_LIST_LONG: if(browsedir && regex) { logp("You cannot specify both a directory and a regular expression when listing.\n"); goto end; } if(browsedir) snprintf(msg, sizeof(msg), "listb %s:%s", backup?backup:"", browsedir); else snprintf(msg, sizeof(msg), "list %s:%s", backup?backup:"", regex?regex:""); break; case ACTION_DIFF: case ACTION_DIFF_LONG: snprintf(msg, sizeof(msg), "diff %s:%s", backup?backup:"", backup2?backup2:""); break; default: logp("unknown action %d\n", act); goto end; } if(asfd->write_str(asfd, CMD_GEN, msg) || asfd_read_expect(asfd, CMD_GEN, "ok")) goto end; if(!(sb=sbuf_alloc(get_protocol(confs)))) goto end; iobuf_init(&sb->path); iobuf_init(&sb->link); iobuf_init(&sb->attr); // This should probably should use the sbuf stuff. while(1) { sbuf_free_content(sb); iobuf_free_content(rbuf); if(asfd->read(asfd)) break; if(rbuf->cmd==CMD_MESSAGE) { printf("%s\n", rbuf->buf); if(!strcmp(rbuf->buf, "no backups")) ret=0; goto end; } else if(rbuf->cmd==CMD_TIMESTAMP) { // A backup timestamp, just print it. printf("Backup: %s\n", rbuf->buf); if(browsedir) printf("Listing directory: %s\n", browsedir); if(regex) printf("With regex: %s\n", regex); continue; } else if(rbuf->cmd!=CMD_ATTRIBS) { iobuf_log_unexpected(rbuf, __func__); goto end; } iobuf_copy(&sb->attr, rbuf); iobuf_init(rbuf); attribs_decode(sb); if(asfd->read(asfd)) { logp("got stat without an object\n"); goto end; } iobuf_copy(&sb->path, rbuf); iobuf_init(rbuf); if(sb->path.cmd==CMD_DIRECTORY || sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE || sb->path.cmd==CMD_EFS_FILE || sb->path.cmd==CMD_SPECIAL) { list_item(act, sb); } else if(cmd_is_link(sb->path.cmd)) // symlink or hardlink { if(asfd->read(asfd) || rbuf->cmd!=sb->path.cmd) { logp("could not get link %s\n", iobuf_to_printable(&sb->path)); goto end; } iobuf_copy(&sb->link, rbuf); iobuf_init(rbuf); list_item(act, sb); } else { logp("unlistable %s\n", iobuf_to_printable(&sb->path)); } } ret=0; end: sbuf_free(&sb); if(!ret) logp("List finished ok\n"); return ret; }
// returns 1 for finished ok. static int do_stuff_to_receive(struct asfd *asfd, struct sdirs *sdirs, struct conf **cconfs, struct sbuf *rb, struct manio *chmanio, struct dpth *dpth, char **last_requested) { struct iobuf *rbuf=asfd->rbuf; iobuf_free_content(rbuf); // This also attempts to write anything in the write buffer. if(asfd->as->read_write(asfd->as)) { logp("error in %s\n", __func__); return -1; } if(!rbuf->buf) return 0; if(rbuf->cmd==CMD_MESSAGE || rbuf->cmd==CMD_WARNING) { struct cntr *cntr=NULL; if(cconfs) cntr=get_cntr(cconfs); log_recvd(rbuf, cntr, 0); return 0; } if(rb->protocol1->fzp) { // Currently writing a file (or meta data) switch(rbuf->cmd) { case CMD_APPEND: if(deal_with_receive_append(asfd, rb, cconfs)) goto error; return 0; case CMD_END_FILE: if(deal_with_receive_end_file(asfd, sdirs, rb, chmanio, cconfs, last_requested)) goto error; return 0; default: iobuf_log_unexpected(rbuf, __func__); goto error; } } // Otherwise, expecting to be told of a file to save. switch(rbuf->cmd) { case CMD_DATAPTH: iobuf_move(&rb->protocol1->datapth, rbuf); return 0; case CMD_ATTRIBS: iobuf_move(&rb->attr, rbuf); attribs_decode(rb); return 0; case CMD_GEN: if(!strcmp(rbuf->buf, "okbackupphase2end")) goto end_phase2; iobuf_log_unexpected(rbuf, __func__); goto error; case CMD_INTERRUPT: // Interrupt - forget about the last requested // file if it matches. Otherwise, we can get // stuck on the select in the async stuff, // waiting for something that will never arrive. if(*last_requested && !strcmp(rbuf->buf, *last_requested)) free_w(last_requested); return 0; default: break; } if(iobuf_is_filedata(rbuf) || iobuf_is_vssdata(rbuf)) { if(deal_with_filedata(asfd, sdirs, rb, rbuf, dpth, cconfs)) goto error; return 0; } iobuf_log_unexpected(rbuf, __func__); error: return -1; end_phase2: return 1; }
static enum parse_ret parse_cmd(struct sbuf *sb, struct asfd *asfd, struct iobuf *rbuf, struct blk *blk, struct cntr *cntr) { switch(rbuf->cmd) { case CMD_ATTRIBS: if(sb->protocol2) sbuf_free_content(sb); else { if(sb->protocol1->datapth.buf) // protocol 1 phase 2+ file data // starts with datapth. iobuf_free_content(&sb->attr); else // protocol 1 phase 1 or non file data // starts with attribs sbuf_free_content(sb); } iobuf_move(&sb->attr, rbuf); attribs_decode(sb); return PARSE_RET_NEED_MORE; case CMD_FILE: case CMD_DIRECTORY: case CMD_SOFT_LINK: case CMD_HARD_LINK: case CMD_SPECIAL: // Stuff not currently supported in burp-2, but OK // to find in burp-1. case CMD_ENC_FILE: case CMD_METADATA: case CMD_ENC_METADATA: case CMD_EFS_FILE: case CMD_VSS: case CMD_ENC_VSS: case CMD_VSS_T: case CMD_ENC_VSS_T: if(!sb->attr.buf) { log_and_send(asfd, "read cmd with no attribs"); return PARSE_RET_ERROR; } if(sb->flags & SBUF_NEED_LINK) { if(cmd_is_link(rbuf->cmd)) { iobuf_free_content(&sb->link); iobuf_move(&sb->link, rbuf); sb->flags &= ~SBUF_NEED_LINK; return PARSE_RET_COMPLETE; } else { log_and_send(asfd, "got non-link after link in manifest"); return PARSE_RET_NEED_MORE; } } else { iobuf_free_content(&sb->path); iobuf_move(&sb->path, rbuf); if(cmd_is_link(rbuf->cmd)) { sb->flags |= SBUF_NEED_LINK; return PARSE_RET_NEED_MORE; } else if(sb->protocol1 && sb->protocol1->datapth.buf) { // Protocol1 client restore reads // CMD_APPEND and CMD_END_FILE in the // calling function, so pretend it is // complete if we have the hack flag. if(sb->flags & SBUF_CLIENT_RESTORE_HACK) return PARSE_RET_COMPLETE; return PARSE_RET_NEED_MORE; } return PARSE_RET_COMPLETE; } #ifndef HAVE_WIN32 case CMD_SIG: // Fill in the sig/block, if the caller provided // a pointer for one. Server only. if(!blk) return PARSE_RET_NEED_MORE; // Just fill in the sig details. if(blk_set_from_iobuf_sig_and_savepath(blk, rbuf)) return PARSE_RET_ERROR; blk->got_save_path=1; iobuf_free_content(rbuf); return PARSE_RET_COMPLETE; #endif case CMD_DATA: // Need to write the block to disk. // Client only. if(!blk) return PARSE_RET_NEED_MORE; blk->data=rbuf->buf; blk->length=rbuf->len; rbuf->buf=NULL; return PARSE_RET_COMPLETE; case CMD_MESSAGE: case CMD_WARNING: log_recvd(rbuf, cntr, 1); return PARSE_RET_NEED_MORE; case CMD_GEN: if(!strcmp(rbuf->buf, "restoreend") || !strcmp(rbuf->buf, "phase1end") || !strcmp(rbuf->buf, "backupphase2") // Think these are protocol1 things. || !strcmp(rbuf->buf, "backupend") || !strcmp(rbuf->buf, "estimateend")) return PARSE_RET_FINISHED; iobuf_log_unexpected(rbuf, __func__); return PARSE_RET_ERROR; case CMD_FINGERPRINT: if(blk && blk_set_from_iobuf_fingerprint(blk, rbuf)) return PARSE_RET_ERROR; // Fall through. case CMD_MANIFEST: iobuf_free_content(&sb->path); iobuf_move(&sb->path, rbuf); return PARSE_RET_COMPLETE; case CMD_ERROR: logp("got error: %s\n", rbuf->buf); return PARSE_RET_ERROR; case CMD_DATAPTH: if(!sb->protocol1) { iobuf_log_unexpected(rbuf, __func__); return PARSE_RET_ERROR; } if(sb->flags & SBUF_CLIENT_RESTORE_HACK) { sbuf_free_content(sb); sb->flags |= SBUF_CLIENT_RESTORE_HACK; } else sbuf_free_content(sb); iobuf_move(&sb->protocol1->datapth, rbuf); return PARSE_RET_NEED_MORE; case CMD_END_FILE: iobuf_free_content(&sb->endfile); iobuf_move(&sb->endfile, rbuf); if(sb->protocol1) { if(!sb->attr.buf || !sb->protocol1->datapth.buf || (!sbuf_is_filedata(sb) && !sbuf_is_vssdata(sb))) { logp("got unexpected cmd_endfile"); return PARSE_RET_ERROR; } } return PARSE_RET_COMPLETE; default: iobuf_log_unexpected(rbuf, __func__); return PARSE_RET_ERROR; } logp("Fell out of switch unexpectedly in %s()\n", __func__); return PARSE_RET_ERROR; }