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