LicenseManager.cc 12.7 KB
Newer Older
1
/*===========================================================================*\
Jan Möbius's avatar
Jan Möbius committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
*                                                                            *
*                              OpenFlipper                                   *
*      Copyright (C) 2001-2010 by Computer Graphics Group, RWTH Aachen       *
*                           www.openflipper.org                              *
*                                                                            *
*--------------------------------------------------------------------------- *
*  This file is part of OpenFlipper.                                         *
*                                                                            *
*  OpenFlipper is free software: you can redistribute it and/or modify       *
*  it under the terms of the GNU Lesser General Public License as            *
*  published by the Free Software Foundation, either version 3 of            *
*  the License, or (at your option) any later version with the               *
*  following exceptions:                                                     *
*                                                                            *
*  If other files instantiate templates or use macros                        *
*  or inline functions from this file, or you compile this file and          *
*  link it with other files to produce an executable, this file does         *
*  not by itself cause the resulting executable to be covered by the         *
*  GNU Lesser General Public License. This exception does not however        *
*  invalidate any other reasons why the executable file might be             *
*  covered by the GNU Lesser General Public License.                         *
*                                                                            *
*  OpenFlipper 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 Lesser General Public License for more details.                       *
*                                                                            *
*  You should have received a copy of the GNU LesserGeneral Public           *
*  License along with OpenFlipper. If not,                                   *
*  see <http://www.gnu.org/licenses/>.                                       *
*                                                                            *
33
34
35
\*===========================================================================*/

/*===========================================================================*\
Jan Möbius's avatar
Jan Möbius committed
36
37
38
39
40
*                                                                            *
*   $Revision$                                                       *
*   $LastChangedBy$                                                *
*   $Date$                     *
*                                                                            *
41
\*===========================================================================*/
42
43
44
45
46
47
48

#include <OpenFlipper/LicenseManager/LicenseManager.hh>
#include <OpenFlipper/common/GlobalOptions.hh>
#include <QFile>
#include <QCryptographicHash>
#include <QNetworkInterface>

Jan Möbius's avatar
Jan Möbius committed
49
/*
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//
// CpuIDSupported will return 0 if CPUID instruction is unavailable. Otherwise, it will return 
// the maximum supported standard function.
//

unsigned int CpuIDSupported(void)
{
  unsigned int MaxInputValue;
  // If CPUID instruction is supported
  #ifndef WIN32
      try
      {
          MaxInputValue = 0;
	  // call cpuid with eax = 0
	  asm
	  (
	      "xorl %%eax,%%eax\n\t"
	      "cpuid\n\t"
		      : "=a" (MaxInputValue)
		      :
		      : "%ebx", "%ecx", "%edx"
		  );
      }
      catch (...)
      {
	  return(0);                   // cpuid instruction is unavailable
      }
  #else //Win32
      try
      {
	  MaxInputValue = 0;
	  // call cpuid with eax = 0
	  __asm
	  {
	      xor eax, eax
	      cpuid
	      mov MaxInputValue, eax
	  }
      }
      catch (...)
      {
	  return(0);                   // cpuid instruction is unavailable
      }
  #endif
  return MaxInputValue;
}

//
// GenuineIntel will return 0 if the processor is not a Genuine Intel Processor
//
unsigned int GenuineIntel(void)
{
  #ifndef WIN32
    unsigned int VendorIDb = 0,VendorIDd = 0, VendorIDc = 0;
    try
    // If CPUID instruction is supported
    {
      // Get vendor id string
      asm
      (
        //get the vendor string
        // call cpuid with eax = 0
              "xorl %%eax, %%eax\n\t"
              "cpuid\n\t"
          :   "=b" (VendorIDb),
              "=d" (VendorIDd),
              "=c" (VendorIDc)
          :
          : "%eax"
      );
    }
    catch (...)
    {
      return(0);                   // cpuid instruction is unavailable
    }
    return (
                (VendorIDb  == 'uneG') &&
                (VendorIDd  == 'Ieni') &&
                (VendorIDc  == 'letn')
            );
  #else
    unsigned int VendorID[3] = {0, 0, 0};
    try    // If CPUID instruction is supported
    {
      __asm
      {
          xor eax, eax            // call cpuid with eax = 0
          cpuid                    // Get vendor id string
          mov VendorID, ebx
          mov VendorID + 4, edx
          mov VendorID + 8, ecx
      }
    }
    catch (...)
    {
      return(0);
      unsigned int MaxInputValue =0;
      // cpuid instruction is unavailable
    }
    return (
               (VendorID[0] == 'uneG') &&
               (VendorID[1] == 'Ieni') &&
               (VendorID[2] == 'letn')
           );
  #endif
}
Jan Möbius's avatar
Jan Möbius committed
156
*/
157
158
159
160
161
162
163
164
165
166


LicenseManager::~LicenseManager() 
{ 
  exit(0); 
}

LicenseManager::LicenseManager()
{
  authenticated_ = false;
Jan Möbius's avatar
Jan Möbius committed
167
168
  
  // On startup, block all signals by default until the plugin is authenticated!
169
170
171
  QObject::blockSignals( true );
}

Jan Möbius's avatar
Jan Möbius committed
172
173
// Override default block signals. Transparent if authenticated, otherwise
// the function will always block the signals automatically
174
void LicenseManager::blockSignals( bool _state) {
Jan Möbius's avatar
Jan Möbius committed
175

176
177
178
179
180
181
182
183
  if ( !authenticated() ) {
    QObject::blockSignals( true );
  } else {
    QObject::blockSignals(_state);
  }

}

Jan Möbius's avatar
Jan Möbius committed
184
185
// Plugin authentication function.
bool LicenseManager::authenticate(QString& _authstring) {
186

Jan Möbius's avatar
Jan Möbius committed
187
188
189
  // Construct license string (will be cleaned up if license valid)
  _authstring = "==\n";
  _authstring += "PluginName: " + pluginFileName() + "\n";
190
191
  
  // ===============================================================================================
Jan Möbius's avatar
Jan Möbius committed
192
  // Compute hash value of Core application binary
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  // ===============================================================================================

  #ifdef WIN32
    QFile coreApp(OpenFlipper::Options::applicationDirStr() + QDir::separator() + "bin" + QDir::separator() + "OpenFlipper.exe");
  #else
    QFile coreApp(OpenFlipper::Options::applicationDirStr() + QDir::separator() + "bin" + QDir::separator() + "OpenFlipper");
  #endif

  if ( ! coreApp.exists() ) {
    std::cerr << "Error finding core application for security check! : " << coreApp.fileName().toStdString() << std::endl;
    return false;
  }

  coreApp.open(QIODevice::ReadOnly);
  QCryptographicHash sha1sumCore( QCryptographicHash::Sha1 );
  sha1sumCore.addData(coreApp.readAll() );
  coreApp.close();

  QString coreHash = QString(sha1sumCore.result().toHex());
  

  // ===============================================================================================
Jan Möbius's avatar
Jan Möbius committed
215
  // Compute hash of Plugin binary
216
217
218
219
220
  // ===============================================================================================

  #ifdef WIN32
    QFile pluginFile(OpenFlipper::Options::pluginDirStr() + QDir::separator() + pluginFileName() + ".dll");
  #else
Jan Möbius's avatar
Jan Möbius committed
221
    QFile pluginFile(OpenFlipper::Options::pluginDirStr() + QDir::separator() + "lib" + pluginFileName() + ".so");
222
223
224
225
  #endif

  if ( ! pluginFile.exists() ) {
    std::cerr << "Error finding plugin file for security check!" << std::endl;
Jan Möbius's avatar
Jan Möbius committed
226
    std::cerr << "Path: " << pluginFile.fileName().toStdString() << std::endl;
227
228
229
230
231
232
233
234
235
236
    return false;
  }

  pluginFile.open(QIODevice::ReadOnly);
  QCryptographicHash sha1sumPlugin( QCryptographicHash::Sha1 );
  sha1sumPlugin.addData(pluginFile.readAll());
  pluginFile.close();

  QString pluginHash = QString(sha1sumPlugin.result().toHex());

Jan Möbius's avatar
Jan Möbius committed
237
238
239
  // ===============================================================================================
  // Compute hash of network interfaces
  // ===============================================================================================  
240

Jan Möbius's avatar
Jan Möbius committed
241
  QString mac;
242
243
244
245

  // Get all Network Interfaces
  QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
  foreach ( QNetworkInterface interface, interfaces ) {
Jan Möbius's avatar
Jan Möbius committed
246
    mac = mac + interface.hardwareAddress().remove(":");
247
248
  }

Jan Möbius's avatar
Jan Möbius committed
249
  QString macHash = QCryptographicHash::hash ( mac.toAscii()  , QCryptographicHash::Sha1 ).toHex();
250

Jan Möbius's avatar
Jan Möbius committed
251
252
//   std::cerr << "CPUID Supported : " << CpuIDSupported() << std::endl;
//   std::cerr << "GenuineIntel    : " << GenuineIntel() << std::endl;
253

Jan Möbius's avatar
Jan Möbius committed
254
255
  QString saltPre;
  ADD_SALT_PRE(saltPre);
Jan Möbius's avatar
Jan Möbius committed
256
  
Jan Möbius's avatar
Jan Möbius committed
257
258
259
  QString saltPost;
  ADD_SALT_POST(saltPost);

Jan Möbius's avatar
Jan Möbius committed
260
  QString licenseFileName = OpenFlipper::Options::licenseDirStr() + QDir::separator() + pluginFileName() + ".lic";
Jan Möbius's avatar
Jan Möbius committed
261
262
263
264
265
266
  QFile file( licenseFileName );

  if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) {
    std::cerr << "Unable to find license File " <<  licenseFileName.toStdString() << std::endl;
  } else {
    QString licenseContents = file.readAll();
Jan Möbius's avatar
Jan Möbius committed
267
268
    QStringList elements = licenseContents.split('\n');

Jan Möbius's avatar
Jan Möbius committed
269
270
271
    for ( int i = 0 ; i < elements.size(); ++i )
      elements[i] = elements[i].simplified();

Jan Möbius's avatar
Jan Möbius committed
272
273
    if ( elements.size() != 6 ) {
      QString sizeMismatchMessage = "The license file for plugin \"" + name() + "\" is invalid!";
274
      QMessageBox::critical(0,tr("License file size invalid"),sizeMismatchMessage );
Jan Möbius's avatar
Jan Möbius committed
275
276
    } else {

Jan Möbius's avatar
Jan Möbius committed
277
278
279
280
281
282
283
284
      // Check signature of license file
      QString license = saltPre + elements[0] + elements[1] + elements[2] + elements[3] + elements[4] + saltPost;
      QString licenseHash = QCryptographicHash::hash ( license.toAscii()  , QCryptographicHash::Sha1 ).toHex();
      
      QDate currentDate = QDate::currentDate();
      QDate expiryDate  = QDate::fromString(elements[4],Qt::ISODate);

      if ( licenseHash !=  elements[5] ) {
Jan Möbius's avatar
Jan Möbius committed
285
        _authstring += tr("License Error: The license file signature for plugin \"") + name() + tr("\" is invalid!\n\n");
Jan Möbius's avatar
Jan Möbius committed
286
      } else  if ( elements[0] != pluginFileName() ) {
Jan Möbius's avatar
Jan Möbius committed
287
        _authstring += tr("License Error: The license file contains plugin name\"") + elements[0] + tr("\" but this is plugin \"") + name() + "\"!\n\n";
Jan Möbius's avatar
Jan Möbius committed
288
      } else if ( elements[1] != coreHash ) {
Jan Möbius's avatar
Jan Möbius committed
289
        _authstring += tr("License Error: The license file for plugin \"") + name() + tr("\" is invalid for the currently running OpenFlipper Core!\n\n");
Jan Möbius's avatar
Jan Möbius committed
290
      } else if ( elements[2] != pluginHash ) {
Jan Möbius's avatar
Jan Möbius committed
291
        _authstring += tr("License Error: The plugin \"") + name() + tr("\" is a different version than specified in license file!\n\n");
Jan Möbius's avatar
Jan Möbius committed
292
      } else if ( elements[3] != macHash ) {
Jan Möbius's avatar
Jan Möbius committed
293
        _authstring += "License Error: The plugin \"" + name() + "\" is not allowed to run on the current system (Changed Hardware?)!\n\n";
Jan Möbius's avatar
Jan Möbius committed
294
      } else if ( currentDate > expiryDate ) {
Jan Möbius's avatar
Jan Möbius committed
295
        _authstring += tr("License Error: The license for plugin \"") + name() + tr("\" has expired on ") + elements[1] + "!\n\n";
Jan Möbius's avatar
Jan Möbius committed
296
      } else {
Jan Möbius's avatar
Jan Möbius committed
297
        authenticated_ = true;
Jan Möbius's avatar
Jan Möbius committed
298
      }
Jan Möbius's avatar
Jan Möbius committed
299

Jan Möbius's avatar
Jan Möbius committed
300
301
302
303
      // Clean it on success
      if (  authenticated_ ) 
        _authstring = "";
      
Jan Möbius's avatar
Jan Möbius committed
304
305
306
    }
  }

Jan Möbius's avatar
Jan Möbius committed
307
308
309
  if ( authenticated_ ) {
    blockSignals(false);
  } else {
Jan Möbius's avatar
Jan Möbius committed
310
311
312
313
    _authstring += tr("Message: License check for plugin failed.\n");
    _authstring += tr("Message: Please get a valid License!\n");
    _authstring += tr("Message: Send the following Information to \n");
    _authstring += tr("Contact mail: ") + CONTACTMAIL + "\n\n";
Jan Möbius's avatar
Jan Möbius committed
314
315
316
317
    _authstring += pluginFileName() +"\n";
    _authstring += coreHash +"\n";
    _authstring += pluginHash +"\n";
    _authstring += macHash +"\n";
Jan Möbius's avatar
Jan Möbius committed
318
319
320

    QString keyRequest = saltPre + pluginFileName() + coreHash+pluginHash+macHash +saltPost;
    QString requestSig = QCryptographicHash::hash ( keyRequest.toAscii()  , QCryptographicHash::Sha1 ).toHex();
Jan Möbius's avatar
Jan Möbius committed
321
    _authstring += requestSig + "\n";
Jan Möbius's avatar
Jan Möbius committed
322

Jan Möbius's avatar
Jan Möbius committed
323
    authenticated_ = false;
324
325
326
327
328
329
  }

  return authenticated_;
}

bool LicenseManager::authenticated() {
Jan Möbius's avatar
Jan Möbius committed
330
  // Function to check if the plugin is authenticated
331
332
333
334
  return authenticated_;
}

void LicenseManager::connectNotify ( const char * /*signal*/ ) {
Jan Möbius's avatar
Jan Möbius committed
335
336
337

  // if the plugin is not authenticated and something wants to connect, we block all signals and force a direct disconnect
  // here, rendering all signal/slot connections useless.
338
339
  if ( !authenticated() ) {
    blockSignals(true);
Jan Möbius's avatar
Jan Möbius committed
340
    disconnect();
341
  }
Jan Möbius's avatar
Jan Möbius committed
342
  
343
344
345
}

QString LicenseManager::pluginFileName() {
Jan Möbius's avatar
Jan Möbius committed
346
347
348
349
  // FileName of the plugin. has to be set via the salt file
  QString pluginFileName;
  ADD_PLUGIN_FILENAME(pluginFileName);
  return pluginFileName;
350
351
}