static int do_backup_server(struct async *as, struct sdirs *sdirs, struct conf **cconfs, const char *incexc, int resume) { int ret=0; int do_phase2=1; struct asfd *asfd=as->asfd; enum protocol protocol=get_protocol(cconfs); struct cntr *cntr=get_cntr(cconfs); logp("in do_backup_server\n"); log_rshash(cconfs); if(resume) { if(sdirs_get_real_working_from_symlink(sdirs) || sdirs_get_real_manifest(sdirs, protocol) || open_log(asfd, sdirs, cconfs)) goto error; } else { // Not resuming - need to set everything up fresh. if(sdirs_create_real_working(sdirs, get_string(cconfs[OPT_TIMESTAMP_FORMAT])) || sdirs_get_real_manifest(sdirs, protocol) || open_log(asfd, sdirs, cconfs)) goto error; if(write_incexc(sdirs->rworking, incexc)) { logp("unable to write incexc\n"); goto error; } if(backup_phase1_server(as, sdirs, cconfs)) { logp("error in phase 1\n"); goto error; } } if(resume) { struct stat statp; if(lstat(sdirs->phase1data, &statp) && !lstat(sdirs->changed, &statp) && !lstat(sdirs->unchanged, &statp)) { // In this condition, it looks like there was an // interruption during phase3. Skip phase2. do_phase2=0; } } if(do_phase2) { if(backup_phase2_server(as, sdirs, incexc, resume, cconfs)) { logp("error in backup phase 2\n"); goto error; } asfd->write_str(asfd, CMD_GEN, "okbackupend"); } // Close the connection with the client, the rest of the job we can do // by ourselves. logp("Backup ending - disconnect from client.\n"); if(asfd_flush_asio(asfd)) goto end; as->asfd_remove(as, asfd); asfd_close(asfd); if(backup_phase3_server(sdirs, cconfs)) { logp("error in backup phase 3\n"); goto error; } if(do_rename(sdirs->working, sdirs->finishing)) goto error; if(backup_phase4_server(sdirs, cconfs)) { logp("error in backup phase 4\n"); goto error; } cntr_print(cntr, ACTION_BACKUP, asfd); cntr_stats_to_file(cntr, sdirs->rworking, ACTION_BACKUP); if(protocol==PROTO_2) { // Regenerate dindex before the symlink is renamed, so that the // champ chooser cleanup does not try to remove data files // whilst the dindex regeneration is happening. if(regenerate_client_dindex(sdirs)) goto error; } // Move the symlink to indicate that we are now in the end phase. The // rename() race condition is automatically recoverable here. if(do_rename(sdirs->finishing, sdirs->current)) goto error; logp("Backup completed.\n"); log_fzp_set(NULL, cconfs); compress_filename(sdirs->rworking, "log", "log.gz", get_int(cconfs[OPT_COMPRESSION])); goto end; error: ret=-1; end: log_fzp_set(NULL, cconfs); 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 *cfd, SSL_CTX *ctx, struct sockaddr_storage *addr, int status_wfd, int status_rfd, const char *conffile, int forking) { int ret=-1; int ca_ret=0; SSL *ssl=NULL; BIO *sbio=NULL; struct conf **confs=NULL; struct conf **cconfs=NULL; struct cntr *cntr=NULL; struct async *as=NULL; const char *cname=NULL; struct asfd *asfd=NULL; int is_status_server=0; if(!(confs=confs_alloc()) || !(cconfs=confs_alloc())) goto end; set_peer_env_vars(addr); // Reload global config, in case things have changed. This means that // the server does not need to be restarted for most conf changes. confs_init(confs); confs_init(cconfs); if(conf_load_global_only(conffile, confs)) goto end; // Hack to keep forking turned off if it was specified as off on the // command line. if(!forking) set_int(confs[OPT_FORK], 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_do_accept(ssl)) goto end; if(!(as=async_alloc()) || as->init(as, 0) || !(asfd=setup_asfd_ssl(as, "main socket", cfd, ssl))) goto end; asfd->set_timeout(asfd, get_int(confs[OPT_NETWORK_TIMEOUT])); asfd->ratelimit=get_float(confs[OPT_RATELIMIT]); if(authorise_server(as->asfd, confs, cconfs) || !(cname=get_string(cconfs[OPT_CNAME])) || !*cname) { // Add an annoying delay in case they are tempted to // try repeatedly. log_and_send(as->asfd, "unable to authorise on server"); sleep(1); goto end; } if(!get_int(cconfs[OPT_ENABLED])) { log_and_send(as->asfd, "client not enabled on server"); sleep(1); goto end; } // Set up counters. Have to wait until here to get cname. if(!(cntr=cntr_alloc()) || cntr_init(cntr, cname)) goto end; set_cntr(confs[OPT_CNTR], cntr); set_cntr(cconfs[OPT_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(as->asfd, confs, cconfs))<0) { logp("Error signing client certificate request for %s\n", 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", cname); ret=0; goto end; } /* Now it is time to check the certificate. */ if(ssl_check_cert(ssl, confs, cconfs)) { log_and_send(as->asfd, "check cert failed on server"); goto end; } if(status_rfd>=0) { is_status_server=1; if(!setup_asfd(as, "status server parent socket", &status_rfd)) goto end; } ret=child(as, is_status_server, status_wfd, confs, cconfs); end: *cfd=-1; if(as && asfd_flush_asio(as->asfd)) ret=-1; async_asfd_free_all(&as); // This closes cfd for us. logp("exit child\n"); if(cntr) cntr_free(&cntr); if(confs) { set_cntr(confs[OPT_CNTR], NULL); confs_free(&confs); } if(cconfs) { set_cntr(cconfs[OPT_CNTR], NULL); confs_free(&cconfs); } return ret; }
int autoupgrade_client(struct async *as, struct conf **confs) { int a=0; int ret=-1; char *cp=NULL; char *copy=NULL; char *script_path=NULL; char script_name[32]=""; char package_name[32]=""; char write_str[256]=""; const char *args[2]; struct iobuf *rbuf=NULL; struct asfd *asfd; char *autoupgrade_dir=get_string(confs[OPT_AUTOUPGRADE_DIR]); const char *autoupgrade_os=get_string(confs[OPT_AUTOUPGRADE_OS]); struct cntr *cntr=get_cntr(confs); asfd=as->asfd; if(!autoupgrade_dir) { logp("autoupgrade_dir not set!\n"); goto end; } if(!autoupgrade_os) { logp("autoupgrade_os not set!\n"); goto end; } if(!(copy=strdup_w(autoupgrade_dir, __func__))) goto end; strip_trailing_slashes(©); if((cp=strchr(copy, '/'))) *cp='\0'; if(mkpath(&autoupgrade_dir, copy)) goto end; // Let the server know we are ready. snprintf(write_str, sizeof(write_str), "autoupgrade:%s", autoupgrade_os); if(asfd->write_str(asfd, CMD_GEN, write_str)) goto end; if(!(a=asfd->simple_loop(asfd, confs, NULL, __func__, autoupgrade_func))) { ret=0; // No autoupgrade. goto end; } else if(a<0) // Error. #ifdef HAVE_WIN32 win32_enable_backup_privileges(); snprintf(script_name, sizeof(script_name), "script.bat"); snprintf(package_name, sizeof(package_name), "package.exe"); #else snprintf(script_name, sizeof(script_name), "script"); snprintf(package_name, sizeof(package_name), "package"); #endif if(receive_file(asfd, autoupgrade_dir, script_name, cntr)) { logp("Problem receiving %s/%s\n", autoupgrade_dir, script_name); goto end; } if(receive_file(asfd, autoupgrade_dir, package_name, cntr)) { logp("Problem receiving %s/%s\n", autoupgrade_dir, package_name); goto end; } if(!(script_path=prepend_s(autoupgrade_dir, script_name))) goto end; chmod(script_path, 0755); /* Run the script here. */ a=0; args[a++]=script_path; args[a++]=NULL; run_script(asfd, args, NULL, confs, 0 /* do not wait */, 1 /* use logp */, 1 /* log_remote */); /* To get round Windows problems to do with installing over files that the current process is running from, I am forking the child, then immediately exiting the parent process. */ printf("\n"); logp("The server tried to upgrade your client.\n"); logp("You will need to try your command again.\n"); asfd_flush_asio(asfd); asfd_free(&as->asfd); exit(0); end: free_w(©); free_w(&script_path); iobuf_free(&rbuf); return ret; }