GateKeeper.cpp
author Volker Birk <vb@pep-project.org>
Wed, 22 Jun 2016 09:01:21 +0200
changeset 116 967ed8d930c1
parent 113 b1bcfae25d26
child 117 a0bb0649aae8
permissions -rw-r--r--
...
vb@88
     1
#include "stdafx.h"
vb@88
     2
vb@88
     3
#include "GateKeeper.h"
vb@110
     4
#include "pEpCOMServerAdapter.h"
vb@88
     5
vb@88
     6
using namespace std;
vb@88
     7
vb@96
     8
namespace pEp {
vb@96
     9
vb@96
    10
    const LPCTSTR GateKeeper::plugin_reg_path = _T("Software\\Microsoft\\Office\\Outlook\\Addins\\pEp");
vb@96
    11
    const LPCTSTR GateKeeper::plugin_reg_value_name = _T("LoadBehavior");
vb@96
    12
    const LPCTSTR GateKeeper::updater_reg_path = _T("Software\\pEp\\Updater";)
vb@96
    13
vb@96
    14
    const time_t GateKeeper::cycle = 7200;   // 7200 sec is 2 h
vb@96
    15
    const DWORD GateKeeper::waiting = 10000; // 10000 ms is 10 sec
vb@88
    16
vb@96
    17
    GateKeeper::GateKeeper(CpEpCOMServerAdapterModule * const self)
vb@116
    18
        : _self(self), now(time(NULL)), next(now + time_diff()), hkUpdater(NULL), internet(NULL), hAES(NULL), hRSA(NULL)
vb@96
    19
    {
vb@96
    20
        LONG lResult = RegOpenCurrentUser(KEY_READ, &cu);
vb@96
    21
        assert(lResult == ERROR_SUCCESS);
vb@96
    22
        if (lResult == ERROR_SUCCESS)
vb@96
    23
            cu_open = true;
vb@96
    24
        else
vb@96
    25
            cu_open = false;
vb@88
    26
vb@96
    27
        if (cu_open) {
vb@96
    28
            LONG lResult = RegOpenKeyEx(cu, updater_reg_path, 0, KEY_READ, &hkUpdater);
vb@96
    29
            assert(lResult == ERROR_SUCCESS);
vb@96
    30
            if (lResult != ERROR_SUCCESS)
vb@96
    31
                return;
vb@96
    32
        }
vb@96
    33
    }
vb@96
    34
    
vb@96
    35
    GateKeeper::~GateKeeper()
vb@96
    36
    {
vb@96
    37
        if (cu_open) {
vb@96
    38
            if (hkUpdater)
vb@96
    39
                RegCloseKey(hkUpdater);
vb@96
    40
            RegCloseKey(cu);
vb@96
    41
        }
vb@96
    42
    }
vb@88
    43
vb@96
    44
    time_t GateKeeper::time_diff()
vb@96
    45
    {
vb@96
    46
        try {
vb@96
    47
            static random_device rd;
vb@96
    48
            static mt19937 gen(rd());
vb@88
    49
vb@96
    50
            uniform_int_distribution<time_t> dist(0, cycle);
vb@96
    51
vb@96
    52
            return dist(gen);
vb@96
    53
        }
vb@96
    54
        catch (exception&) {
vb@96
    55
            assert(0);
vb@96
    56
            return 0;
vb@96
    57
        }
vb@88
    58
    }
vb@96
    59
vb@96
    60
    void GateKeeper::keep()
vb@96
    61
    {
vb@96
    62
        if (!cu_open)
vb@96
    63
            return;
vb@96
    64
vb@96
    65
        while (1) {
vb@96
    66
            keep_plugin();
vb@96
    67
vb@96
    68
            now = time(NULL);
vb@96
    69
            assert(now != -1);
vb@96
    70
vb@96
    71
            if (now > next) {
vb@96
    72
                next = now + GateKeeper::cycle;
vb@96
    73
                keep_updated();
vb@96
    74
            }
vb@96
    75
vb@96
    76
            Sleep(waiting);
vb@96
    77
        }
vb@88
    78
    }
vb@96
    79
vb@96
    80
    void GateKeeper::keep_plugin()
vb@96
    81
    {
vb@110
    82
        while (!_self->m_bComInitialized)
vb@110
    83
            Sleep(1);
vb@110
    84
vb@116
    85
        MessageBox(NULL, _T("test"), _T("keep_plugin"), MB_ICONINFORMATION | MB_TOPMOST);
vb@110
    86
vb@96
    87
        DWORD value;
vb@96
    88
        DWORD size;
vb@88
    89
vb@96
    90
        LONG lResult = RegGetValue(cu, plugin_reg_path, plugin_reg_value_name, RRF_RT_REG_DWORD, NULL, &value, &size);
vb@96
    91
        if (lResult != ERROR_SUCCESS)
vb@96
    92
            return;
vb@96
    93
vb@96
    94
        if (value != 3) {
vb@96
    95
            lResult = RegSetValue(cu, plugin_reg_path, RRF_RT_REG_DWORD, plugin_reg_value_name, 3);
vb@96
    96
            assert(lResult == ERROR_SUCCESS);
vb@96
    97
        }
vb@96
    98
    }
vb@96
    99
vb@111
   100
    string GateKeeper::update_key()
vb@110
   101
    {
vb@110
   102
        static string key;
vb@110
   103
vb@110
   104
        if (key.length() == 0) {
vb@110
   105
            HRSRC res = FindResource(_self->hModule(), MAKEINTRESOURCE(IRD_UPDATEKEY), RT_RCDATA);
vb@110
   106
            assert(res);
vb@110
   107
            if (!res)
vb@110
   108
                throw runtime_error("FindResource: IRD_UPDATEKEY");
vb@110
   109
vb@110
   110
            HGLOBAL hRes = LoadResource(_self->hModule(), res);
vb@110
   111
            assert(hRes);
vb@110
   112
            if (!hRes)
vb@110
   113
                throw runtime_error("LoadResource: IRD_UPDATEKEY");
vb@110
   114
vb@110
   115
            key = string((char *)LockResource(hRes), SizeofResource(_self->hModule(), res));
vb@110
   116
            UnlockResource(hRes);
vb@110
   117
        }
vb@110
   118
vb@110
   119
        return key;
vb@110
   120
    }
vb@110
   121
vb@116
   122
    BCRYPT_KEY_HANDLE GateKeeper::delivery_key()
vb@112
   123
    {
vb@112
   124
        aeskey_t key;
vb@112
   125
vb@112
   126
        static random_device rd;
vb@112
   127
        static mt19937 gen(rd());
vb@112
   128
vb@112
   129
        uniform_int_distribution<time_t> dist(0, UINT64_MAX);
vb@112
   130
vb@113
   131
        key.qw_key[0] = dist(gen);
vb@113
   132
        key.qw_key[1] = dist(gen);
vb@113
   133
vb@116
   134
        BCRYPT_KEY_HANDLE hKey;
vb@116
   135
        NTSTATUS status = BCryptGenerateSymmetricKey(hAES, &hKey, NULL, 0, (PUCHAR) &key, (ULONG) sizeof(aeskey_t), 0);
vb@116
   136
        assert(status == 0);
vb@116
   137
        if (status)
vb@116
   138
            throw runtime_error("BCryptGenerateSymmetricKey");
vb@116
   139
vb@116
   140
        return hKey;
vb@113
   141
    }
vb@113
   142
vb@116
   143
    string GateKeeper::wrapped_delivery_key(BCRYPT_KEY_HANDLE hKey)
vb@113
   144
    {
vb@113
   145
        string result;
vb@113
   146
vb@116
   147
        BCRYPT_KEY_HANDLE hUpdateKey;
vb@113
   148
vb@113
   149
        return result;
vb@112
   150
    }
vb@112
   151
vb@96
   152
    GateKeeper::product_list& GateKeeper::registered_products()
vb@96
   153
    {
vb@96
   154
        static product_list products;
vb@88
   155
vb@96
   156
        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724872(v=vs.85).aspx
vb@96
   157
        static TCHAR value_name[16384];
vb@96
   158
        DWORD value_name_size;
vb@96
   159
        static TCHAR value[L_MAX_URL_LENGTH + 1];
vb@96
   160
        DWORD value_size;
vb@88
   161
vb@96
   162
        products.empty();
vb@96
   163
vb@96
   164
        LONG lResult = ERROR_SUCCESS;
vb@96
   165
        for (DWORD i = 0; lResult == ERROR_SUCCESS; i++) {
vb@96
   166
            value_size = L_MAX_URL_LENGTH + 1;
vb@96
   167
            lResult = RegEnumValue(hkUpdater, 0, value_name, &value_name_size, NULL, NULL, (LPBYTE) value, &value_size);
vb@96
   168
            if (lResult == ERROR_SUCCESS)
vb@96
   169
                products.push_back({ value_name, value });
vb@88
   170
        }
vb@88
   171
vb@96
   172
        return products;
vb@88
   173
    }
vb@88
   174
vb@97
   175
    void GateKeeper::update_product(product p, DWORD context)
vb@96
   176
    {
vb@97
   177
        HINTERNET hUrl = InternetOpenUrl(internet, p.second.c_str(), NULL, 0,
vb@97
   178
                INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_UI | INTERNET_FLAG_SECURE, context);
vb@97
   179
        if (hUrl == NULL)
vb@97
   180
            return;
vb@94
   181
vb@97
   182
        // update
vb@107
   183
        PCTSTR rgpszAcceptTypes[] = { _T("text/plain"), NULL };
vb@107
   184
        HINTERNET hRequest = HttpOpenRequest(hUrl, NULL, _T("challenge"), NULL, NULL, rgpszAcceptTypes, INTERNET_FLAG_NO_UI | INTERNET_FLAG_SECURE, context);
vb@107
   185
vb@97
   186
vb@97
   187
        InternetCloseHandle(hUrl);
vb@96
   188
    }
vb@88
   189
vb@96
   190
    void GateKeeper::keep_updated()
vb@96
   191
    {
vb@107
   192
        return; // disabled for now
vb@107
   193
vb@116
   194
        NTSTATUS status = BCryptOpenAlgorithmProvider(&hAES, BCRYPT_AES_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
vb@116
   195
        assert(status == 0);
vb@116
   196
        if (status)
vb@116
   197
            goto closing;
vb@116
   198
vb@116
   199
        status = BCryptOpenAlgorithmProvider(&hRSA, BCRYPT_RSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
vb@116
   200
        assert(status == 0);
vb@116
   201
        if (status)
vb@116
   202
            goto closing;
vb@116
   203
vb@97
   204
        internet = InternetOpen(_T("pEp"), INTERNET_OPEN_TYPE_PROXY, NULL, NULL, 0);
vb@116
   205
        if (!internet)
vb@116
   206
            goto closing;
vb@97
   207
vb@96
   208
        product_list& products = registered_products();
vb@97
   209
        DWORD context = 0;
vb@96
   210
        for (auto i = products.begin(); i != products.end(); i++) {
vb@97
   211
            update_product(*i, context++);
vb@96
   212
        }
vb@97
   213
vb@116
   214
    closing:
vb@116
   215
        if (internet)
vb@116
   216
            InternetCloseHandle(internet);
vb@116
   217
        if (hAES)
vb@116
   218
            BCryptCloseAlgorithmProvider(hAES, 0);
vb@116
   219
        if (hRSA)
vb@116
   220
            BCryptCloseAlgorithmProvider(hRSA, 0);
vb@97
   221
        internet = NULL;
vb@116
   222
        hAES = NULL;
vb@116
   223
        hRSA = NULL;
vb@96
   224
    }
vb@88
   225
vb@96
   226
} // namespace pEp