/************************************************************************* * 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 #include "../../cryptoplugin/ICryptoFactory.h" #include "../server_settings.h" extern ICryptoFactory *crypto_fak; extern std::string server_token; namespace { bool verify_signature(const std::string& exe_extension, const std::string& basename) { if(crypto_fak==NULL) return false; #ifdef _WIN32 std::string pubkey_fn="urbackup_ecdsa409k1.pub"; #else std::string pubkey_fn="urbackup/urbackup_ecdsa409k1.pub"; #endif std::string p_pubkey_fn = Server->getServerParameter("urbackup_public_key"); if(!p_pubkey_fn.empty()) { pubkey_fn = p_pubkey_fn; } return crypto_fak->verifyFile(pubkey_fn, "urbackup/"+basename+"."+ exe_extension, "urbackup/"+ basename+".sig2"); } std::string constructClientSettings(Helper& helper, int clientid, const std::string& clientname, const std::string& authkey, const std::string& access_keys) { ServerSettings settings(helper.getDatabase(), clientid); SSettings *settingsptr=settings.getSettings(); std::string ret="\r\n"; ret+="internet_mode_enabled="+convert(settingsptr->internet_mode_enabled)+"\r\n"; ret+="internet_server="+settingsptr->internet_server+"\r\n"; ret+="internet_server_port="+convert(settingsptr->internet_server_port)+"\r\n"; ret+="internet_authkey="+(authkey.empty() ? settingsptr->internet_authkey : authkey ) +"\r\n"; if(!clientname.empty()) { ret+="computername="+clientname+"\r\n"; } if (!access_keys.empty()) { ret += "access_keys=" + access_keys + "\r\n"; } return ret; } bool replaceToken(const std::string end_token, const std::string& repl, std::string& data, size_t& offset) { for(size_t i=offset;irepl.size()) { data.replace(data.begin()+offset, data.begin()+offset+repl.size(), repl.begin(), repl.end()); offset=i+end_token.size(); return true; } else { Server->Log("Cannot replace, because data is too large", LL_ERROR); return false; } } } return false; } bool replaceStrings(Helper& helper, const std::string& settings, std::string& data) { const std::string settings_start_token="#48692563-17e4-4ccb-a078-f14372fdbe20"; const std::string settings_end_token="#6e7f6ba0-8478-4946-b70a-f1c7e83d28cc"; const std::string ident_start_token="#17460620-769b-4add-85aa-a764efe84ab7"; const std::string ident_end_token="#569d42d2-1b40-4745-a426-e86a577c7f1a"; bool replaced_settings=false; bool replaced_ident=false; for(size_t i=0;iid==SESSION_ID_INVALID) return; bool all_client_rights; std::vector clientids = helper.clientRights(RIGHT_SETTINGS, all_client_rights); bool all_browse_backups; std::vector browse_backups_rights = helper.clientRights(RIGHT_BROWSE_BACKUPS, all_browse_backups); std::string authkey = GET["authkey"]; std::string errstr; if( !authkey.empty() || (session!=NULL && (all_client_rights || !clientids.empty()) ) ) { helper.releaseAll(); session = NULL; int clientid=watoi(GET["clientid"]); if(!authkey.empty() || all_client_rights || std::find(clientids.begin(), clientids.end(), clientid)!=clientids.end() ) { std::string os = GET["os"]; std::string exe_extension = "exe"; std::string basename = "UrBackupUpdate"; if (os == "osx" || os=="mac") { exe_extension = "sh"; basename = "UrBackupUpdateMac"; } else if (os == "linux") { exe_extension = "sh"; basename = "UrBackupUpdateLinux"; } Server->Log("Verifying "+ basename +"."+exe_extension+" signature...", LL_INFO); if(verify_signature(exe_extension, basename)) { IQuery *q=helper.getDatabase()->Prepare("SELECT name FROM clients WHERE id=?"); q->Bind(clientid); db_results res=q->Read(); q->Reset(); std::string clientname; if(!res.empty()) { clientname=(res[0]["name"]); } std::string access_keys; if ( all_client_rights || std::find(clientids.begin(), clientids.end(), clientid) != clientids.end() ) { if (all_browse_backups || std::find(browse_backups_rights.begin(), browse_backups_rights.end(), clientid) != browse_backups_rights.end() ) { if (os == "linux" || os == "osx" || os == "mac") { //There is only ~4KB available space. Add only root for now IQuery* q_root_token = helper.getDatabase()->Prepare("SELECT token FROM user_tokens WHERE username='root' AND tgroup IS NULL AND clientid = ? ORDER BY created DESC"); q_root_token->Bind(clientid); db_results res_root_token = q_root_token->Read(); q_root_token->Reset(); if (!res_root_token.empty()) { access_keys = "uroot:" + res_root_token[0]["token"]; } } ServerSettings settings(helper.getDatabase(), clientid); std::string client_access_key = settings.getSettings()->client_access_key; if (!client_access_key.empty()) { if (!access_keys.empty()) { access_keys += ";"; } access_keys += "t" + server_token + ":" + client_access_key; } } } std::string data=getFile("urbackup/"+basename+"."+ exe_extension); if( replaceStrings(helper, constructClientSettings(helper, clientid, clientname, authkey, access_keys), data) ) { Server->setContentType(tid, "application/octet-stream"); Server->addHeader(tid, "Content-Disposition: attachment; filename=\"UrBackup Client ("+clientname+")."+exe_extension+"\""); Server->addHeader(tid, "Content-Length: "+convert(data.size()) ); Server->WriteRaw(tid, data.c_str(), data.size(), false); } else { errstr="Replacing data in install file failed"; } } else { errstr="Signature verification failed"; } } else { errstr="No right to download client"; } } else { errstr="No right to download any client"; } if(!errstr.empty()) { Server->Log(errstr, LL_ERROR); helper.Write("ERROR: "+errstr, false); } }