Ticket #12668: keyfile-envvars.patch

File keyfile-envvars.patch, 4.1 KB (added by Jeffrey Walton, 3 years ago)

The attached patch may help with key file envvars. I was not able to test it because I cannot get SVN trunk to configure on Ubuntu 20.04 LTS, x86_64, fully patched.

  • src/interface/fzputtygen_interface.cpp

     
    99
    1010#include <wx/filedlg.h>
    1111
     12// mbsrtowcs, mbsrtowcs_s and getenv
     13#include <stdlib.h>
     14#include <wchar.h>
     15#include <stdexcept>
     16
     17// Unnamed namespace for scoping
     18namesapce {
     19
     20    // Safe conversion from char* to string
     21    inline std::string to_string(const char* str) {
     22        return str ? std::string(str) : std::string("");
     23    }
     24
     25    // Safe conversion from wchar_t* to wstring
     26    inline std::wstring to_string(const wchar_t* str) {
     27        return str ? std::wstring(str) : std::wstring("");
     28    }
     29
     30    // mbsrtowcs_s should be used on MS platforms when _MSC_VER >= 1400.
     31    inline std::wstring mbstring_to_wstring(const std::string& str) {
     32        const char* cs = str.c_str();
     33        size_t size = 0;
     34
     35#if _MSC_VER >= 1400
     36        size_t len = str.length()+1;
     37        errno_t err;
     38        err = mbsrtowcs_s(&size, NULL, 0, cs, len);
     39
     40        if (err != 0) {
     41            throw std::runtime_error("mbsrtowcs_s failed");
     42        }
     43
     44        std::vector<wchar_t> buf(size);
     45        err = mbsrtowcs_s(&size, &buf[0], buf.size(), cs, len);
     46
     47        if (err != 0) {
     48            throw std::runtime_error("mbsrtowcs_s failed");
     49        }
     50#else
     51        size = mbsrtowcs(NULL, &cs, 0, NULL);
     52
     53        if (size == size_t(-1)) {
     54            throw std::runtime_error("mbsrtowcs failed");
     55        }
     56
     57        std::vector<wchar_t> buf(size + 1);
     58        size = mbsrtowcs(&buf[0], &cs, buf.size(), NULL);
     59
     60        if (size == size_t(-1)) {
     61            throw std::runtime_error("mbsrtowcs failed");
     62        }
     63#endif
     64
     65        // Trim trailing NULL character, if present
     66        std::wstring res(&buf[0], buf.size());
     67        if (! res.empty() && *(res.end()-1) == '\0')
     68            res.erase(res.end()-1);
     69       
     70        return res;
     71    }
     72
     73    // str is source string, t is target string, r is replacement string
     74    inline void maybe_replace(std::wstring& str, const std::wtring& t, const wstring& r) {
     75        std::wstring::size_type pos = 0;
     76        if ((pos = str.find(t)) != std::wstring::npos) {
     77            str.replace(pos, t.length(), r);
     78        }
     79    }
     80}
     81
    1282CFZPuttyGenInterface::CFZPuttyGenInterface(wxWindow* parent)
    1383    : m_parent(parent)
    1484{
     
    62132    return reply == _T("1") ? 1 : 0;
    63133}
    64134
     135// Should wxExpandEnvVars be used here? Something like:
     136//     std::wstring t = wxExpandEnvVars(keyFile);
     137//     std::swap(t, keyFile);
     138bool CFZPuttyGenInterface::ExpandEnvVars(std::wstring& keyFile)
     139{
     140    // See if we can early out
     141    if (keyFile.find(_T("$")) == std::wstring::npos)
     142        return true;
     143
     144    std::wstring s(keyFile);
     145
     146    try {
     147        std::wstring t, v;
     148
     149        // For the next 4 replacements
     150        v = std::wstring(mbstring_to_wstring(to_string(getenv("HOME"))));
     151        if (! v.empty()) {
     152            // Not an envar, but a Bashism
     153            t = _T("~/");
     154            if (s.substr(0,2) == t) {
     155                s.replace(0, t.length(), v);
     156            }
     157
     158            t = _T("${HOME}");
     159            maybe_replace(s, t, v);
     160
     161            t = _T("$(HOME)");
     162            maybe_replace(s, t, v);
     163
     164            t = _T("$HOME");
     165            maybe_replace(s, t, v);
     166        }
     167    }
     168    catch(std::excpetion& ) {
     169        return false;
     170    }
     171   
     172    std::swap(s, keyFile);
     173    return true;
     174}
     175
    65176bool CFZPuttyGenInterface::LoadKeyFile(std::wstring& keyFile, bool silent, std::wstring& comment, std::wstring& data)
    66177{
    67178    if (!LoadProcess(silent)) {
     
    69180        return false;
    70181    }
    71182
     183    // Allow failure. A failure means keyFile is unchanged, which is the behavior of the previous code.
     184    (void)ExpandEnvVars(keyFile);
     185
    72186    int needs_conversion = NeedsConversion(keyFile, silent);
    73187    if (needs_conversion < 0) {
    74188        comment = fztranslate("Could not load key file");
  • src/interface/fzputtygen_interface.h

     
    1010public:
    1111    CFZPuttyGenInterface(wxWindow* parent);
    1212    virtual ~CFZPuttyGenInterface();
     13    // Expand some envars in a key file name, like $HOME/.ssh/id_ed25519
     14    bool ExpandEnvVars(std::wstring& str);
    1315    bool LoadKeyFile(std::wstring& keyFile, bool silent, std::wstring& comment, std::wstring& data);
    1416
    1517    bool ProcessFailed() const;