static struct asfd *asfd_setup(const char *outputpath) { struct asfd *asfd; fail_unless((asfd=asfd_alloc())!=NULL); fail_unless((asfd->rbuf=iobuf_alloc())!=NULL); asfd->write=my_asfd_write; fail_unless(!build_path_w(outputpath)); fail_unless((output=fzp_open(outputpath, "wb"))!=NULL); json_set_pretty_print(1); return asfd; }
struct asfd *asfd_mock_setup(struct ioevent_list *user_reads, struct ioevent_list *user_writes) { struct asfd *asfd=NULL; fail_unless((asfd=asfd_alloc())!=NULL); fail_unless((asfd->rbuf=iobuf_alloc())!=NULL); asfd->read=mock_asfd_read; asfd->write=do_asfd_assert_write; asfd->write_str=mock_asfd_assert_write_str; asfd->append_all_to_write_buffer= mock_asfd_assert_append_all_to_write_buffer; asfd->parse_readbuf=mock_parse_readbuf; asfd->simple_loop=asfd_simple_loop; ioevent_list_init(user_reads); ioevent_list_init(user_writes); asfd->data1=(void *)user_reads; asfd->data2=(void *)user_writes; return asfd; };
struct asfd *champ_chooser_connect(struct async *as, struct sdirs *sdirs, struct conf *conf) { int champsock=-1; char *champname=NULL; struct asfd *chfd=NULL; // Connect to champ chooser now. // This may start up a new champ chooser. On a machine with multiple // cores, it may be faster to do now, way before it is actually needed // in phase2. if((champsock=connect_to_champ_chooser(sdirs, conf))<0) { logp("could not connect to champ chooser\n"); goto error; } if(!(chfd=asfd_alloc()) || chfd->init(chfd, "champ chooser socket", as, champsock, NULL /* no SSL */, ASFD_STREAM_STANDARD, conf)) goto error; as->asfd_add(as, chfd); if(!(champname=prepend("cname", conf->cname, strlen(conf->cname), ":"))) goto error; if(chfd->write_str(chfd, CMD_GEN, champname) || chfd->read_expect(chfd, CMD_GEN, "cname ok")) goto error; free(champname); return chfd; error: free(champname); as->asfd_remove(as, chfd); asfd_free(&chfd); close_fd(&champsock); return NULL; }
static enum cliret do_client(struct conf *conf, enum action action, int vss_restore, int json) { enum cliret ret=CLIENT_OK; int rfd=-1; int resume=0; SSL *ssl=NULL; SSL_CTX *ctx=NULL; struct cntr *cntr=NULL; char *incexc=NULL; long name_max=0; enum action act=action; struct async *as=NULL; struct asfd *asfd=NULL; // as->settimers(0, 100); logp("begin client\n"); if(!(cntr=cntr_alloc()) || cntr_init(cntr, conf->cname)) goto error; conf->cntr=cntr; if(act!=ACTION_ESTIMATE && ssl_setup(&rfd, &ssl, &ctx, conf)) goto error; if(!(as=async_alloc()) || !(asfd=asfd_alloc()) || as->init(as, act==ACTION_ESTIMATE) || asfd->init(asfd, as, rfd, ssl, conf)) goto end; as->add_asfd(as, asfd); // Set quality of service bits on backup packets. if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK) as->asfd->set_bulk_packets(as->asfd); if(act!=ACTION_ESTIMATE) { if((ret=initial_comms(as, &act, &incexc, &name_max, conf))) goto end; } rfd=-1; switch(act) { case ACTION_BACKUP: ret=backup_wrapper(asfd, act, "backupphase1", incexc, resume, name_max, conf); break; case ACTION_BACKUP_TIMED: ret=backup_wrapper(asfd, act, "backupphase1timed", incexc, resume, name_max, conf); break; case ACTION_TIMER_CHECK: ret=backup_wrapper(asfd, act, "backupphase1timedcheck", incexc, resume, name_max, conf); break; case ACTION_RESTORE: case ACTION_VERIFY: ret=restore_wrapper(asfd, act, vss_restore, conf); break; case ACTION_ESTIMATE: if(do_backup_client(asfd, conf, act, name_max, 0)) goto error; break; case ACTION_DELETE: if(do_delete_client(asfd, conf)) goto error; break; case ACTION_LIST: case ACTION_LONG_LIST: default: if(do_list_client(asfd, conf, act, json)) goto error; break; } goto end; error: ret=CLIENT_ERROR; end: close_fd(&rfd); async_free(&as); asfd_free(&asfd); if(ctx) ssl_destroy_ctx(ctx); if(incexc) free(incexc); conf->cntr=NULL; if(cntr) cntr_free(&cntr); //logp("end client\n"); return ret; }
static enum cliret do_client(struct conf **confs, enum action action, int vss_restore) { enum cliret ret=CLIENT_OK; int rfd=-1; SSL *ssl=NULL; SSL_CTX *ctx=NULL; struct cntr *cntr=NULL; char *incexc=NULL; enum action act=action; struct async *as=NULL; struct asfd *asfd=NULL; // as->settimers(0, 100); // logp("begin client\n"); // logp("action %d\n", action); // Status monitor forks a child process instead of connecting to // the server directly. if(action==ACTION_STATUS || action==ACTION_STATUS_SNAPSHOT) { #ifdef HAVE_WIN32 logp("Status mode not implemented on Windows.\n"); goto error; #endif if(status_client_ncurses_init(act) || status_client_ncurses(confs)) ret=CLIENT_ERROR; goto end; } if(!(cntr=cntr_alloc()) || cntr_init(cntr, get_string(confs[OPT_CNAME]))) goto error; set_cntr(confs[OPT_CNTR], cntr); if(act!=ACTION_ESTIMATE && ssl_setup(&rfd, &ssl, &ctx, action, confs)) goto could_not_connect; if(!(as=async_alloc()) || !(asfd=asfd_alloc()) || as->init(as, act==ACTION_ESTIMATE) || asfd->init(asfd, "main socket", as, rfd, ssl, ASFD_STREAM_STANDARD, confs)) goto end; as->asfd_add(as, asfd); // Set quality of service bits on backup packets. if(act==ACTION_BACKUP || act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK) as->asfd->set_bulk_packets(as->asfd); if(act!=ACTION_ESTIMATE) { if((ret=initial_comms(as, &act, &incexc, confs))) goto end; } rfd=-1; switch(act) { case ACTION_BACKUP: ret=backup_wrapper(asfd, act, "backupphase1", incexc, confs); break; case ACTION_BACKUP_TIMED: ret=backup_wrapper(asfd, act, "backupphase1timed", incexc, confs); break; case ACTION_TIMER_CHECK: ret=backup_wrapper(asfd, act, "backupphase1timedcheck", incexc, confs); break; case ACTION_RESTORE: case ACTION_VERIFY: ret=restore_wrapper(asfd, act, vss_restore, confs); break; case ACTION_ESTIMATE: if(do_backup_client(asfd, confs, act, 0)) goto error; break; case ACTION_DELETE: if(do_delete_client(asfd, confs)) goto error; break; case ACTION_MONITOR: if(do_monitor_client(asfd, confs)) goto error; break; case ACTION_DIFF: case ACTION_DIFF_LONG: /* if(!strcmp(get_string(confs[OPT_BACKUP2]), "n")) // Do a phase1 scan and diff that. ret=backup_wrapper(asfd, act, "backupphase1diff", incexc, confs); else */ // Diff two backups that already exist. // Fall through, the list code is all we need // for simple diffs on the client side. case ACTION_LIST: case ACTION_LIST_LONG: default: if(do_list_client(asfd, act, confs)) goto error; break; } if(asfd_flush_asio(asfd)) ret=CLIENT_ERROR; goto end; error: ret=CLIENT_ERROR; goto end; could_not_connect: ret=CLIENT_COULD_NOT_CONNECT; end: close_fd(&rfd); async_free(&as); asfd_free(&asfd); if(ctx) ssl_destroy_ctx(ctx); free_w(&incexc); set_cntr(confs[OPT_CNTR], NULL); cntr_free(&cntr); //logp("end client\n"); return ret; }
static int run_child(int *rfd, int *cfd, SSL_CTX *ctx, const char *conffile, int forking) { int ret=-1; int ca_ret=0; SSL *ssl=NULL; BIO *sbio=NULL; struct conf *conf=NULL; struct conf *cconf=NULL; struct cntr *cntr=NULL; struct async *as=NULL; struct asfd *asfd=NULL; if(!(conf=conf_alloc()) || !(cconf=conf_alloc())) goto end; if(forking) close_fd(rfd); // Reload global config, in case things have changed. This means that // the server does not need to be restarted for most conf changes. conf_init(conf); conf_init(cconf); if(conf_load(conffile, conf, 1)) goto end; // Hack to keep forking turned off if it was specified as off on the // command line. if(!forking) conf->forking=0; if(!(sbio=BIO_new_socket(*cfd, BIO_NOCLOSE)) || !(ssl=SSL_new(ctx))) { logp("There was a problem joining ssl to the socket\n"); goto end; } SSL_set_bio(ssl, sbio, sbio); /* Do not try to check peer certificate straight away. Clients can send a certificate signing request when they have no certificate. */ SSL_set_verify(ssl, SSL_VERIFY_PEER /* | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */, 0); if(SSL_accept(ssl)<=0) { char buf[256]=""; ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); logp("SSL_accept: %s\n", buf); goto end; } if(!(as=async_alloc()) || !(asfd=asfd_alloc()) || as->init(as, 0) || asfd->init(asfd, "main socket", as, *cfd, ssl, conf)) goto end; as->asfd_add(as, asfd); if(authorise_server(asfd, conf, cconf) || !cconf->cname || !*(cconf->cname)) { // Add an annoying delay in case they are tempted to // try repeatedly. log_and_send(asfd, "unable to authorise on server"); sleep(1); goto end; } // Set up counters. Have to wait until here to get cname. if(!(cntr=cntr_alloc()) || cntr_init(cntr, cconf->cname)) goto end; conf->cntr=cntr; cconf->cntr=cntr; /* At this point, the client might want to get a new certificate signed. Clients on 1.3.2 or newer can do this. */ if((ca_ret=ca_server_maybe_sign_client_cert(asfd, conf, cconf))<0) { logp("Error signing client certificate request for %s\n", cconf->cname); goto end; } else if(ca_ret>0) { // Certificate signed and sent back. // Everything is OK, but we will close this instance // so that the client can start again with a new // connection and its new certificates. logp("Signed and returned client certificate request for %s\n", cconf->cname); ret=0; goto end; } /* Now it is time to check the certificate. */ if(ssl_check_cert(ssl, cconf)) { log_and_send(asfd, "check cert failed on server"); goto end; } set_non_blocking(*cfd); ret=child(as, conf, cconf); end: *cfd=-1; async_free(&as); asfd_free(&asfd); // This closes cfd for us. logp("exit child\n"); if(cntr) cntr_free(&cntr); if(conf) conf_free(conf); if(cconf) conf_free(cconf); return ret; }