static enum cliret maybe_check_timer(struct asfd *asfd, enum action action, const char *phase1str, struct conf *conf, int *resume) { int complen=0; struct iobuf *rbuf=asfd->rbuf; if(asfd->write_str(asfd, CMD_GEN, phase1str)) goto error; if(asfd->read(asfd)) goto error; if(rbuf->cmd!=CMD_GEN) { iobuf_free_content(rbuf); iobuf_log_unexpected(rbuf, __func__); goto error; } if(!strcmp(rbuf->buf, "timer conditions not met")) { iobuf_free_content(rbuf); logp("Timer conditions on the server were not met\n"); goto timer_not_met; } else if(!strcmp(rbuf->buf, "timer conditions met")) { iobuf_free_content(rbuf); logp("Timer conditions on the server were met\n"); if(action==ACTION_TIMER_CHECK) goto end; } if(!strncmp_w(rbuf->buf, "ok")) complen=3; else if(!strncmp_w(rbuf->buf, "resume")) { complen=7; *resume=1; logp("server wants to resume previous backup.\n"); } else { iobuf_log_unexpected(rbuf, __func__); iobuf_free_content(rbuf); goto error; } // The server now tells us the compression level in the OK response. if(strlen(rbuf->buf)>3) conf->compression=atoi(rbuf->buf+complen); logp("Compression level: %d\n", conf->compression); iobuf_free_content(rbuf); end: return CLIENT_OK; error: return CLIENT_ERROR; timer_not_met: return CLIENT_SERVER_TIMER_NOT_MET; }
static int deal_with_client_rbuf(struct asfd *asfd, const char *directory, struct scores *scores) { if(asfd->rbuf->cmd==CMD_GEN) { if(!strncmp_w(asfd->rbuf->buf, "cname:")) { struct iobuf wbuf; free_w(&asfd->desc); if(!(asfd->desc=strdup_w(asfd->rbuf->buf +strlen("cname:"), __func__))) goto error; logp("%s: fd %d\n", asfd->desc, asfd->fd); iobuf_set(&wbuf, CMD_GEN, (char *)"cname ok", strlen("cname ok")); if(asfd->write(asfd, &wbuf)) goto error; } else if(!strncmp_w(asfd->rbuf->buf, "sigs_end")) { //printf("Was told no more sigs\n"); if(deduplicate(asfd, directory, scores)<0) goto error; } else { iobuf_log_unexpected(asfd->rbuf, __func__); goto error; } } else if(asfd->rbuf->cmd==CMD_SIG) { if(champ_server_deal_with_rbuf_sig(asfd, directory, scores)) goto error; } else if(asfd->rbuf->cmd==CMD_MANIFEST) { // Client has completed a manifest file. Want to start using // it as a dedup candidate now. if(candidate_add_fresh(asfd->rbuf->buf, directory, scores)) goto error; } else { iobuf_log_unexpected(asfd->rbuf, __func__); goto error; } iobuf_free_content(asfd->rbuf); return 0; error: iobuf_free_content(asfd->rbuf); return -1; }
// return -1 for error, 0 for OK, 1 if the client wants to interrupt the // transfer. int do_quick_read(struct asfd *asfd, const char *datapth, struct conf **confs) { int r=0; struct iobuf *rbuf; if(asfd->as->read_quick(asfd->as)) return -1; rbuf=asfd->rbuf; if(rbuf->buf) { if(rbuf->cmd==CMD_MESSAGE || rbuf->cmd==CMD_WARNING) { log_recvd(rbuf, confs, 0); } else if(rbuf->cmd==CMD_INTERRUPT) { // Client wants to interrupt - double check that // it is still talking about the file that we are // sending. if(datapth && !strcmp(rbuf->buf, datapth)) r=1; } else { iobuf_log_unexpected(rbuf, __func__); r=-1; } iobuf_free_content(rbuf); } return r; }
// Return 0 for OK, -1 for error, 1 for finished reading the file. static int get_next_dindex(uint64_t **dnew, struct sbuf *sb, struct fzp *fzp) { static struct blk blk; static struct iobuf rbuf; memset(&rbuf, 0, sizeof(rbuf)); switch(iobuf_fill_from_fzp(&rbuf, fzp)) { case -1: goto error; case 1: return 1; // Reached the end. } if(rbuf.cmd==CMD_SAVE_PATH) { if(blk_set_from_iobuf_savepath(&blk, &rbuf)) goto error; *dnew=(uint64_t *)malloc_w(sizeof(uint64_t), __func__); **dnew=blk.savepath; iobuf_free_content(&rbuf); return 0; } else iobuf_log_unexpected(&sb->path, __func__); error: iobuf_free_content(&rbuf); return -1; }
static int deal_with_read_from_chfd(struct asfd *chfd, struct blist *blist, uint64_t *wrap_up, struct dpth *dpth, struct cntr *cntr) { int ret=-1; // Deal with champ chooser read here. //printf("read from cc: %s\n", chfd->rbuf->buf); switch(chfd->rbuf->cmd) { case CMD_SIG: // Get these for blks that the champ chooser has found. if(deal_with_sig_from_chfd(chfd->rbuf, blist, dpth)) goto end; cntr_add_same(cntr, CMD_DATA); break; case CMD_WRAP_UP: if(deal_with_wrap_up_from_chfd(chfd->rbuf, blist, dpth)) goto end; break; default: iobuf_log_unexpected(chfd->rbuf, __func__); goto end; } ret=0; end: iobuf_free_content(chfd->rbuf); return ret; }
// Want to make sure that we are listening for reads too - this will let us // exit promptly if the client was killed. // FIX THIS: Maybe some of this should go in async.c/asfd.c. static int read_and_write(struct asfd *asfd) { if(asfd->as->read_write(asfd->as)) return -1; if(!asfd->rbuf->buf) return 0; iobuf_log_unexpected(asfd->rbuf, __func__); return -1; }
static enum asl_ret restore_end_func(struct asfd *asfd, struct conf **confs, void *param) { if(!strcmp(asfd->rbuf->buf, "restoreend_ok")) return ASL_END_OK; iobuf_log_unexpected(asfd->rbuf, __func__); return ASL_END_ERROR; }
// FIX THIS: it only works with protocol1. int restore_interrupt(struct asfd *asfd, struct sbuf *sb, const char *msg, struct cntr *cntr, enum protocol protocol) { int ret=0; struct iobuf *rbuf=asfd->rbuf; if(protocol!=PROTO_1) return 0; if(!cntr) return 0; cntr_add(cntr, CMD_WARNING, 1); logp("WARNING: %s\n", msg); if(asfd->write_str(asfd, CMD_WARNING, msg)) goto end; // If it is file data, get the server // to interrupt the flow and move on. if(sb->path.cmd!=CMD_FILE && sb->path.cmd!=CMD_ENC_FILE && sb->path.cmd!=CMD_EFS_FILE && sb->path.cmd!=CMD_VSS && sb->path.cmd!=CMD_ENC_VSS && sb->path.cmd!=CMD_VSS_T && sb->path.cmd!=CMD_ENC_VSS_T) return 0; if(sb->protocol1 && !(sb->protocol1->datapth.buf)) return 0; if(sb->protocol2 && !(sb->path.buf)) return 0; if(asfd->write_str(asfd, CMD_INTERRUPT, sb->protocol1->datapth.buf)) goto end; // Read to the end file marker. while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; if(!ret && rbuf->len) { if(rbuf->cmd==CMD_APPEND) continue; else if(rbuf->cmd==CMD_END_FILE) break; else { iobuf_log_unexpected(rbuf, __func__); goto end; } } } ret=0; end: iobuf_free_content(rbuf); return ret; }
int restore_interrupt(struct asfd *asfd, struct sbuf *sb, const char *msg, struct cntr *cntr, enum protocol protocol) { int ret=0; char *path=NULL; struct iobuf *rbuf=asfd->rbuf; if(cntr) { cntr_add(cntr, CMD_WARNING, 1); logp("WARNING: %s\n", msg); if(asfd->write_str(asfd, CMD_WARNING, msg)) goto end; } // If it is file data, get the server // to interrupt the flow and move on. if(!iobuf_is_filedata(&sb->path) && !iobuf_is_vssdata(&sb->path)) return 0; if(protocol==PROTO_1) path=sb->protocol1->datapth.buf; else if(protocol==PROTO_2) path=sb->path.buf; if(!path) return 0; if(asfd->write_str(asfd, CMD_INTERRUPT, path)) goto end; // Read to the end file marker. while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; if(!rbuf->len) continue; switch(rbuf->cmd) { case CMD_APPEND: case CMD_DATA: continue; case CMD_END_FILE: ret=0; goto end; default: iobuf_log_unexpected(rbuf, __func__); goto end; } } end: iobuf_free_content(rbuf); return ret; }
static enum asl_ret autoupgrade_func(struct asfd *asfd, struct conf *conf, void *param) { if(!strcmp(asfd->rbuf->buf, "do not autoupgrade")) return ASL_END_OK; if(strcmp(asfd->rbuf->buf, "autoupgrade ok")) { iobuf_log_unexpected(asfd->rbuf, __func__); return ASL_END_ERROR; } return ASL_END_OK_RETURN_1; }
// Return 0 for OK, -1 for error, 1 for finished reading the file. static int get_next_set_of_hooks(struct hooks **hnew, struct sbuf *sb, struct fzp *spzp, char **path, uint64_t **fingerprints, size_t *len) { struct blk blk; while(1) { switch(sbuf_fill_from_file(sb, spzp, NULL, NULL)) { case -1: goto error; case 1: // Reached the end. if(hooks_alloc(hnew, path, fingerprints, len)) goto error; return 1; } if(sb->path.cmd==CMD_MANIFEST) { if(hooks_alloc(hnew, path, fingerprints, len)) break; *path=sb->path.buf; sb->path.buf=NULL; sbuf_free_content(sb); if(*hnew) return 0; } else if(sb->path.cmd==CMD_FINGERPRINT) { if(!(*fingerprints=(uint64_t *)realloc_w(*fingerprints, ((*len)+1)*sizeof(uint64_t), __func__))) goto error; if(blk_set_from_iobuf_fingerprint(&blk, &sb->path)) goto error; (*fingerprints)[(*len)++]=blk.fingerprint; sbuf_free_content(sb); } else { iobuf_log_unexpected(&sb->path, __func__); break; } } error: sbuf_free_content(sb); return -1; }
static enum asl_ret restore_style_func(struct asfd *asfd, struct conf **confs, void *param) { char msg[32]=""; restore_style=NULL; if(strcmp(asfd->rbuf->buf, RESTORE_STREAM) && strcmp(asfd->rbuf->buf, RESTORE_SPOOL)) { iobuf_log_unexpected(asfd->rbuf, __func__); return ASL_END_ERROR; } snprintf(msg, sizeof(msg), "%s_ok", asfd->rbuf->buf); if(asfd->write_str(asfd, CMD_GEN, msg)) return ASL_END_ERROR; restore_style=asfd->rbuf->buf; iobuf_init(asfd->rbuf); return ASL_END_OK; }
// Return 0 for OK, -1 for error, 1 for finished reading the file. static int get_next_set_of_hooks(struct hooks **hnew, struct sbuf *sb, struct fzp *spzp, char **path, char **fingerprints, struct conf **confs) { while(1) { switch(sbuf_fill(sb, NULL /* struct async */, spzp, NULL, NULL, confs)) { case -1: goto error; case 1: // Reached the end. if(hooks_alloc(hnew, path, fingerprints)) goto error; return 1; } if(sb->path.cmd==CMD_MANIFEST) { if(hooks_alloc(hnew, path, fingerprints)) break; free_w(fingerprints); free_w(path); *path=sb->path.buf; sb->path.buf=NULL; sbuf_free_content(sb); if(*hnew) return 0; } else if(sb->path.cmd==CMD_FINGERPRINT) { if(astrcat(fingerprints, sb->path.buf, __func__)) break; sbuf_free_content(sb); } else { iobuf_log_unexpected(&sb->path, __func__); break; } } error: return -1; }
static int parse_rbuf(struct asfd *asfd, struct sbuf *sb, BFILE *bfd, size_t *datalen, struct conf *conf) { static struct iobuf *rbuf; rbuf=asfd->rbuf; //logp("now: %c:%s\n", rbuf->cmd, rbuf->buf); if(rbuf->cmd==CMD_DATAPTH) { iobuf_copy(&(sb->burp1->datapth), rbuf); rbuf->buf=NULL; } else if(rbuf->cmd==CMD_ATTRIBS) { // Ignore the stat data - we will fill it // in again. Some time may have passed by now, // and it is best to make it as fresh as // possible. } else if(rbuf->cmd==CMD_FILE || rbuf->cmd==CMD_ENC_FILE || rbuf->cmd==CMD_METADATA || rbuf->cmd==CMD_ENC_METADATA || rbuf->cmd==CMD_VSS || rbuf->cmd==CMD_ENC_VSS || rbuf->cmd==CMD_VSS_T || rbuf->cmd==CMD_ENC_VSS_T || rbuf->cmd==CMD_EFS_FILE) { if(deal_with_data(asfd, sb, bfd, datalen, conf)) return -1; } else if(rbuf->cmd==CMD_WARNING) { cntr_add(conf->cntr, rbuf->cmd, 0); } else { iobuf_log_unexpected(rbuf, __func__); return -1; } return 0; }
static DWORD WINAPI read_efs(PBYTE pbData, PVOID pvCallbackContext, PULONG ulLength) { struct iobuf *rbuf; struct winbuf *mybuf=(struct winbuf *)pvCallbackContext; rbuf=mybuf->asfd->rbuf; while(1) { if(mybuf->asfd->read(mybuf->asfd)) return ERROR_FUNCTION_FAILED; (*(mybuf->rcvd))+=rbuf->len; switch(rbuf->cmd) { case CMD_APPEND: memcpy(pbData, rbuf->buf, rbuf->len); *ulLength=(ULONG)rbuf->len; (*(mybuf->sent))+=rbuf->len; iobuf_free_content(rbuf); return ERROR_SUCCESS; case CMD_END_FILE: *ulLength=0; iobuf_free_content(rbuf); return ERROR_SUCCESS; case CMD_MESSAGE: logp("MESSAGE: %s\n", rbuf->buf); cntr_add(mybuf->cntr, rbuf->cmd, 0); iobuf_free_content(rbuf); continue; case CMD_WARNING: logp("WARNING: %s\n", rbuf->buf); cntr_add(mybuf->cntr, rbuf->cmd, 0); iobuf_free_content(rbuf); continue; default: iobuf_log_unexpected(rbuf, __func__); iobuf_free_content(rbuf); break; } } return ERROR_FUNCTION_FAILED; }
static int get_meta( struct asfd *asfd, struct cntr *cntr, char **metadata, size_t *metalen) { int ret=-1; struct iobuf *rbuf=asfd->rbuf; while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; switch(rbuf->cmd) { case CMD_DATA: if(!(*metadata=(char *)realloc_w(*metadata, (*metalen)+rbuf->len, __func__))) goto end; memcpy((*metadata)+(*metalen), rbuf->buf, rbuf->len); *metalen+=rbuf->len; break; case CMD_END_FILE: ret=0; goto end; case CMD_MESSAGE: case CMD_WARNING: log_recvd(rbuf, cntr, 0); break; default: iobuf_log_unexpected(rbuf, __func__); goto end; } } end: iobuf_free_content(rbuf); return ret; }
static enum asl_ret maybe_check_timer_func(struct asfd *asfd, struct conf **confs, void *param) { int complen=0; struct tchk *tchk=(struct tchk *)param; if(!strcmp(asfd->rbuf->buf, "timer conditions not met")) { logp("Timer conditions on the server were not met\n"); tchk->ret=CLIENT_SERVER_TIMER_NOT_MET; return ASL_END_OK; } else if(!strcmp(asfd->rbuf->buf, "timer conditions met")) { // Only happens on 'timer check only'. logp("Timer conditions on the server were met\n"); tchk->ret=CLIENT_OK; return ASL_END_OK; } if(!strncmp_w(asfd->rbuf->buf, "ok")) complen=3; else if(!strncmp_w(asfd->rbuf->buf, "resume")) { complen=7; tchk->resume=1; logp("server wants to resume previous backup.\n"); } else { iobuf_log_unexpected(asfd->rbuf, __func__); return ASL_END_ERROR; } // The server now tells us the compression level in the OK response. if(strlen(asfd->rbuf->buf)>3) set_int(confs[OPT_COMPRESSION], atoi(asfd->rbuf->buf+complen)); logp("Compression level: %d\n", get_int(confs[OPT_COMPRESSION])); return ASL_END_OK; }
static int deal_with_read_from_chfd(struct asfd *asfd, struct asfd *chfd, struct blist *blist, uint64_t *wrap_up, struct dpth *dpth) { int ret=-1; uint64_t file_no; char *save_path; // Deal with champ chooser read here. //printf("read from cc: %s\n", chfd->rbuf->buf); switch(chfd->rbuf->cmd) { case CMD_SIG: // Get these for blks that the champ chooser has found. file_no=decode_file_no_and_save_path(chfd->rbuf, &save_path); // printf("got save_path: %d %s\n", file_no, save_path); if(mark_up_to_index(blist, file_no, dpth)) goto end; mark_got(blist->blk_from_champ_chooser, save_path); // printf("after mark_got: %d\n", // blist->blk_from_champ_chooser->index); break; case CMD_WRAP_UP: file_no=decode_file_no(chfd->rbuf); // printf("mark up to: %d\n", file_no); if(mark_up_to_index(blist, file_no, dpth)) goto end; mark_not_got(blist->blk_from_champ_chooser, dpth); //printf("after mark_up: %d\n", // blist->blk_from_champ_chooser->index); break; default: iobuf_log_unexpected(chfd->rbuf, __func__); goto end; } ret=0; end: iobuf_free_content(chfd->rbuf); return ret; }
static enum asl_ret csr_server_func(struct asfd *asfd, struct conf **confs, void *param) { static const char **client; static struct iobuf *rbuf; const char *ca_conf=get_string(confs[OPT_CA_CONF]); client=(const char **)param; rbuf=asfd->rbuf; if(!strcmp(rbuf->buf, "csr")) { // Client wants to sign a certificate. logp("Client %s wants a certificate signed\n", *client); if(!ca_conf || !gca_dir) { logp("But server is not configured to sign client certificate requests.\n"); logp("See option 'ca_conf'.\n"); asfd->write_str(asfd, CMD_ERROR, "server not configured to sign client certificates"); return ASL_END_ERROR; } if(sign_client_cert(asfd, *client, confs)) return ASL_END_ERROR; return ASL_END_OK; } else if(!strcmp(rbuf->buf, "nocsr")) { // Client does not want to sign a certificate. // No problem, just carry on. logp("Client %s does not want a certificate signed\n", *client); if(asfd->write_str(asfd, CMD_GEN, "nocsr ok")) return ASL_END_ERROR; return ASL_END_OK; } else { iobuf_log_unexpected(rbuf, __func__); return ASL_END_ERROR; } }
int authorise_server(struct asfd *asfd, struct conf **globalcs, struct conf **cconfs) { int ret=-1; char *cp=NULL; char *password=NULL; char *cname=NULL; char whoareyou[256]=""; struct iobuf *rbuf=asfd->rbuf; const char *peer_version=NULL; if(asfd->read(asfd)) { logp("unable to read initial message\n"); goto end; } if(rbuf->cmd!=CMD_GEN || strncmp_w(rbuf->buf, "hello")) { iobuf_log_unexpected(rbuf, __func__); goto end; } // String may look like... // "hello" // "hello:(version)" // (version) is a version number if((cp=strchr(rbuf->buf, ':'))) { cp++; if(cp && set_string(cconfs[OPT_PEER_VERSION], cp)) goto end; } iobuf_free_content(rbuf); snprintf(whoareyou, sizeof(whoareyou), "whoareyou"); peer_version=get_string(cconfs[OPT_PEER_VERSION]); if(peer_version) { long min_ver=0; long cli_ver=0; if((min_ver=version_to_long("1.3.2"))<0 || (cli_ver=version_to_long(peer_version))<0) return -1; // Stick the server version on the end of the whoareyou string. // if the client version is recent enough. if(min_ver<=cli_ver) snprintf(whoareyou, sizeof(whoareyou), "whoareyou:%s", VERSION); } if(asfd->write_str(asfd, CMD_GEN, whoareyou) || asfd->read(asfd)) { logp("unable to get client name\n"); goto end; } if(!(cname=strdup_w(rbuf->buf, __func__))) goto end; if(!get_int(globalcs[OPT_CNAME_FQDN])) strip_fqdn(&cname); if(get_int(globalcs[OPT_CNAME_LOWERCASE])) strlwr(cname); if(set_string(cconfs[OPT_CNAME], cname)) goto end; iobuf_free_content(rbuf); if(asfd->write_str(asfd, CMD_GEN, "okpassword") || asfd->read(asfd)) { logp("unable to get password for client %s\n", get_string(cconfs[OPT_CNAME])); goto end; } password=rbuf->buf; iobuf_init(rbuf); if(check_client_and_password(globalcs, password, cconfs)) goto end; if(get_int(cconfs[OPT_VERSION_WARN])) version_warn(asfd, globalcs, cconfs); logp("auth ok for: %s%s\n", get_string(cconfs[OPT_CNAME]), get_int(cconfs[OPT_PASSWORD_CHECK])? "":" (no password needed)"); if(asfd->write_str(asfd, CMD_GEN, "ok")) goto end; ret=0; end: iobuf_free_content(rbuf); free_w(&password); free_w(&cname); return ret; }
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; }
static int deal_with_read(struct iobuf *rbuf, struct slist *slist, struct cntr *cntr, uint8_t *end_flags, struct dpth *dpth) { int ret=0; switch(rbuf->cmd) { /* Incoming block data. */ case CMD_DATA: if(add_data_to_store(cntr, slist, rbuf, dpth)) goto error; goto end; /* Incoming block signatures. */ case CMD_ATTRIBS_SIGS: static struct iobuf attr; static uint64_t index; iobuf_init(&attr); iobuf_move(&attr, rbuf); index=decode_file_no(&attr); // Need to go through slist to find the matching // entry. if(set_up_for_sig_info(slist, &attr, index)) goto error; return 0; case CMD_SIG: if(add_to_sig_list(slist, rbuf)) goto error; goto end; /* Incoming control/message stuff. */ case CMD_MESSAGE: case CMD_WARNING: { struct cntr *cntr=NULL; log_recvd(rbuf, cntr, 0); goto end; } case CMD_GEN: if(!strcmp(rbuf->buf, "sigs_end")) { (*end_flags)|=END_SIGS; goto end; } else if(!strcmp(rbuf->buf, "backup_end")) { (*end_flags)|=END_BACKUP; goto end; } break; case CMD_INTERRUPT: { uint64_t file_no; file_no=base64_to_uint64(rbuf->buf); if(slist_del_sbuf_by_index(slist, file_no)) goto error; goto end; } default: break; } iobuf_log_unexpected(rbuf, __func__); error: ret=-1; end: iobuf_free_content(rbuf); return ret; }
/* * If the stream has no more data available, read some from F into * BUF, and let the stream use that. On return, SEEN_EOF is true if * the end of file has passed into the stream. */ rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf, void *opaque) { int len=0; rs_filebuf_t *fb=(rs_filebuf_t *) opaque; struct cntr *cntr; int fd=fb->fd; cntr=fb->cntr; //logp("rs_infilebuf_fill\n"); /* This is only allowed if either the buf has no input buffer * yet, or that buffer could possibly be BUF. */ if(buf->next_in) { //logp("infilebuf avail_in %d buf_len %d\n", // buf->avail_in, fb->buf_len); if(buf->avail_in > fb->buf_len) { logp("buf->avail_in > fb->buf_len (%d > %d) in %s\n", buf->avail_in, fb->buf_len, __func__); return RS_IO_ERROR; } if(buf->next_in < fb->buf) { logp("buf->next_in < fb->buf in %s\n", __func__); return RS_IO_ERROR; } if(buf->next_in > fb->buf + fb->buf_len) { logp("buf->next_in > fb->buf + fb->buf_len in %s\n", __func__); return RS_IO_ERROR; } } else { if(buf->avail_in) { logp("buf->avail_in is %d in %s\n", buf->avail_in, __func__); return RS_IO_ERROR; } } if(buf->eof_in) return RS_DONE; if(buf->avail_in) /* Still some data remaining. Perhaps we should read anyhow? */ return RS_DONE; if(fd>=0) { static struct iobuf *rbuf=NULL; rbuf=fb->asfd->rbuf; if(fb->asfd->read(fb->asfd)) return RS_IO_ERROR; if(rbuf->cmd==CMD_APPEND) { //logp("got '%c' in fd infilebuf: %d\n", // CMD_APPEND, rbuf->len); memcpy(fb->buf, rbuf->buf, rbuf->len); len=rbuf->len; iobuf_free_content(rbuf); } else if(rbuf->cmd==CMD_END_FILE) { iobuf_free_content(rbuf); //logp("got %c in fd infilebuf\n", CMD_END_FILE); buf->eof_in=1; return RS_DONE; } else if(rbuf->cmd==CMD_WARNING) { logp("WARNING: %s\n", rbuf->buf); cntr_add(cntr, rbuf->cmd, 0); iobuf_free_content(rbuf); return RS_DONE; } else { iobuf_log_unexpected(rbuf, __func__); iobuf_free_content(rbuf); return RS_IO_ERROR; } } else if(fb->bfd) { if(fb->do_known_byte_count) { if(fb->data_len>0) { len=fb->bfd->read(fb->bfd, fb->buf, min(fb->buf_len, fb->data_len)); fb->data_len-=len; } else { // We have already read as much data as the VSS // header told us to, so set len=0 in order to // finish up. len=0; } } else len=fb->bfd->read(fb->bfd, fb->buf, fb->buf_len); if(len==0) { //logp("bread: eof\n"); buf->eof_in=1; return RS_DONE; } else if(len<0) { logp("rs_infilebuf_fill: error in bread\n"); return RS_IO_ERROR; } //logp("bread: ok: %d\n", len); fb->bytes+=len; if(!MD5_Update(&(fb->md5), fb->buf, len)) { logp("rs_infilebuf_fill: MD5_Update() failed\n"); return RS_IO_ERROR; } } else if(fb->fzp) { if((len=fzp_read(fb->fzp, fb->buf, fb->buf_len))<=0) { // This will happen if file size is a multiple of // input block len. if(fzp_eof(fb->fzp)) { buf->eof_in=1; return RS_DONE; } else { logp("rs_infilebuf_fill: got return %d when trying to read\n", len); return RS_IO_ERROR; } } fb->bytes+=len; if(!MD5_Update(&(fb->md5), fb->buf, len)) { logp("rs_infilebuf_fill: MD5_Update() failed\n"); return RS_IO_ERROR; } } buf->avail_in = len; buf->next_in = fb->buf; return RS_DONE; }
static int unexpected(struct iobuf *rbuf, const char *func) { iobuf_log_unexpected(rbuf, func); iobuf_free_content(rbuf); return -1; }
int authorise_client(struct asfd *asfd, char **server_version, const char *cname, const char *password, struct cntr *cntr) { int ret=-1; char hello[256]=""; struct iobuf *rbuf=asfd->rbuf; snprintf(hello, sizeof(hello), "hello:%s", VERSION); if(asfd->write_str(asfd, CMD_GEN, hello)) { logp("problem with auth\n"); goto end; } if(asfd->read(asfd) || rbuf->cmd!=CMD_GEN || strncmp_w(rbuf->buf, "whoareyou")) { logp("problem with auth\n"); goto end; } if(rbuf->buf) { char *cp=NULL; if((cp=strchr(rbuf->buf, ':'))) { cp++; if(cp && !(*server_version=strdup_w(cp, __func__))) goto end; } iobuf_free_content(rbuf); } if(asfd->write_str(asfd, CMD_GEN, cname) || asfd_read_expect(asfd, CMD_GEN, "okpassword") || asfd->write_str(asfd, CMD_GEN, password) || asfd->read(asfd)) { logp("problem with auth\n"); goto end; } if(rbuf->cmd==CMD_WARNING) // special case for the version warning { //logw(conf->p1cntr, rbuf->buf); logp("WARNING: %s\n", rbuf->buf); cntr_add(cntr, rbuf->cmd, 0); iobuf_free_content(rbuf); if(asfd->read(asfd)) { logp("problem with auth\n"); goto end; } } if(rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "ok")) { // It is OK. logp("auth ok\n"); } else { iobuf_log_unexpected(rbuf, __func__); goto end; } ret=0; end: iobuf_free_content(rbuf); return ret; }
static int extra_comms_read(struct async *as, struct vers *vers, int *srestore, char **incexc, struct conf **globalcs, struct conf **cconfs) { int ret=-1; struct asfd *asfd; struct iobuf *rbuf; asfd=as->asfd; rbuf=asfd->rbuf; while(1) { iobuf_free_content(rbuf); if(asfd->read(asfd)) goto end; if(rbuf->cmd!=CMD_GEN) { iobuf_log_unexpected(rbuf, __func__); goto end; } if(!strcmp(rbuf->buf, "extra_comms_end")) { if(asfd->write_str(asfd, CMD_GEN, "extra_comms_end ok")) goto end; break; } else if(!strncmp_w(rbuf->buf, "autoupgrade:")) { char *os=NULL; const char *autoupgrade_dir= get_string(globalcs[OPT_AUTOUPGRADE_DIR]); os=rbuf->buf+strlen("autoupgrade:"); iobuf_free_content(rbuf); if(os && *os && autoupgrade_server(as, vers->ser, vers->cli, os, get_cntr(globalcs), autoupgrade_dir)) goto end; } else if(!strcmp(rbuf->buf, "srestore ok")) { iobuf_free_content(rbuf); // Client can accept the restore. // Load the restore config, then send it. *srestore=1; if(conf_parse_incexcs_path(cconfs, get_string(cconfs[OPT_RESTORE_PATH])) || incexc_send_server_restore(asfd, cconfs)) goto end; // Do not unlink it here - wait until // the client says that it wants to do the // restore. // Also need to leave it around if the // restore is to an alternative client, so // that the code below that reloads the config // can read it again. //unlink(get_string(cconfs[OPT_RESTORE_PATH])); } else if(!strcmp(rbuf->buf, "srestore not ok")) { const char *restore_path=get_string( cconfs[OPT_RESTORE_PATH]); // Client will not accept the restore. unlink(restore_path); if(set_string(cconfs[OPT_RESTORE_PATH], NULL)) goto end; logp("Client not accepting server initiated restore.\n"); } else if(!strcmp(rbuf->buf, "sincexc ok")) { // Client can accept incexc conf from the // server. iobuf_free_content(rbuf); if(incexc_send_server(asfd, cconfs)) goto end; } else if(!strcmp(rbuf->buf, "incexc")) { // Client is telling server its incexc // configuration so that it can better decide // what to do on resume. iobuf_free_content(rbuf); if(incexc_recv_server(asfd, incexc, globalcs)) goto end; if(*incexc) { char *tmp=NULL; char comp[32]=""; snprintf(comp, sizeof(comp), "compression = %d\n", get_int(cconfs[OPT_COMPRESSION])); if(!(tmp=prepend(*incexc, comp))) goto end; free_w(incexc); *incexc=tmp; } } else if(!strcmp(rbuf->buf, "countersok")) { // Client can accept counters on // resume/verify/restore. logp("Client supports being sent counters.\n"); set_int(cconfs[OPT_SEND_CLIENT_CNTR], 1); } else if(!strncmp_w(rbuf->buf, "uname=") && strlen(rbuf->buf)>strlen("uname=")) { char *uname=rbuf->buf+strlen("uname="); if(!strncasecmp("Windows", uname, strlen("Windows"))) set_int(cconfs[OPT_CLIENT_IS_WINDOWS], 1); } else if(!strncmp_w(rbuf->buf, "orig_client=") && strlen(rbuf->buf)>strlen("orig_client=")) { if(conf_switch_to_orig_client(globalcs, cconfs, rbuf->buf+strlen("orig_client="))) goto end; // If this started out as a server-initiated // restore, need to load the restore file // again. if(*srestore) { if(conf_parse_incexcs_path(cconfs, get_string(cconfs[OPT_RESTORE_PATH]))) goto end; } if(asfd->write_str(asfd, CMD_GEN, "orig_client ok")) goto end; } else if(!strncmp_w(rbuf->buf, "restore_spool=")) { // Client supports temporary spool directory // for restores. if(set_string(cconfs[OPT_RESTORE_SPOOL], rbuf->buf+strlen("restore_spool="))) goto end; } else if(!strncmp_w(rbuf->buf, "protocol=")) { char msg[128]=""; // Client wants to set protocol. enum protocol protocol=get_protocol(cconfs); if(protocol!=PROTO_AUTO) { snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s but server is set to protocol=%d\n", rbuf->buf, protocol); log_and_send_oom(asfd, __func__); goto end; } else if(!strcmp(rbuf->buf+strlen("protocol="), "1")) { set_protocol(cconfs, PROTO_1); set_protocol(globalcs, PROTO_1); } else if(!strcmp(rbuf->buf+strlen("protocol="), "2")) { set_protocol(cconfs, PROTO_2); set_protocol(globalcs, PROTO_2); } else { snprintf(msg, sizeof(msg), "Client is trying to use protocol=%s, which is unknown\n", rbuf->buf); log_and_send_oom(asfd, __func__); goto end; } logp("Client has set protocol=%d\n", (int)get_protocol(cconfs)); } else if(!strncmp_w(rbuf->buf, "rshash=blake2")) { #ifdef RS_DEFAULT_STRONG_LEN logp("Client is trying to use librsync hash blake2, but server does not support it.\n"); goto end; #else set_e_rshash(cconfs[OPT_RSHASH], RSHASH_BLAKE2); set_e_rshash(globalcs[OPT_RSHASH], RSHASH_BLAKE2); #endif } else if(!strncmp_w(rbuf->buf, "msg")) { set_int(cconfs[OPT_MESSAGE], 1); set_int(globalcs[OPT_MESSAGE], 1); } else { iobuf_log_unexpected(rbuf, __func__); goto end; } } ret=0; end: iobuf_free_content(rbuf); return ret; }
static int deal_with_read(struct iobuf *rbuf, struct slist *slist, struct cntr *cntr, uint8_t *end_flags) { int ret=0; switch(rbuf->cmd) { /* Incoming file request. */ case CMD_FILE: case CMD_METADATA: if(add_to_file_requests(slist, rbuf)) goto error; return 0; /* Incoming data block request. */ case CMD_DATA_REQ: if(add_to_data_requests(slist->blist, rbuf)) goto error; goto end; /* Incoming control/message stuff. */ case CMD_WRAP_UP: { int64_t wrap_up; struct blk *blk; struct blist *blist=slist->blist; from_base64(&wrap_up, rbuf->buf); for(blk=blist->head; blk; blk=blk->next) { if(blk->index==(uint64_t)wrap_up) { blist->last_requested=blk; blist->last_sent=blk; break; } } if(!blk) { logp("Could not find wrap up index: %016" PRIX64 "\n", wrap_up); // goto error; } goto end; } case CMD_MESSAGE: case CMD_WARNING: { log_recvd(rbuf, cntr, 0); goto end; } case CMD_GEN: if(!strcmp(rbuf->buf, "requests_end")) { (*end_flags)|=END_REQUESTS; goto end; } else if(!strcmp(rbuf->buf, "blk_requests_end")) { (*end_flags)|=END_BLK_REQUESTS; goto end; } else if(!strcmp(rbuf->buf, "backup_end")) { (*end_flags)|=END_BACKUP; goto end; } break; default: break; } iobuf_log_unexpected(rbuf, __func__); error: ret=-1; end: iobuf_free_content(rbuf); return ret; }
static int unknown_command(struct asfd *asfd) { iobuf_log_unexpected(asfd->rbuf, __func__); asfd->write_str(asfd, CMD_ERROR, "unknown command"); return -1; }
static int deal_with_read(struct iobuf *rbuf, struct slist *slist, struct blist *blist, struct conf *conf, int *sigs_end, int *backup_end, struct dpth *dpth) { int ret=0; static struct sbuf *inew=NULL; if(!inew && !(inew=sbuf_alloc(conf))) goto error; switch(rbuf->cmd) { /* Incoming block data. */ case CMD_DATA: if(add_data_to_store(conf, blist, rbuf, dpth)) goto error; goto end; /* Incoming block signatures. */ case CMD_ATTRIBS_SIGS: // New set of stuff incoming. Clean up. if(inew->attr.buf) free(inew->attr.buf); iobuf_copy(&inew->attr, rbuf); inew->burp2->index=decode_file_no(&inew->attr); rbuf->buf=NULL; // Need to go through slist to find the matching // entry. if(set_up_for_sig_info(slist, blist, inew)) goto error; return 0; case CMD_SIG: if(add_to_sig_list(slist, blist, rbuf, dpth, conf)) goto error; goto end; /* Incoming control/message stuff. */ case CMD_WARNING: logp("WARNING: %s\n", rbuf); cntr_add(conf->cntr, rbuf->cmd, 0); goto end; case CMD_GEN: if(!strcmp(rbuf->buf, "sigs_end")) { *sigs_end=1; goto end; } else if(!strcmp(rbuf->buf, "backup_end")) { *backup_end=1; goto end; } break; } iobuf_log_unexpected(rbuf, __func__); error: ret=-1; sbuf_free(&inew); end: if(rbuf->buf) { free(rbuf->buf); rbuf->buf=NULL; } return ret; }
int authorise_server(struct asfd *asfd, struct conf *conf, struct conf *cconf) { int ret=-1; char *cp=NULL; char *password=NULL; char whoareyou[256]=""; struct iobuf *rbuf=asfd->rbuf; if(asfd->read(asfd)) { logp("unable to read initial message\n"); goto end; } if(rbuf->cmd!=CMD_GEN || strncmp_w(rbuf->buf, "hello")) { iobuf_log_unexpected(rbuf, __func__); goto end; } // String may look like... // "hello" // "hello:(version)" // (version) is a version number if((cp=strchr(rbuf->buf, ':'))) { cp++; if(cp && !(cconf->peer_version=strdup_w(cp, __func__))) goto end; } iobuf_free_content(rbuf); snprintf(whoareyou, sizeof(whoareyou), "whoareyou"); if(cconf->peer_version) { long min_ver=0; long cli_ver=0; if((min_ver=version_to_long("1.3.2"))<0 || (cli_ver=version_to_long(cconf->peer_version))<0) return -1; // Stick the server version on the end of the whoareyou string. // if the client version is recent enough. if(min_ver<=cli_ver) snprintf(whoareyou, sizeof(whoareyou), "whoareyou:%s", VERSION); } asfd->write_str(asfd, CMD_GEN, whoareyou); if(asfd->read(asfd)) { logp("unable to get client name\n"); goto end; } cconf->cname=rbuf->buf; iobuf_init(rbuf); asfd->write_str(asfd, CMD_GEN, "okpassword"); if(asfd->read(asfd)) { logp("unable to get password for client %s\n", cconf->cname); goto end; } password=rbuf->buf; iobuf_init(rbuf); if(check_client_and_password(conf, password, cconf)) goto end; if(cconf->version_warn) version_warn(asfd, conf, cconf); logp("auth ok for: %s%s\n", cconf->cname, cconf->password_check?"":" (no password needed)"); asfd->write_str(asfd, CMD_GEN, "ok"); ret=0; end: iobuf_free_content(rbuf); free_w(&password); return ret; }