Line data Source code
1 : /*! 2 : * \file esys/repo/libssh2/ssh_libssh2.cpp 3 : * \brief 4 : * 5 : * \cond 6 : * __legal_b__ 7 : * 8 : * Copyright (c) 2021-2022 Michel Gillet 9 : * Distributed under the MIT License. 10 : * (See accompanying file LICENSE.txt or 11 : * copy at https://opensource.org/licenses/MIT) 12 : * 13 : * __legal_e__ 14 : * \endcond 15 : * 16 : */ 17 : 18 : #include "esys/repo/esysrepo_prec.h" 19 : #include "esys/repo/libssh2/ssh.h" 20 : #include "esys/repo/libssh2/sshimpl.h" 21 : 22 : #include <boost/filesystem.hpp> 23 : 24 : #include <fstream> 25 : #include <sstream> 26 : #include <cstdlib> 27 : 28 : namespace esys::repo::libssh2 29 : { 30 : 31 : std::string SSH::s_dflt_agent_identity_path; 32 : 33 1 : void SSH::set_dflt_agent_identity_path(const std::string &agent_identity_path) 34 : { 35 1 : s_dflt_agent_identity_path = agent_identity_path; 36 1 : } 37 : 38 331 : const std::string &SSH::get_dflt_agent_identity_path() 39 : { 40 331 : return s_dflt_agent_identity_path; 41 : } 42 : 43 203 : SSH::SSH() 44 203 : : SSHBase() 45 : { 46 203 : m_impl = std::make_unique<SSHImpl>(this); 47 203 : } 48 : 49 203 : SSH::~SSH() = default; 50 : 51 193 : bool SSH::is_agent_present() 52 : { 53 193 : check_for_custom_agent(); 54 : 55 193 : if (_get_agent_present() == AgentPresent::NOT_CHECKED) 56 : { 57 139 : bool present = m_impl->is_agent_present(); 58 139 : if (present) 59 139 : _set_agent_present(AgentPresent::PRESENT); 60 : else 61 0 : _set_agent_present(AgentPresent::NOT_PRESENT); 62 : } 63 193 : return (_get_agent_present() == AgentPresent::PRESENT); 64 : } 65 : 66 193 : void SSH::check_for_custom_agent(bool force_check) 67 : { 68 193 : static int s_run_count = 0; 69 : 70 193 : if (s_run_count > 0) return; 71 : 72 1 : ++s_run_count; 73 : 74 1 : bool do_check = true; 75 : #ifndef ESYSREPO_SNAP_BUILD 76 1 : do_check = false; 77 : #endif 78 : 79 1 : if (do_check) debug(0, "Snap detected"); 80 : 81 1 : char *ssh_auth_sock_c = getenv("SSH_AUTH_SOCK"); 82 1 : std::string ssh_auth_sock = ssh_auth_sock_c ? ssh_auth_sock_c : ""; 83 : 84 1 : if (ssh_auth_sock.size() != 0) 85 : { 86 1 : std::ostringstream oss; 87 : 88 1 : oss << "SSH_AUTH_SOCK = '" << ssh_auth_sock << "'"; 89 1 : debug(0, oss.str()); 90 1 : } 91 : else 92 : { 93 0 : debug(0, "SSH_AUTH_SOCK is not set"); 94 0 : return; 95 : } 96 : 97 1 : if (!do_check && !force_check) 98 : { 99 1 : std::ostringstream oss; 100 : 101 1 : oss << "Set set_agent_identity_path to '" << ssh_auth_sock << "'"; 102 1 : debug(0, oss.str()); 103 1 : set_agent_identity_path(ssh_auth_sock.c_str()); 104 1 : return; 105 1 : } 106 : 107 0 : char *home_c = std::getenv("HOME"); 108 0 : char *snap_real_home_c = std::getenv("SNAP_REAL_HOME"); 109 : 110 0 : boost::filesystem::path home = home_c; 111 0 : boost::filesystem::path snap_real_home = snap_real_home_c; 112 : 113 0 : std::ostringstream oss; 114 : 115 0 : oss << "SNAP_REAL_HOME = '" << snap_real_home << "'"; 116 0 : debug(0, oss.str()); 117 : 118 0 : if (ssh_auth_sock.find(snap_real_home.string()) == 0) 119 : { 120 0 : debug(0, "Nothing to do."); 121 0 : return; 122 : } 123 : 124 : // SSH_AUTH_SOCK points to a file that can be accessed by a snap application 125 0 : boost::filesystem::path esysrepo_dir = snap_real_home; 126 0 : boost::filesystem::path new_ssh_auth_sock; 127 0 : esysrepo_dir /= "_esysrepo"; 128 0 : new_ssh_auth_sock = esysrepo_dir / ssh_auth_sock; 129 : 130 0 : if (boost::filesystem::exists(new_ssh_auth_sock)) 131 : { 132 0 : std::ostringstream oss; 133 : 134 0 : oss << "Set set_agent_identity_path to '" << new_ssh_auth_sock.string() << "'"; 135 0 : debug(0, oss.str()); 136 : 137 0 : set_agent_identity_path(new_ssh_auth_sock.string()); 138 0 : return; 139 0 : } 140 : 141 0 : oss.str(""); 142 : 143 0 : oss << "This application was installed from a snap package." << std::endl; 144 0 : oss << "So it can't access the /tmp folder. When using an ssh agent or" << std::endl; 145 0 : oss << "using agent forwarding, required files are written to the /tmp." << std::endl; 146 0 : oss << "Currently, the only way around this is to mount the /tmp folder" << std::endl; 147 0 : oss << "in your home folder." << std::endl; 148 0 : oss << std::endl; 149 0 : oss << "To mount the /tmp folder:" << std::endl; 150 : 151 0 : boost::filesystem::path path = esysrepo_dir / "tmp"; 152 0 : boost::filesystem::path tmp_path = path; 153 : 154 0 : if (!boost::filesystem::exists(path)) 155 : { 156 0 : boost::filesystem::create_directories(path); 157 : } 158 : 159 0 : path = snap_real_home / "bin"; 160 0 : if (!boost::filesystem::exists(path)) 161 : { 162 0 : boost::filesystem::create_directories(path); 163 : } 164 : 165 0 : path /= "esysrepo_mount_tmp.sh"; 166 : 167 0 : oss << "sudo " << path.string() << std::endl; 168 : 169 0 : std::ofstream ofs(path.string().c_str(), std::ios_base::out | std::ios_base::trunc); 170 : 171 0 : ofs << "#!/usr/bin/env sh" << std::endl; 172 0 : ofs << std::endl; 173 0 : ofs << "# This file was generated by esysrepo, so don't modify it." << std::endl; 174 0 : ofs << std::endl; 175 0 : ofs << "sudo mount --bind /tmp " << tmp_path.string() << std::endl; 176 0 : ofs.close(); 177 : 178 0 : boost::filesystem::permissions(path, boost::filesystem::owner_exe | boost::filesystem::owner_read 179 : | boost::filesystem::owner_write); 180 0 : warn(oss.str()); 181 194 : } 182 : 183 1 : void SSH::set_agent_identity_path(const std::string &agent_identity_path) 184 : { 185 1 : SSHBase::set_agent_identity_path(agent_identity_path); 186 : 187 1 : if (get_dflt_agent_identity_path().empty()) set_dflt_agent_identity_path(agent_identity_path); 188 1 : } 189 : 190 278 : const std::string &SSH::get_agent_identity_path() const 191 : { 192 278 : if (!SSHBase::get_agent_identity_path().empty()) return SSHBase::get_agent_identity_path(); 193 : 194 138 : m_agent_identity_path = get_dflt_agent_identity_path(); 195 : 196 138 : return m_agent_identity_path; 197 : } 198 : 199 : } // namespace esys::repo::libssh2