/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2016 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **************************************************************************/ #include "action_header.h" #include "../../Interface/File.h" #include "../../urbackupcommon/os_functions.h" #include "../../urbackupcommon/file_metadata.h" #include "../../urbackupcommon/mbrdata.h" #include "../../Interface/SettingsReader.h" #include "../../cryptoplugin/ICryptoFactory.h" #include "../../fsimageplugin/IFSImageFactory.h" #include "../../fsimageplugin/IVHDFile.h" #include "../server_settings.h" #include "backups.h" #include #include #include #include "../../fileservplugin/IFileServ.h" #include "../server_status.h" #include "../restore_client.h" #include "../dao/ServerBackupDao.h" #include "../server_dir_links.h" #include "../ImageMount.h" #include "../server.h" extern ICryptoFactory *crypto_fak; extern IFileServ* fileserv; extern IFSImageFactory *image_fak; namespace backupaccess { std::string constructFilter(const std::vector &clientid, std::string key) { std::string clientf="("; for(size_t i=0;i &backup_tokens, const std::vector &tokens, bool skip_hashes); namespace { bool sendFile(Helper& helper, const std::string& filename) { THREAD_ID tid = Server->getThreadID(); Server->setContentType(tid, "application/octet-stream"); Server->addHeader(tid, "Content-Disposition: attachment; filename=\""+(ExtractFileName(filename))+"\""); IFile *in=Server->openFile(os_file_prefix(filename), MODE_READ); if(in!=NULL) { helper.releaseAll(); Server->addHeader(tid, "Content-Length: "+convert(in->Size()) ); char buf[4096]; _u32 r; do { r=in->Read(buf, 4096); Server->WriteRaw(tid, buf, r, false); } while(r>0); Server->destroy(in); return true; } else { Server->Log("Error opening file \""+filename+"\"", LL_ERROR); return false; } } bool sendZip(Helper& helper, std::string folderbase, std::string foldername, std::string hashfolderbase, std::string hashfoldername, const std::string& filter, bool token_authentication, const std::vector& backup_tokens, const std::vector& tokens, bool skip_hashes) { std::string zipname=ExtractFileName(foldername)+".zip"; THREAD_ID tid = Server->getThreadID(); Server->setContentType(tid, "application/octet-stream"); Server->addHeader(tid, "Content-Disposition: attachment; filename=\""+(zipname)+"\""); helper.releaseAll(); if(!foldername.empty()) { if(foldername[foldername.size()-1]==os_file_sep()[0]) { foldername.resize(foldername.size()-1); } } if(!hashfoldername.empty()) { if(hashfoldername[hashfoldername.size()-1]==os_file_sep()[0]) { hashfoldername.resize(hashfoldername.size()-1); } } return create_zip_to_output(folderbase, foldername, hashfolderbase, hashfoldername, filter, token_authentication, backup_tokens, tokens, skip_hashes); } std::vector getMetadata(std::string dir, const std::vector& files, bool skip_special) { std::vector ret; ret.resize(files.size()); if(dir.empty() || dir[dir.size()-1]!=os_file_sep()[0]) { dir+=os_file_sep(); } for(size_t i=0;iLog("Error reading metadata of file "+dir+os_file_sep()+ file.name, LL_ERROR); } } return ret; } FileMetadata getMetaData(std::string path, bool is_file) { if(path.empty() || (!is_file && path[path.size()-1]!=os_file_sep()[0]) ) { path+=os_file_sep(); } std::string metadata_fn; if(is_file) { metadata_fn = ExtractFilePath(path) + os_file_sep() + escape_metadata_fn(ExtractFileName(path)); } else { metadata_fn = ExtractFilePath(path) + os_file_sep() + escape_metadata_fn(ExtractFileName(path))+os_file_sep()+metadata_dir_fn; } FileMetadata ret; if(!read_metadata(metadata_fn, ret) ) { Server->Log("Error reading metadata of path "+path, LL_ERROR); } return ret; } int getClientid(IDatabase* db, const std::string& clientname) { IQuery* q=db->Prepare("SELECT id FROM clients WHERE name=?"); q->Bind(clientname); db_results res=q->Read(); q->Reset(); if(!res.empty()) { return watoi(res[0]["id"]); } return -1; } std::string getClientname(IDatabase* db, int clientid) { IQuery *q=db->Prepare("SELECT name FROM clients WHERE id=?"); q->Bind(clientid); db_results res=q->Read(); q->Reset(); if(!res.empty()) { return res[0]["name"]; } else { return std::string(); } } bool checkBackupTokens(const std::string& fileaccesstokens, const std::string& backupfolder, const std::string& clientname, const std::string& path) { std::vector tokens; Tokenize(fileaccesstokens, tokens, ";"); backupaccess::STokens backup_tokens = backupaccess::readTokens(backupfolder, clientname, path); if(backup_tokens.tokens.empty()) { return false; } for(size_t i=0;i tokens; Tokenize(fileaccesstokens, tokens, ";"); backupaccess::STokens backup_tokens = backupaccess::readTokens(backupfolder, clientname, path); if(backup_tokens.tokens.empty()) { return false; } FileMetadata metadata; if(!read_metadata(filemetadatapath, metadata)) { return false; } return checkFileToken(backup_tokens.tokens, tokens, metadata); } } //unnamed namespace namespace backupaccess { std::string getBackupFolder(IDatabase* db) { IQuery* q=db->Prepare("SELECT value FROM settings_db.settings WHERE key='backupfolder'"); db_results res_bf=q->Read(); q->Reset(); if(!res_bf.empty() ) { return res_bf[0]["value"]; } else { return std::string(); } } std::string decryptTokens(IDatabase* db, const str_map& CURRP) { if(crypto_fak==NULL) { return std::string(); } int clientid; str_map::const_iterator iter_clientname =CURRP.find("clientname"); if(iter_clientname!=CURRP.end()) { clientid = getClientid(db, iter_clientname->second); } else { str_map::const_iterator iter_clientid = CURRP.find("clientid"); if(iter_clientid!=CURRP.end()) { clientid = watoi(iter_clientid->second); } else { return std::string(); } } if(clientid==-1) { return std::string(); } ServerSettings server_settings(db, clientid); std::string client_key = server_settings.getSettings()->client_access_key; size_t i=0; str_map::const_iterator iter; do { iter = CURRP.find("tokens"+convert(i)); if(iter!=CURRP.end()) { std::string bin_input = base64_decode_dash(iter->second); std::string session_key = crypto_fak->decryptAuthenticatedAES(bin_input, client_key, 1); if(!session_key.empty()) { iter = CURRP.find("token_data"); if(iter==CURRP.end()) { return std::string(); } bin_input = base64_decode_dash(iter->second); std::string decry = crypto_fak->decryptAuthenticatedAES(bin_input, session_key, 1); if(!decry.empty()) { std::string tokenhash = Server->GenerateBinaryMD5(bin_input); ServerBackupDao backupdao(db); if(backupdao.hasUsedAccessToken(tokenhash).exists) { return std::string(); } else { backupdao.addUsedAccessToken(clientid, tokenhash); } } return decry; } } ++i; } while (iter!=CURRP.end()); return std::string(); } STokens readTokens(const std::string& backupfolder, const std::string& clientname, const std::string& path) { if(backupfolder.empty() || clientname.empty() || path.empty()) { return STokens(); } std::auto_ptr backup_tokens(Server->createFileSettingsReader(backupfolder+os_file_sep()+clientname+os_file_sep()+path+os_file_sep()+".hashes"+os_file_sep()+".urbackup_tokens.properties")); if(!backup_tokens.get()) { return STokens(); } std::string ids_str = backup_tokens->getValue("ids", ""); std::vector ids; Tokenize(ids_str, ids, ","); std::vector ret; for(size_t i=0;igetValue(ids[i]+"."+"accountname", "")), backup_tokens->getValue(ids[i]+"."+"token", "") }; ret.push_back(token); } STokens tokens = { backup_tokens->getValue("access_key", ""), ret }; return tokens; } bool checkFileToken( const std::vector &backup_tokens, const std::vector &tokens, const FileMetadata &metadata ) { bool has_permission=false; for(size_t i=0;igetThreadID(), NULL, NULL); IQuery *q=db->Prepare("SELECT id, strftime('"+helper.getTimeFormatString()+"', backuptime) AS t_backuptime, incremental, size_bytes, archived, archive_timeout, path FROM backups WHERE complete=1 AND done=1 AND clientid=? ORDER BY backuptime DESC"); q->Bind(t_clientid); db_results res=q->Read(); JSON::Array backups; has_access = false; if (res.empty()) { has_access = true; } for(size_t i=0;igetTimeSeconds(); } } if(archived!=0) { obj.set("archive_timeout", archive_timeout); } backups.add(obj); } return backups; } bool valid_path_component(const std::string& t_path) { return !t_path.empty() && t_path != " " && t_path != "." && t_path != ".." && t_path.find("/") == std::string::npos && t_path.find("\\") == std::string::npos; } SPathInfo get_metadata_path_with_tokens(const std::string& u_path, std::string* fileaccesstokens, std::string clientname, std::string backupfolder, int* backupid, std::string backuppath) { SPathInfo ret; std::vector tokens; if(fileaccesstokens) { ret.backup_tokens = readTokens(backupfolder, clientname, backuppath); Tokenize(*fileaccesstokens, tokens, ";"); } std::vector t_path; Tokenize(u_path, t_path, "/"); ret.can_access_path=true; for(size_t i=0;i t_path; Tokenize(u_path, t_path, "/"); std::string rel_path; for (size_t i = 0; i < t_path.size(); ++i) { if (valid_path_component(t_path[i])) { rel_path += os_file_sep() + t_path[i]; } } std::string content_path = backuppath + rel_path; int ftype = os_get_file_type(os_file_prefix(content_path)); SPathInfo ret; ret.can_access_path = ftype!=0; ret.full_path = content_path; ret.is_file = (ftype & EFileType_File) > 0; ret.is_symlink = (ftype & EFileType_Symlink) > 0; ret.rel_path = !rel_path.empty() ? rel_path.substr(1) : rel_path; return ret; } std::string get_backup_path(IDatabase* db, int backupid, int t_clientid) { IQuery* q=db->Prepare("SELECT path FROM backups WHERE id=? AND clientid=?"); q->Bind(backupid); q->Bind(t_clientid); db_results res=q->Read(); q->Reset(); if(!res.empty()) { return res[0]["path"]; } else { return std::string(); } } bool get_files_with_tokens(IDatabase* db, int* backupid, int t_clientid, std::string clientname, std::string* fileaccesstokens, const std::string& u_path, int backupid_offset, JSON::Object& ret) { Helper helper(Server->getThreadID(), NULL, NULL); db_results res; if(backupid) { IQuery* q=db->Prepare("SELECT path,strftime('"+helper.getTimeFormatString()+"', backuptime) AS backuptime FROM backups WHERE id=? AND clientid=?"); q->Bind(*backupid); q->Bind(t_clientid); res=q->Read(); q->Reset(); if(!res.empty()) { ret.set("backuptime", watoi64(res[0]["backuptime"])); ret.set("backupid", *backupid + backupid_offset); } else { return false; } } else { IQuery* q=db->Prepare("SELECT id, path,strftime('"+helper.getTimeFormatString()+"', backuptime) AS backuptime FROM backups WHERE clientid=? ORDER BY backuptime DESC"); q->Bind(t_clientid); res=q->Read(); q->Reset(); } std::string backupfolder=getBackupFolder(db); if(backupfolder.empty()) { return false; } bool can_restore = false; bool restore_server_confirms; if (ServerStatus::canRestore(clientname, restore_server_confirms) ) { can_restore = true; if (fileaccesstokens) { ServerSettings clientsettings(db, t_clientid); if (!clientsettings.getSettings()->allow_file_restore) { can_restore = false; } } } std::string path; std::vector t_path; Tokenize(u_path, t_path, "/"); bool is_file=false; bool has_access=false; JSON::Array ret_files; for(size_t k=0;k tokens; if(fileaccesstokens) { Tokenize(*fileaccesstokens, tokens, ";"); } ret.set("clientname", clientname); ret.set("clientid", t_clientid); ret.set("path", u_path); if(can_restore) { ret.set("can_restore", true); if(restore_server_confirms) { ret.set("server_confirms_restore", true); } } if(backupid) { std::string full_path = path_info.full_path; std::string full_metadata_path = path_info.full_metadata_path; std::string fn_filter; if(is_file) { fn_filter = ExtractFileName(path_info.full_path, os_file_sep()); if(!fn_filter.empty()) { full_path = ExtractFilePath(path_info.full_path, os_file_sep()); full_metadata_path = ExtractFilePath(path_info.full_metadata_path, os_file_sep()); } } std::vector tfiles=getFiles(os_file_prefix(full_path), NULL); std::vector tmetadata=getMetadata(full_metadata_path, tfiles, path.empty()); JSON::Array files; for(size_t i=0;i(tmetadata[i].shahash.c_str()), static_cast(tmetadata[i].shahash.size()))); } files.add(obj); } } ret.set("files", files); } else { std::auto_ptr f; if(path_info.is_file) { f.reset(Server->openFile(os_file_prefix(path_info.full_path), MODE_READ)); } if( (path_info.is_file && f.get()) || os_directory_exists(os_file_prefix(path_info.full_path)) ) { FileMetadata metadata = getMetaData(path_info.full_metadata_path, path_info.is_file); JSON::Object obj; obj.set("name", ExtractFileName(path_info.full_path)); if(path_info.is_file) { obj.set("size", f->Size()); obj.set("dir", false); } else { obj.set("dir", true); } obj.set("mod", metadata.last_modified); obj.set("creat", metadata.created); obj.set("access", metadata.accessed); obj.set("backupid", watoi(res[k]["id"])+backupid_offset); obj.set("backuptime", watoi64(res[k]["backuptime"])); if(!metadata.shahash.empty()) { obj.set("shahash", base64_encode(reinterpret_cast(metadata.shahash.c_str()), static_cast(metadata.shahash.size()))); } ret_files.add(obj); } } } } if(!backupid) { ret.set("single_item", true); ret.set("is_file", is_file); ret.set("files", ret_files); } return has_access; } JSON::Array get_backup_images(IDatabase * db, int t_clientid, std::string clientname, int backupid_offset) { std::string backupfolder = getBackupFolder(db); Helper helper(Server->getThreadID(), NULL, NULL); IQuery *q = db->Prepare("SELECT id, strftime('" + helper.getTimeFormatString() + "', backuptime) AS t_backuptime, incremental, size_bytes, archived, archive_timeout, path, letter FROM backup_images WHERE complete=1 AND clientid=? ORDER BY backuptime DESC"); q->Bind(t_clientid); db_results res = q->Read(); JSON::Array backups; for (size_t i = 0; igetTimeSeconds(); } } if (archived != 0) { obj.set("archive_timeout", archive_timeout); } backups.add(obj); } return backups; } JSON::Object get_image_info(IDatabase* db, int backupid, int t_clientid, int backupid_offset, std::string& path) { Helper helper(Server->getThreadID(), NULL, NULL); IQuery *q = db->Prepare("SELECT id, strftime('" + helper.getTimeFormatString() + "', backuptime) AS t_backuptime, incremental, " "size_bytes, archived, archive_timeout, path, letter FROM backup_images WHERE complete=1 AND clientid=? AND id=?"); q->Bind(t_clientid); q->Bind(backupid); db_results res = q->Read(); JSON::Object ret; if (!res.empty()) { path = res[0]["path"]; ret.set("id", watoi(res[0]["id"]) + backupid_offset); ret.set("backuptime", watoi64(res[0]["t_backuptime"])); ret.set("incremental", watoi(res[0]["incremental"])); ret.set("size_bytes", watoi64(res[0]["size_bytes"])); ret.set("letter", res[0]["letter"]); int archived = watoi(res[0]["archived"]); ret.set("archived", watoi(res[0]["archived"])); _i64 archive_timeout = 0; if (!res[0]["archive_timeout"].empty()) { archive_timeout = watoi64(res[0]["archive_timeout"]); if (archive_timeout != 0) { archive_timeout -= Server->getTimeSeconds(); } } if (archived != 0) { ret.set("archive_timeout", archive_timeout); } std::string path = res[0]["path"]; std::string filename = ExtractFileName(path); std::string extension = findextension(filename); if (extension == "vhd" || extension == "vhdz") { std::auto_ptr vhdfile(image_fak->createVHDFile(path, true, 0)); if (vhdfile.get() != NULL) { ret.set("volume_size", vhdfile->getSize()); } } else if (extension == "raw") { std::auto_ptr rawfile(Server->openFile(os_file_prefix(path), MODE_READ)); if (rawfile.get() != NULL) { ret.set("volume_size", rawfile->Size()); } } else { assert(false); } std::auto_ptr mbrfile(Server->openFile(os_file_prefix(path + ".mbr"), MODE_READ)); if (mbrfile.get() && mbrfile->Size()<10*1024*1024) { std::string mbrdata = mbrfile->Read(static_cast<_u32>(mbrfile->Size())); if (mbrdata.size() == mbrfile->Size()) { CRData mbrdata_view(mbrdata.data(), mbrdata.size()); SMBRData mbr(mbrdata_view); if (!mbr.hasError()) { ret.set("part_table", mbr.gpt_style ? "GPT" : "MBR"); ret.set("disk_number", mbr.device_number); ret.set("partition_number", mbr.partition_number); ret.set("volume_name", mbr.volume_name); ret.set("fs_type", mbr.fsn); ret.set("serial_number", mbr.serial_number); } } } } return ret; } bool get_image_files(IDatabase* db, int backupid, int t_clientid, std::string clientname, const std::string& u_path, int backupid_offset, bool do_mount, JSON::Object& ret) { std::string path; JSON::Object image_backup_info = get_image_info(db, backupid, t_clientid, backupid_offset, path); ret.set("image_backup_info", image_backup_info); ret.set("single_item", false); if (!path.empty()) { ScopedMountedImage mounted_image; std::string content_path = ImageMount::get_mount_path(backupid, !u_path.empty() && u_path!="/", mounted_image); if (content_path.empty() || !os_directory_exists(content_path) ) { if (!do_mount) { if (BackupServer::canMountImages()) { ret.set("can_mount", true); #ifndef __linux__ ret.set("os_mount", true); #endif } else { ret.set("no_files", true); } content_path.clear(); } else { content_path = ImageMount::get_mount_path(backupid, true, mounted_image); if (content_path.empty()) { ret.set("mount_failed", true); } } } JSON::Array files; if (!content_path.empty()) { std::vector t_path; Tokenize(u_path, t_path, "/"); for (size_t i = 0; i < t_path.size(); ++i) { if (valid_path_component(t_path[i])) { content_path += os_file_sep() + t_path[i]; } } std::vector tfiles = getFiles(os_file_prefix(content_path), NULL); for (size_t i = 0; iid==SESSION_ID_TOKEN_AUTH) && has_tokens) { token_authentication=true; fileaccesstokens = backupaccess::decryptTokens(helper.getDatabase(), CURRP); if(fileaccesstokens.empty()) { JSON::Object err_ret; err_ret.set("err", "access_denied"); err_ret.set("errcode", "token_decryption_failed"); helper.Write(err_ret.stringify(false)); return; } else { std::string ses=helper.generateSession("anonymous"); ret.set("session", ses); CURRP["ses"]=ses; helper.update(tid, &CURRP, &PARAMS); if(helper.getSession()) { helper.getSession()->mStr["fileaccesstokens"]=fileaccesstokens; helper.getSession()->id = SESSION_ID_TOKEN_AUTH; } } } else if(session!=NULL && session->id==SESSION_ID_TOKEN_AUTH) { fileaccesstokens = session->mStr["fileaccesstokens"]; if(!fileaccesstokens.empty()) { token_authentication=true; } else { JSON::Object err_ret; err_ret.set("err", "access_denied"); err_ret.set("errcode", "token_not_in_session"); helper.Write(err_ret.stringify(false)); return; } } if(token_authentication) { ret.set("token_authentication", true); } std::string sa=CURRP["sa"]; std::string rights=helper.getRights("browse_backups"); std::string archive_rights=helper.getRights("manual_archive"); std::vector clientid; if(rights!="tokens") { clientid = helper.getRightIDs(rights); } std::vector clientid_archive=helper.getRightIDs(archive_rights); if(clientid.size()==1 && sa.empty() ) { sa="backups"; CURRP["clientid"]=convert(clientid[0]); } if( (session!=NULL && rights!="none" ) || token_authentication) { IDatabase *db=helper.getDatabase(); if(sa.empty()) { std::string qstr = "SELECT id, name, strftime('"+helper.getTimeFormatString()+"', lastbackup) AS lastbackup FROM clients"; if(token_authentication) { if(CURRP.find("clientname")==CURRP.end()) { std::vector tokens; Tokenize(fileaccesstokens, tokens, ";"); IQuery* q_clients = db->Prepare("SELECT clientid FROM tokens_on_client WHERE token=?"); for(size_t i=0;iBind(tokens[i]); db_results res = q_clients->Read(); q_clients->Reset(); if(!res.empty()) { int n_clientid = watoi(res[0]["clientid"]); if(std::find(clientid.begin(), clientid.end(), n_clientid)== clientid.end()) { clientid.push_back(n_clientid); } } } if(!clientid.empty()) { qstr+=" WHERE "+backupaccess::constructFilter(clientid, "id"); } else { sa="backups"; } } else { sa="backups"; } } else { if(!clientid.empty()) { qstr+=" WHERE "+backupaccess::constructFilter(clientid, "id"); } } qstr+=" ORDER BY name"; if(sa!="backups") { IQuery *q=db->Prepare(qstr); db_results res=q->Read(); q->Reset(); JSON::Array clients; for(size_t i=0;iPrepare("UPDATE "+tbl+" SET archived=1, archive_timeout=0 WHERE id=?"); q->Bind(archive_id); q->Write(); } else if(CURRP.find("unarchive")!=CURRP.end()) { int unarchive_id = watoi(CURRP["unarchive"]); if (unarchive_id < 0) { tbl = "backup_images"; unarchive_id *= -1; } IQuery *q=db->Prepare("UPDATE "+tbl+" SET archived=0 WHERE id=?"); q->Bind(unarchive_id); q->Write(); } } bool has_access; JSON::Array backups = backupaccess::get_backups_with_tokens(db, t_clientid, clientname, token_authentication ? &fileaccesstokens : NULL, 0, has_access); if (!has_access) { JSON::Object err_ret; err_ret.set("err", "access_denied"); err_ret.set("errcode", "backups_access_denied"); helper.Write(err_ret.stringify(false)); return; } ret.set("backups", backups); if (r_ok) { ret.set("backup_images", backupaccess::get_backup_images(db, t_clientid, clientname, 0)); } ret.set("can_archive", archive_ok); ret.set("clientname", clientname); ret.set("clientid", t_clientid); } else { ret.set("error", 2); } } else if(sa=="files" || sa=="filesdl" || sa=="zipdl" || sa=="clientdl" ) { int t_clientid; std::string clientname; if (token_authentication && CURRP.find("backupid") != CURRP.end() && watoi(CURRP["backupid"]) < 0) { ret.set("error", "2"); helper.Write(ret.stringify(false)); return; } if(token_authentication && CURRP.find("clientid")==CURRP.end()) { clientname=CURRP["clientname"]; t_clientid = getClientid(helper.getDatabase(), clientname); if(t_clientid==-1) { ret.set("error", "2"); helper.Write(ret.stringify(false)); return; } } else { t_clientid = watoi(CURRP["clientid"]); clientname = getClientname(helper.getDatabase(), t_clientid); } bool r_ok = token_authentication ? true : helper.hasRights(t_clientid, rights, clientid); if(r_ok) { bool has_backupid=CURRP.find("backupid")!=CURRP.end(); int backupid=0; if(has_backupid) { backupid=watoi(CURRP["backupid"]); } std::string u_path=UnescapeHTML(UnescapeSQLString(CURRP["path"])); if (backupid < 0 && token_authentication) { clientname.clear(); } if(!clientname.empty() ) { if( (sa=="filesdl" || sa=="zipdl" || sa=="clientdl") && has_backupid) { std::string backupfolder = backupaccess::getBackupFolder(db); if (backupfolder.empty()) { return; } std::string backuppath; backupaccess::SPathInfo path_info; ScopedMountedImage mounted_image; if (backupid >= 0) { backuppath = backupaccess::get_backup_path(db, backupid, t_clientid); path_info = backupaccess::get_metadata_path_with_tokens(u_path, token_authentication ? &fileaccesstokens : NULL, clientname, backupfolder, has_backupid ? &backupid : NULL, backuppath); } else { backuppath = ImageMount::get_mount_path(-1*backupid, true, mounted_image); path_info = backupaccess::get_image_path_info(u_path, clientname, backupfolder, backupid, backuppath); } if(token_authentication && !path_info.can_access_path) { JSON::Object err_ret; err_ret.set("err", "access_denied"); err_ret.set("errcode", "path_dl_access_denied"); helper.Write(err_ret.stringify(false)); return; } std::vector tokens; if(token_authentication) { Tokenize(fileaccesstokens, tokens, ";"); } if(sa=="filesdl") { if(!token_authentication || checkFileToken(fileaccesstokens, backupfolder, clientname, backuppath, path_info.full_metadata_path)) { sendFile(helper, path_info.full_path); } return; } else if(sa=="zipdl") { std::string bpath = backupfolder + os_file_sep() + clientname + os_file_sep() + backuppath; sendZip(helper, bpath, path_info.full_path, backupid<0 ? "" : bpath + os_file_sep()+".hashes", path_info.full_metadata_path, CURRP["filter"], token_authentication, path_info.backup_tokens.tokens, tokens, backupid<0 ? false : path_info.rel_path.empty()); return; } else if(sa=="clientdl" && fileserv!=NULL) { if(ServerStatus::getStatus(clientname).comm_pipe==NULL) { ret.set("err", "client_not_online"); helper.Write(ret.stringify(false)); return; } int64 restore_id; size_t status_id; logid_t log_id; THREADPOOL_TICKET ticket; if(!create_clientdl_thread(clientname, t_clientid, t_clientid, path_info.full_path, path_info.full_metadata_path, CURRP["filter"], path_info.rel_path.empty(), path_info.rel_path, restore_id, status_id, log_id, std::string(), std::vector< std::pair >(), true, true, greplace(os_file_sep(), "/", path_info.rel_path), 0, true, ticket)) { ret.set("err", "internal_error"); helper.Write(ret.stringify(false)); return; } if (session != NULL) { std::string wait_key = ServerSettings::generateRandomAuthKey(); session->mStr[wait_key] = convert(ticket); ret.set("wait_key", wait_key); } ret.set("ok", "true"); helper.Write(ret.stringify(false)); return; } } else { if (has_backupid && backupid < 0) { if (!backupaccess::get_image_files(db, -1 * backupid, t_clientid, clientname, u_path, 0, CURRP["mount"]=="1", ret)) { JSON::Object err_ret; err_ret.set("err", "internal_error"); helper.Write(err_ret.stringify(false)); return; } } else { if (!backupaccess::get_files_with_tokens(db, has_backupid ? &backupid : NULL, t_clientid, clientname, token_authentication ? &fileaccesstokens : NULL, u_path, 0, ret)) { JSON::Object err_ret; err_ret.set("err", "access_denied"); err_ret.set("errcode", "path_browse_access_denied"); helper.Write(err_ret.stringify(false)); return; } } ret.set("clientname", clientname); ret.set("clientid", t_clientid); ret.set("path", u_path); } } } } } else { ret.set("error", 1); } helper.Write(ret.stringify(false)); }