Sync with 5.4.0
[deliverable/titan.core.git] / common / license.c
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
3// All rights reserved. This program and the accompanying materials
4// are made available under the terms of the Eclipse Public License v1.0
5// which accompanies this distribution, and is available at
6// http://www.eclipse.org/legal/epl-v10.html
7///////////////////////////////////////////////////////////////////////////////
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <time.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <sys/time.h>
16#ifndef MINGW
17# include <pwd.h>
18#endif
19#include <errno.h>
20
21#include <openssl/bn.h>
22#include <openssl/sha.h>
23#include <openssl/rand.h>
24#include <openssl/dsa.h>
25#include <openssl/pem.h>
26#include <openssl/err.h>
27
28#ifdef WIN32
29# include <windows.h>
30# include <winreg.h>
31# ifdef MINGW
32# include <lmcons.h>
33# endif
34# include <openssl/md5.h>
35#endif
36
37#ifdef INTERIX
38# include <interix/interix.h>
39# include <openssl/md5.h>
40#endif
41
42#include "memory.h"
43#include "license.h"
44#include "version.h"
45
46#ifdef TTCN3_BUILDNUMBER
47 /* In pre-release builds: */
48#define TTCN3_VERSION_CHECK TTCN3_MAJOR * 1000000 + TTCN3_MINOR * 10000 + TTCN3_PATCHLEVEL * 100 + TTCN3_BUILDNUMBER
49#else
50 /* In official releases: */
51#define TTCN3_VERSION_CHECK TTCN3_MAJOR * 10000 + TTCN3_MINOR * 100 + TTCN3_PATCHLEVEL
52#endif
53
54#if TTCN3_VERSION_CHECK != TTCN3_VERSION
55#error TTCN3_VERSION in version.h does not match the value computed from TTCN3_MAJOR,TTCN3_MINOR,TTCN3_PATCHLEVEL,TTCN3_BUILDNUMBER
56/* for debugging: these would appear in the preprocessed file */
57static const int ttcn3_version = TTCN3_VERSION;
58static const int ttcn3_version_check = TTCN3_VERSION_CHECK;
59#endif
60
61static const unsigned char dsa_p[] = { 0x90, 0x63, 0x82, 0xae, 0x72, 0x71, 0xac, 0x14, 0xec, 0x9c, 0x71, 0x38, 0x9f, 0xda, 0x8d, 0x52, 0xbd, 0xb1, 0xa7, 0x1a, 0x19, 0xd4, 0x5f, 0xe7, 0x37, 0x3d, 0x44, 0xef, 0xce, 0xa1, 0x99, 0xfa, 0x85, 0xb6, 0x49, 0x77, 0xf1, 0x98, 0x39, 0x6b, 0x71, 0xce, 0x2, 0x42, 0x64, 0x4b, 0xd, 0xad, 0x83, 0xb0, 0x6b, 0x76, 0xba, 0xdc, 0x4f, 0xe0, 0x19, 0xf9, 0xc2, 0x79, 0x6e, 0xbb, 0xc, 0xab, 0x16, 0xae, 0xec, 0x56, 0x75, 0xff, 0x82, 0xb, 0x74, 0xd8, 0x96, 0x42, 0x23, 0x68, 0xf, 0xad, 0x27, 0xee, 0x4c, 0xbf, 0xf2, 0xd4, 0x49, 0x77, 0x8b, 0x1e, 0xf1, 0xdc, 0x5c, 0x4d, 0xfd, 0xa6, 0xd8, 0x5a, 0x70, 0x3f, 0x13, 0xd2, 0xed, 0x3f, 0x59, 0x9, 0x62, 0x2b, 0xb2, 0x8f, 0xcd, 0x7a, 0xa9, 0x3e, 0x6c, 0xb1, 0xe8, 0x80, 0x9d, 0xd2, 0x74, 0xc, 0xc8, 0xdf, 0xa, 0x40, 0xc9, 0xb3 },
62 dsa_q[] = { 0xa3, 0xe2, 0x23, 0x73, 0xd3, 0x8a, 0x4b, 0x61, 0xd0, 0x60, 0x41, 0x21, 0x41, 0x6d, 0xc4, 0xf6, 0x8c, 0x5c, 0x89, 0x87 },
63 dsa_g[] = { 0x40, 0x6d, 0xfb, 0x6d, 0xb6, 0x6, 0x32, 0xcc, 0xf0, 0xe9, 0x84, 0x16, 0x1e, 0xe1, 0x21, 0xcd, 0x34, 0xe7, 0xbb, 0x6c, 0x98, 0xff, 0xa9, 0xb9, 0xae, 0xe4, 0x6a, 0x61, 0x51, 0xf8, 0x66, 0x83, 0xa4, 0x34, 0x63, 0x81, 0xc4, 0x5f, 0xee, 0x85, 0x74, 0xee, 0x2a, 0x63, 0x9d, 0xcf, 0x97, 0x50, 0xb8, 0x9f, 0x76, 0xd9, 0xe, 0x58, 0xab, 0xac, 0x2e, 0x23, 0xac, 0x95, 0xc3, 0xb7, 0x14, 0xd6, 0x69, 0xff, 0x36, 0xef, 0xa4, 0xa9, 0xe1, 0xd6, 0x7a, 0xfd, 0x9d, 0x68, 0x91, 0xcf, 0x2d, 0xcd, 0x98, 0xc5, 0xe6, 0xf4, 0x1e, 0xde, 0xf8, 0x65, 0x6b, 0xeb, 0x80, 0x41, 0xab, 0xc7, 0x97, 0xcb, 0xbb, 0xc5, 0x5, 0x7, 0x22, 0x81, 0x58, 0x63, 0xf9, 0x67, 0xd4, 0x7c, 0xb6, 0x21, 0x17, 0xea, 0x62, 0xe3, 0xe8, 0x3f, 0x60, 0xb1, 0x51, 0x51, 0x4, 0xf2, 0x6f, 0x5c, 0x47, 0x69, 0x6b, 0xc1 },
64 dsa_pub_key[] = { 0x76, 0xe, 0xf, 0x36, 0x77, 0x6, 0x9d, 0xb1, 0xf1, 0x4e, 0x9a, 0x95, 0xae, 0xc9, 0x39, 0xdf, 0x90, 0xd3, 0x94, 0x54, 0xf8, 0xf6, 0x89, 0xc8, 0x11, 0x8d, 0x2e, 0x92, 0x81, 0x6b, 0x2c, 0x37, 0x4, 0x9d, 0x97, 0x9a, 0x43, 0xa3, 0x2e, 0xed, 0x9a, 0x99, 0xb0, 0xcb, 0x9f, 0x4e, 0xea, 0x4f, 0xb7, 0xd5, 0x93, 0xc0, 0x86, 0x1b, 0xc7, 0x97, 0x5f, 0x5, 0xb4, 0xf1, 0xf9, 0xd6, 0x73, 0x97, 0x19, 0xe3, 0xc9, 0xda, 0xfc, 0x39, 0xe0, 0x37, 0xed, 0x7a, 0x62, 0xcb, 0xe3, 0x17, 0x9b, 0x64, 0x3c, 0x46, 0x86, 0x3f, 0x32, 0xec, 0x70, 0xab, 0x5b, 0x87, 0x5a, 0x6e, 0xc3, 0x37, 0xeb, 0x92, 0x58, 0x6c, 0x9e, 0x25, 0x1f, 0x37, 0x4b, 0xcd, 0xb5, 0x22, 0x62, 0x1d, 0x1b, 0x1c, 0xb1, 0x5d, 0xa1, 0xef, 0x50, 0xc3, 0x75, 0xff, 0x2, 0x24, 0x8c, 0xd7, 0x3b, 0x91, 0x77, 0xef, 0x94, 0x76 };
65
66/** Big-endian decoding of a 4-byte integer */
67static unsigned int decode_int(const unsigned char *from)
68{
69 return (unsigned int)from[3]
70 | ((unsigned int)from[2] << 8)
71 | ((unsigned int)from[1] << 16)
72 | ((unsigned int)from[0] << 24);
73}
74
75/** Extract a string from a fixed-length field.
76 *
77 * @param from the beginning of the field
78 * @param max_length the size of the field
79 * @return a newly allocated string. The caller is responsible for
80 * calling Free()
81 *
82 * Verifies that the unused portion of the field is properly zeroed out
83 * (no non-NUL characters after the first NUL character). Terminates
84 * the program with EXIT_FAILURE if there is trailing garbage
85 * after the end of the string. */
86static char *decode_string(const char *from, size_t max_length)
87{
88 size_t i, length;
89 char *ptr;
90 for (i = 0; i < max_length && from[i] != '\0'; i++);
91 length = i;
92 /* Verify that the tail is properly zeroed (no junk). */
93 for (i++; i < max_length; i++)
94 if (from[i] != '\0') {
95 fputs("License file is corrupted: invalid string encoding\n",
96 stderr);
97 exit(EXIT_FAILURE);
98 }
99 ptr = (char*)Malloc(length + 1);
100 memcpy(ptr, from, length);
101 ptr[length] = '\0';
102 return ptr;
103}
104
105static void decode_license(license_struct *to, const license_raw *from)
106{
107 to->license_file = NULL;
108 to->unique_id = decode_int(from->unique_id);
109 to->licensee_name = decode_string(from->licensee_name,
110 sizeof(from->licensee_name));
111 to->licensee_email = decode_string(from->licensee_email,
112 sizeof(from->licensee_email));
113 to->licensee_company = decode_string(from->licensee_company,
114 sizeof(from->licensee_company));
115 to->licensee_department = decode_string(from->licensee_department,
116 sizeof(from->licensee_department));
117 to->valid_from = decode_int(from->valid_from);
118 to->valid_until = decode_int(from->valid_until);
119 to->host_id = decode_int(from->host_id);
120 to->login_name = decode_string(from->login_name, sizeof(from->login_name));
121 to->from_major = decode_int(from->from_major);
122 to->from_minor = decode_int(from->from_minor);
123 to->from_patchlevel = decode_int(from->from_patchlevel);
124 to->to_major = decode_int(from->to_major);
125 to->to_minor = decode_int(from->to_minor);
126 to->to_patchlevel = decode_int(from->to_patchlevel);
127 to->feature_list = decode_int(from->feature_list);
128
129 /* Borrow the PER bit for this year */
130 /* 1262300400 is Fri Jan 1 00:00:00 2010 */
131 if((to->feature_list & FEATURE_PER) && (time(NULL) < 1262300400)) {
132 to->feature_list |= FEATURE_XER;
133 }
134
135 to->limitation_type = decode_int(from->limitation_type);
136 to->max_ptcs = decode_int(from->max_ptcs);
137}
138
139static void check_license_signature(license_raw *lptr)
140{
141 unsigned char message_digest[SHA_DIGEST_LENGTH];
142 SHA_CTX sha_ctx;
143 DSA *dsa = DSA_new();
144
145 SHA1_Init(&sha_ctx);
146 SHA1_Update(&sha_ctx, lptr, sizeof(*lptr) - sizeof(lptr->dsa_signature));
147 SHA1_Final(message_digest, &sha_ctx);
148
149 dsa->p = BN_bin2bn(dsa_p, sizeof(dsa_p), NULL);
150 dsa->q = BN_bin2bn(dsa_q, sizeof(dsa_q), NULL);
151 dsa->g = BN_bin2bn(dsa_g, sizeof(dsa_g), NULL);
152 dsa->pub_key = BN_bin2bn(dsa_pub_key, sizeof(dsa_pub_key), NULL);
153
509718e0 154 // calculate the right len of the signiture
155 DSA_SIG *temp_sig=DSA_SIG_new();
156 int siglen = -1;
157 const unsigned char *data =lptr->dsa_signature;
158 if (temp_sig == NULL || d2i_DSA_SIG(&temp_sig,&data,sizeof(lptr->dsa_signature)) == NULL){
159 fprintf(stderr, "License signature verification failed: %s\n",
160 ERR_error_string(ERR_get_error(), NULL));
161 exit(EXIT_FAILURE);
162 }
163 unsigned char *tmp_buff= NULL;
164 siglen = i2d_DSA_SIG(temp_sig, &tmp_buff);
165 OPENSSL_cleanse(tmp_buff, siglen);
166 OPENSSL_free(tmp_buff);
167 DSA_SIG_free(temp_sig);
168
970ed795 169 switch(DSA_verify(0, message_digest, sizeof(message_digest),
509718e0 170 lptr->dsa_signature, siglen, dsa)) {
970ed795
EL
171 case 0:
172 fputs("License file is corrupted: invalid DSA signature.\n", stderr);
173 exit(EXIT_FAILURE);
174 case 1:
175 break; /* valid signature */
176 default:
177 fprintf(stderr, "License signature verification failed: %s\n",
178 ERR_error_string(ERR_get_error(), NULL));
179 exit(EXIT_FAILURE);
180 }
181
182 DSA_free(dsa);
183}
184
185/** Read a PEM-encoded license from a file.
186 *
187 * @param [in] file_name string containing license file name
188 * @param [out] lptr filled with the decoded license information
189 *
190 * If the license information cannot be obtained (bad file name or wrong content),
191 * terminates the program with EXIT_FAILURE. */
192static void read_license(const char *file_name, license_raw *lptr)
193{
194 char *name = NULL;
195 char *header = NULL;
196 unsigned char *data = NULL;
197 long len = 0;
198 struct stat buf;
199 FILE *fp;
200
201 if (stat(file_name, &buf) != 0) {
202 fprintf(stderr, "Cannot access license file `%s'. (%s)\n",
203 file_name, strerror(errno));
204 exit(EXIT_FAILURE);
205 }
206 if (buf.st_mode & S_IFDIR) {
207 fprintf(stderr, "The environment variable TTCN3_LICENSE_FILE was set "
208 "to `%s', which is a directory. It must be set to the file that "
209 "contains the license key.\n", file_name);
210 exit(EXIT_FAILURE);
211 }
212 fp = fopen(file_name, "r");
213 if (fp == NULL) {
214 fprintf(stderr, "Cannot open license file `%s' for reading. (%s)\n",
215 file_name, strerror(errno));
216 exit(EXIT_FAILURE);
217 }
218 if (!PEM_read(fp, &name, &header, &data, &len)) {
219 fprintf(stderr, "License file is corrupted: %s\n",
220 ERR_error_string(ERR_get_error(), NULL));
221 exit(EXIT_FAILURE);
222 }
223 fclose(fp);
224 if (strcmp(name, "TTCN-3 LICENSE FILE") || strcmp(header, "")) {
225 fputs("License file is corrupted: invalid header.\n", stderr);
226 exit(EXIT_FAILURE);
227 }
228 if (len != sizeof(*lptr)) {
229 fputs("License file is corrupted: invalid length.\n", stderr);
230 exit(EXIT_FAILURE);
231 }
232 memcpy(lptr, data, sizeof(*lptr));
233 OPENSSL_free(name);
234 OPENSSL_free(header);
235 OPENSSL_free(data);
236}
237
238void load_license(license_struct *lptr)
239{
240 const char *file_name = getenv("TTCN3_LICENSE_FILE");
241 if (file_name == NULL) {
242 fputs("TTCN3_LICENSE_FILE environment variable is not set.\n",
243 stderr);
244 exit(EXIT_FAILURE);
245 }
246 load_license_from_file(lptr, file_name);
247}
248
249void load_license_from_file(license_struct *lptr, const char *file_name)
250{
251 license_raw lraw;
252 read_license(file_name, &lraw);
253 check_license_signature(&lraw);
254 decode_license(lptr, &lraw);
255 lptr->license_file = mcopystr(file_name);
256}
257
258void free_license(license_struct *lptr)
259{
260 Free(lptr->license_file);
261 lptr->license_file = NULL;
262 Free(lptr->licensee_name);
263 lptr->licensee_name = NULL;
264 Free(lptr->licensee_email);
265 lptr->licensee_email = NULL;
266 Free(lptr->licensee_company);
267 lptr->licensee_company = NULL;
268 Free(lptr->licensee_department);
269 lptr->licensee_department = NULL;
270 Free(lptr->login_name);
271 lptr->login_name = NULL;
272}
273
274int verify_license(const license_struct *lptr)
275{
276 time_t current_time = time(NULL);
277 int errflag = 0;
278
279 if (current_time < lptr->valid_from) {
280 fputs("The license key is not yet valid.\n", stderr);
281 errflag = 1;
282 }
283
284 if (current_time > lptr->valid_until) {
285 fputs("The license key has already expired.\n", stderr);
286 errflag = 1;
287 }
288
289 if (lptr->limitation_type & LIMIT_HOST) {
290 /* broken libc call gethostid() performs sign extension on some 64-bit
291 * Linux platforms, thus only the lowest 32 bits are considered */
292 unsigned long host_id = (unsigned long)gethostid() & 0xffffffffUL;
293 if (host_id != lptr->host_id) {
294 fprintf(stderr, "The license key is not valid for this host "
295 "(%08lx).\n", host_id);
296 errflag = 1;
297 }
298 }
299
300 if (lptr->limitation_type & LIMIT_USER) {
301#ifdef MINGW
302 TCHAR user_name[UNLEN + 1];
303 DWORD buffer_size = sizeof(user_name);
304 if (GetUserName(user_name, &buffer_size)) {
305 if (strcmp(user_name, lptr->login_name)) {
306 fprintf(stderr, "The license key is not valid for this user "
307 "name (%s).\n", user_name);
308 errflag = 1;
309 }
310 } else {
311 fprintf(stderr, "Getting the current user name failed when "
312 "verifying the license key. Windows error code: %d.\n",
313 (int)GetLastError());
314 errflag = 1;
315 }
316#else
317 uid_t process_uid = getuid();
318 struct passwd *p;
319 setpwent();
320 p = getpwuid(process_uid);
321 if (p == NULL) {
322 fprintf(stderr, "The current user ID (%d) does not have login "
323 "name.\n", (int)process_uid);
324 errflag = 1;
325 } else if (strcmp(p->pw_name, lptr->login_name)) {
326 /* First making a backup copy of the current login name because
327 * the subsequent getpwnam() call will overwrite it. */
328 char *login_name = mcopystr(p->pw_name);
329 /* Another chance: Trying to map the login name of the license key
330 * to a valid UID. Note that it is possible to associate several
331 * login names with the same UID. */
332 p = getpwnam(lptr->login_name);
333 if (p == NULL || p->pw_uid != process_uid) {
334 fprintf(stderr, "The license key is not valid for this login "
335 "name (%s).\n", login_name);
336 errflag = 1;
337 }
338 Free(login_name);
339 }
340 endpwent();
341#endif
342 }
343
344 if (TTCN3_MAJOR < lptr->from_major ||
345 (TTCN3_MAJOR == lptr->from_major && (TTCN3_MINOR < lptr->from_minor ||
346 (TTCN3_MINOR == lptr->from_minor &&
347 TTCN3_PATCHLEVEL < lptr->from_patchlevel)))) {
348 /* Checking of to_{major,minor,patchlevel} removed when Titan moved
349 * to major version 2 (licenses were valid up to 1.99pl99 only) */
350 fputs("The license key is not valid for this version.\n", stderr);
351 errflag = 1;
352 }
353
354 if (errflag) {
355 return 0;
356 }
357
358 if (lptr->valid_until - current_time < EXPIRY_WARNING * 86400) {
359 time_t expiry_days = (lptr->valid_until - current_time) / 86400 + 1;
360 fprintf(stderr, "Warning: The license key will expire within %ld "
361 "day%s.\n", (long)expiry_days, expiry_days > 1 ? "s" : "");
362 }
363 /* setpwent and getpwuid calls may use some system calls that fail.
364 * We should ignore these error codes in future error messages. */
365 errno = 0;
366 return 1;
367}
368
369unsigned int check_feature(const license_struct *lptr, unsigned int feature)
370{
371 return (lptr->feature_list & feature) != 0;
372}
373
374void print_license(const license_struct *lptr)
375{
376 fprintf(stderr,
377 "---------------------------------------------------------------\n"
378 "License file : %s\n"
379 "Unique ID : %d\n"
380 "Licensee : %s\n"
381 "E-mail : %s\n"
382 "Company : %s\n"
383 "Department : %s\n"
384 "Valid from : %s",
385 lptr->license_file != NULL ? lptr->license_file : "",
386 lptr->unique_id,
387 lptr->licensee_name,
388 lptr->licensee_email,
389 lptr->licensee_company,
390 lptr->licensee_department,
391 ctime(&lptr->valid_from));
392
393 fprintf(stderr,
394 "Valid until : %s"
395 "Limitation :%s%s\n"
396 "Host ID : %08lx\n"
397 "Login name : %s\n"
398 "Versions : from %d.%d.pl%d until %d.%d.pl%d\n"
399 "Languages :%s%s\n"
400 "Encoders :%s%s%s%s%s\n"
401 "Applications :%s%s%s%s%s%s\n"
402 "Max PTCs : %d\n"
403 "---------------------------------------------------------------\n",
404 ctime(&lptr->valid_until),
405 lptr->limitation_type & LIMIT_HOST ? " HOST" : "",
406 lptr->limitation_type & LIMIT_USER ? " USER" : "",
407 lptr->host_id,
408 lptr->login_name,
409 lptr->from_major, lptr->from_minor, lptr->from_patchlevel,
410 lptr->to_major, lptr->to_minor, lptr->to_patchlevel,
411 lptr->feature_list & FEATURE_TTCN3 ? " TTCN3" : "",
412 lptr->feature_list & FEATURE_ASN1 ? " ASN1" : "",
413 lptr->feature_list & FEATURE_RAW ? " RAW" : "",
414 lptr->feature_list & FEATURE_TEXT ? " TEXT" : "",
415 lptr->feature_list & FEATURE_BER ? " BER" : "",
416 lptr->feature_list & FEATURE_PER ? " PER" : "",
417 lptr->feature_list & FEATURE_XER ? " XER" : "",
418 lptr->feature_list & FEATURE_CODEGEN ? " CODEGEN" : "",
419 lptr->feature_list & FEATURE_TPGEN ? " TPGEN" : "",
420 lptr->feature_list & FEATURE_SINGLE ? " SINGLE" : "",
421 lptr->feature_list & FEATURE_MCTR ? " MCTR" : "",
422 lptr->feature_list & FEATURE_HC ? " HC" : "",
423 lptr->feature_list & FEATURE_LOGFORMAT ? " LOGFORMAT" : "",
424 lptr->max_ptcs);
425}
426
427void print_license_info()
428{
429 license_struct lstr;
430 int license_valid;
431 fputs("License information:\n", stderr);
432 init_openssl();
433 load_license(&lstr);
434 print_license(&lstr);
435 license_valid = verify_license(&lstr);
436 free_license(&lstr);
437 free_openssl();
438
439 if (!license_valid) {
440 exit(EXIT_FAILURE);
441 }
442
443 fputs("The license key is valid.\n", stderr);
444}
445
446void init_openssl()
447{
448 if (!RAND_status()) {
449 time_t time_sec = time(NULL);
450 if (time_sec == (time_t)-1) {
451 perror("time() system call failed");
452 exit(EXIT_FAILURE);
453 }
454 RAND_seed(&time_sec, sizeof(time_sec));
455 }
456 while (!RAND_status()) {
457#ifdef MINGW
458 FILETIME filetime;
459 GetSystemTimeAsFileTime(&filetime);
460 RAND_seed(&filetime.dwLowDateTime, sizeof(filetime.dwLowDateTime));
461#else
462 struct timeval tv;
463 if (gettimeofday(&tv, NULL) == -1) {
464 perror("gettimeofday() system call failed");
465 exit(EXIT_FAILURE);
466 }
467 RAND_seed(&tv.tv_usec, sizeof(tv.tv_usec));
468#endif
469 }
470 ERR_load_crypto_strings();
471 /* Random seeding in OpenSSL may use some system calls that fail.
472 * We should ignore these error codes in future error messages. */
473 errno = 0;
474}
475
476void free_openssl()
477{
478 RAND_cleanup();
479 ERR_free_strings();
480}
481
482const char * openssl_version_str(void) {
483 return SSLeay_version(SSLEAY_VERSION);
484}
485
486#if defined(WIN32) || defined(INTERIX)
487
488#ifdef INTERIX
489#define INTERIX_PREFIX "\\Registry\\Machine\\"
490#else
491#define INTERIX_PREFIX
492#endif
493
494static const char * const keys[] = {
495 INTERIX_PREFIX "Software\\Microsoft\\Windows\\CurrentVersion\\",
496 INTERIX_PREFIX "Software\\Microsoft\\Windows NT\\CurrentVersion\\",
497 NULL
498};
499
500static const char * const values[] = {
501/* Product specific info */
502 "ProductName",
503 "Version",
504 "CurrentVersion",
505 "VersionNumber",
506 "CurrentBuildNumber",
507/* Unique identifiers */
508 "ProductKey",
509 "ProductId",
510 "DigitalProductId",
511/* User specific info */
512 "RegisteredOwner",
513 "RegisteredOrganization",
514/* Installation specific info */
515 "InstallDate",
516 "FirstInstallDateTime",
517 "SystemRoot",
518 NULL
519};
520#endif
521
522#ifdef WIN32
523
524long gethostid(void)
525{
526 const char * const *subKey;
527 MD5_CTX context;
528 unsigned char digest[MD5_DIGEST_LENGTH];
529 long hostid = 0;
530 unsigned int i;
531
532 MD5_Init(&context);
533
534 for (subKey = keys; *subKey != NULL; subKey++) {
535 HKEY hKey;
536 const char * const *valueName;
537
538 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, *subKey,
539 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
540 continue;
541
542 for (valueName = values; *valueName != NULL; valueName++) {
543 DWORD length = 0;
544 unsigned char *buffer;
545
546 if (RegQueryValueEx(hKey, *valueName, NULL, NULL, NULL, &length)
547 != ERROR_SUCCESS) continue;
548 buffer = (unsigned char*)Malloc(length);
549 if (RegQueryValueEx(hKey, *valueName, NULL, NULL, buffer, &length)
550 == ERROR_SUCCESS) {
551 MD5_Update(&context, buffer, length);
552 }
553 Free(buffer);
554 }
555 RegCloseKey(hKey);
556 }
557 MD5_Final(digest, &context);
558 for (i = 0; i < sizeof(hostid); i++) hostid |= digest[i] << i * 8;
559 return hostid;
560}
561
562#endif
563
564#ifdef INTERIX
565
566long gethostid(void)
567{
568 long hostid = 0;
569 const char * const *subKey;
570 size_t i;
571 MD5_CTX context;
572 unsigned char digest[MD5_DIGEST_LENGTH];
573
574 MD5_Init(&context);
575
576 for (subKey = keys; *subKey != NULL; subKey++) {
577 const char * const *valueName;
578 for (valueName = values; *valueName != NULL; valueName++) {
579 int ret = -13, type = -42;
580 size_t size = 0;
581 unsigned char *buffer;
582 char * key = mcopystr(*subKey);
583 key = mputstr(key, *valueName);
584
585 ret = getreg(key, &type, 0, &size); /* query the size; ret always -1 */
586 if (size > 0) {
587 buffer = Malloc(size);
588 ret = getreg(key, &type, buffer, &size);
589 if (ret == 0) {
590 switch (type) {
591 case WIN_REG_SZ:
592 case WIN_REG_EXPAND_SZ:
593 case WIN_REG_MULTI_SZ: {
594 /* getreg gave use _wide_ strings. Make them narrow.
595 FIXME this assumes everybody is american and uses US-ASCII.
596 It would be more correct to use iconv()
597 but we don't know which codepage to convert to.
598 */
599 const unsigned char *from = buffer, *end = buffer + size;
600 unsigned char *to = buffer;
601 for (; from < end; ++from) { /* Yes, from is incremented twice */
602 *to++ = *from++;
603 }
604 size /= 2;
605 break; }
606 default:
607 break;
608 }
609 MD5_Update(&context, buffer, size);
610 }
611 Free(buffer);
612 }
613 Free(key);
614 }
615 }
616
617 MD5_Final(digest, &context);
618 for (i = 0; i < sizeof(hostid); i++) hostid |= digest[i] << (i * 8);
619 return hostid;
620}
621
622#endif
This page took 0.062339 seconds and 5 git commands to generate.