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 | * Gecse, Roland | |
12 | * Raduly, Csaba | |
13 | * Szabados, Kristof | |
14 | * Szabo, Janos Zoltan – initial implementation | |
15 | * | |
16 | ******************************************************************************/ | |
970ed795 EL |
17 | #include <stdio.h> |
18 | #include <string.h> | |
19 | #include <stdlib.h> | |
20 | #include <stdarg.h> | |
21 | #include <unistd.h> | |
22 | #include <sys/types.h> | |
23 | #include <sys/time.h> | |
24 | #include <sys/wait.h> | |
25 | ||
26 | #include <mysql.h> | |
27 | ||
28 | #include <openssl/rand.h> | |
29 | #include <openssl/sha.h> | |
30 | #include <openssl/dsa.h> | |
31 | #include <openssl/pem.h> | |
32 | #include <openssl/err.h> | |
33 | ||
34 | #include "../common/memory.h" | |
35 | #include "../common/license.h" | |
36 | ||
37 | #define MYSQL_HOST "mwlx122.eth.ericsson.se" | |
38 | #define MYSQL_USER "ttcn3" | |
39 | #define MYSQL_PASSWORD "ttcn3" | |
40 | #define MYSQL_DATABASE "ttcn3" | |
41 | ||
42 | #define LICENSE_DIR "/mnt/TTCN/license" | |
43 | #define PRIVATE_KEY LICENSE_DIR "/key.pem" | |
44 | ||
45 | #define SECS_IN_DAY 86400 | |
46 | ||
47 | __attribute__ ((__format__ (__printf__, 1, 2), __noreturn__)) | |
48 | static void error(const char *fmt, ...) | |
49 | { | |
50 | va_list pvar; | |
51 | fputs("ERROR: ", stderr); | |
52 | va_start(pvar, fmt); | |
53 | vfprintf(stderr, fmt, pvar); | |
54 | va_end(pvar); | |
55 | fputc('\n', stderr); | |
56 | exit(EXIT_FAILURE); | |
57 | } | |
58 | ||
59 | /* Big-endian */ | |
60 | static void encode_int(unsigned char *to, unsigned int from) | |
61 | { | |
62 | to[3] = from & 0xFF; | |
63 | from >>= 8; | |
64 | to[2] = from & 0xFF; | |
65 | from >>= 8; | |
66 | to[1] = from & 0xFF; | |
67 | from >>= 8; | |
68 | to[0] = from & 0xFF; | |
69 | } | |
70 | ||
71 | static void encode_string(char *to, const char *from, size_t length) | |
72 | { | |
73 | strncpy(to, from, length); | |
74 | } | |
75 | ||
76 | static void encode_license(license_raw *to, const license_struct *from) | |
77 | { | |
78 | memset(to, 0, sizeof(*to)); | |
79 | encode_int(to->unique_id, from->unique_id); | |
80 | encode_string(to->licensee_name, from->licensee_name, | |
81 | sizeof(to->licensee_name)); | |
82 | encode_string(to->licensee_email, from->licensee_email, | |
83 | sizeof(to->licensee_email)); | |
84 | encode_string(to->licensee_company, from->licensee_company, | |
85 | sizeof(to->licensee_company)); | |
86 | encode_string(to->licensee_department, from->licensee_department, | |
87 | sizeof(to->licensee_department)); | |
88 | encode_int(to->valid_from, from->valid_from); | |
89 | encode_int(to->valid_until, from->valid_until); | |
90 | encode_int(to->host_id, from->host_id); | |
91 | encode_string(to->login_name, from->login_name, sizeof(to->login_name)); | |
92 | encode_int(to->from_major, from->from_major); | |
93 | encode_int(to->from_minor, from->from_minor); | |
94 | encode_int(to->from_patchlevel, from->from_patchlevel); | |
95 | encode_int(to->to_major, from->to_major); | |
96 | encode_int(to->to_minor, from->to_minor); | |
97 | encode_int(to->to_patchlevel, from->to_patchlevel); | |
98 | encode_int(to->feature_list, from->feature_list); | |
99 | encode_int(to->limitation_type, from->limitation_type); | |
100 | encode_int(to->max_ptcs, from->max_ptcs); | |
101 | } | |
102 | ||
103 | static void sign_license(license_raw *lptr, const char *dsa_key_file) | |
104 | { | |
105 | unsigned char message_digest[20]; | |
106 | SHA_CTX sha_ctx; | |
107 | unsigned int signature_len = sizeof(lptr->dsa_signature); | |
108 | DSA *dsa; | |
109 | ||
110 | FILE *fp = fopen(dsa_key_file, "r"); | |
111 | if (fp == NULL) { | |
112 | error("Cannot open DSA private key file `%s' for reading: %s", | |
113 | dsa_key_file, strerror(errno)); | |
114 | } | |
115 | ||
116 | dsa = PEM_read_DSAPrivateKey(fp, NULL, NULL, NULL); | |
117 | fclose(fp); | |
118 | ||
119 | if (dsa == NULL) { | |
120 | error("Cannot read DSA private key from `%s': %s", | |
121 | dsa_key_file, ERR_error_string(ERR_get_error(), NULL)); | |
122 | } | |
123 | ||
124 | SHA1_Init(&sha_ctx); | |
125 | SHA1_Update(&sha_ctx, lptr, sizeof(*lptr) - sizeof(lptr->dsa_signature)); | |
126 | SHA1_Final(message_digest, &sha_ctx); | |
127 | ||
128 | if ((int)signature_len != DSA_size(dsa)) { | |
129 | error("Invalid DSA signature size: %d", DSA_size(dsa)); | |
130 | } | |
131 | ||
132 | if (!DSA_sign(0, message_digest, sizeof(message_digest), | |
133 | lptr->dsa_signature, &signature_len, dsa)) { | |
134 | error("DSA signature generation failed: %s", | |
135 | ERR_error_string(ERR_get_error(), NULL)); | |
136 | } | |
137 | ||
138 | DSA_free(dsa); | |
139 | } | |
140 | ||
141 | static void write_license(const char *file_name, const license_raw *lptr) | |
142 | { | |
143 | FILE *fp = fopen(file_name, "w"); | |
144 | if (fp == NULL) { | |
145 | error("Cannot open license file `%s' for writing: %s", file_name, | |
146 | strerror(errno)); | |
147 | } | |
148 | if (!PEM_write(fp, "TTCN-3 LICENSE FILE", "", (unsigned char *)lptr, | |
149 | sizeof(*lptr))) { | |
150 | error("Writing to license file `%s' failed: %s", file_name, | |
151 | ERR_error_string(ERR_get_error(), NULL)); | |
152 | } | |
153 | fclose(fp); | |
154 | } | |
155 | ||
156 | static int privileged_user = 0; | |
157 | static uid_t my_uid = -1; | |
158 | ||
159 | static void check_user(void) | |
160 | { | |
161 | if (geteuid() != 45719) { | |
162 | error("This program must have set-uid to user etccadmi1 (uid 45719)"); | |
163 | } | |
164 | my_uid = getuid(); | |
165 | switch (my_uid) { | |
166 | case 45719: /* etccadmi1 */ | |
167 | privileged_user = 1; | |
168 | case 34217: /* ethjra */ | |
169 | case 34385: /* ethgasz */ | |
170 | break; | |
171 | default: | |
172 | error("You are not allowed to use this program"); | |
173 | } | |
174 | } | |
175 | ||
176 | static void connect_database(MYSQL *mysql) | |
177 | { | |
178 | if (!mysql_init(mysql)) { | |
179 | error("MySQL structure initialization failed"); | |
180 | } | |
181 | if (!mysql_real_connect(mysql, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, | |
182 | MYSQL_DATABASE, 0, NULL, 0)) { | |
183 | error("MySQL database connection failed: %s", mysql_error(mysql)); | |
184 | } else { | |
185 | fputs("Connected to MySQL database.\n", stderr); | |
186 | } | |
187 | } | |
188 | ||
189 | static void disconnect_database(MYSQL *mysql) | |
190 | { | |
191 | mysql_close(mysql); | |
192 | fputs("Disconnected from MySQL database.\n", stderr); | |
193 | } | |
194 | ||
195 | static void fill_from_database_c(MYSQL *mysql, license_struct *plic, int unique_id) | |
196 | { | |
197 | MYSQL_RES *result; | |
198 | my_ulonglong num_rows; | |
199 | unsigned int i, num_fields; | |
200 | MYSQL_FIELD *fields; | |
201 | MYSQL_ROW row; | |
202 | time_t current_time = time(NULL); | |
203 | char *query = mprintf("SELECT * FROM licenses WHERE unique_id = %d", unique_id); | |
204 | if (mysql_query(mysql, query)) { | |
205 | error("Execution of MySQL query `%s' failed: %s", query, | |
206 | mysql_error(mysql)); | |
207 | } | |
208 | Free(query); | |
209 | ||
210 | result = mysql_store_result(mysql); | |
211 | if (result == NULL) { | |
212 | error("MySQL query result fetching failed: %s", mysql_error(mysql)); | |
213 | } | |
214 | ||
215 | num_rows = mysql_num_rows(result); | |
216 | if (num_rows <= 0) { | |
217 | error("There is no license in the database with unique id %d", | |
218 | unique_id); | |
219 | } else if (num_rows > 1) { | |
220 | error("There are %llu licenses in the database with unique id %d", | |
221 | num_rows, unique_id); | |
222 | } | |
223 | ||
224 | num_fields = mysql_num_fields(result); | |
225 | fields = mysql_fetch_fields(result); | |
226 | row = mysql_fetch_row(result); | |
227 | ||
228 | fprintf(stderr, "License data was fetched for unique id %d.\n", unique_id); | |
229 | ||
230 | for (i = 0; i < num_fields; i++) { | |
231 | const char *field_name = fields[i].name; | |
232 | if (!strcmp(field_name, "unique_id")) { | |
233 | plic->unique_id = atoi(row[i]); | |
234 | } else if (!strcmp(field_name, "licensee_name")) { | |
235 | plic->licensee_name = row[i] != NULL ? row[i] : ""; | |
236 | } else if (!strcmp(field_name, "licensee_email")) { | |
237 | plic->licensee_email = row[i] != NULL ? row[i] : ""; | |
238 | } else if (!strcmp(field_name, "contact_name")) { | |
239 | plic->contact_name = row[i] != NULL ? row[i] : ""; | |
240 | } else if (!strcmp(field_name, "contact_email")) { | |
241 | plic->contact_email = row[i] != NULL ? row[i] : ""; | |
242 | } else if (!strcmp(field_name, "send_to")) { | |
243 | if (!strcmp(row[i], "Contact")) plic->send_to = SENDTO_CONTACT; | |
244 | else if (!strcmp(row[i], "Both")) plic->send_to = SENDTO_BOTH; | |
245 | else /*if (!strcmp(row[i], "Licensee"))*/ plic->send_to = SENDTO_LICENSEE; | |
246 | /* SENDTO_LICENSEE is the default */ | |
247 | } else if (!strcmp(field_name, "licensee_company")) { | |
248 | plic->licensee_company = row[i] != NULL ? row[i] : ""; | |
249 | } else if (!strcmp(field_name, "licensee_department")) { | |
250 | plic->licensee_department = row[i] != NULL ? row[i] : ""; | |
251 | } else if (!strcmp(field_name, "valid_from")) { | |
252 | int year, month, day; | |
253 | struct tm tm_struct; | |
254 | if (sscanf(row[i], "%4d-%2d-%2d", &year, &month, &day) != 3) { | |
255 | error("Invalid date format: `%s'", row[i]); | |
256 | } | |
257 | tm_struct.tm_year = year - 1900; | |
258 | tm_struct.tm_mon = month - 1; | |
259 | tm_struct.tm_mday = day; | |
260 | tm_struct.tm_hour = 0; | |
261 | tm_struct.tm_min = 0; | |
262 | tm_struct.tm_sec = 0; | |
263 | tm_struct.tm_isdst = -1; | |
264 | plic->valid_from = mktime(&tm_struct); | |
265 | } else if (!strcmp(field_name, "valid_until")) { | |
266 | int year, month, day; | |
267 | struct tm tm_struct; | |
268 | if (sscanf(row[i], "%4d-%2d-%2d", &year, &month, &day) != 3) { | |
269 | error("Invalid date format: `%s'", row[i]); | |
270 | } | |
271 | tm_struct.tm_year = year - 1900; | |
272 | tm_struct.tm_mon = month - 1; | |
273 | tm_struct.tm_mday = day; | |
274 | tm_struct.tm_hour = 23; | |
275 | tm_struct.tm_min = 59; | |
276 | tm_struct.tm_sec = 59; | |
277 | tm_struct.tm_isdst = -1; | |
278 | plic->valid_until = mktime(&tm_struct); | |
279 | } else if (!strcmp(field_name, "host_id")) { | |
280 | if (row[i] == NULL || sscanf(row[i], "%lx", &plic->host_id) != 1) | |
281 | plic->host_id = 0; | |
282 | } else if (!strcmp(field_name, "login_name")) { | |
283 | plic->login_name = row[i] != NULL ? row[i] : ""; | |
284 | } else if (!strcmp(field_name, "from_major")) { | |
285 | plic->from_major = atoi(row[i]); | |
286 | } else if (!strcmp(field_name, "from_minor")) { | |
287 | plic->from_minor = atoi(row[i]); | |
288 | } else if (!strcmp(field_name, "from_patchlevel")) { | |
289 | plic->from_patchlevel = atoi(row[i]); | |
290 | } else if (!strcmp(field_name, "to_major")) { | |
291 | plic->to_major = atoi(row[i]); | |
292 | } else if (!strcmp(field_name, "to_minor")) { | |
293 | plic->to_minor = atoi(row[i]); | |
294 | } else if (!strcmp(field_name, "to_patchlevel")) { | |
295 | plic->to_patchlevel = atoi(row[i]); | |
296 | } else if (!strcmp(field_name, "feature_ttcn3")) { | |
297 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_TTCN3; | |
298 | } else if (!strcmp(field_name, "feature_asn1")) { | |
299 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_ASN1; | |
300 | } else if (!strcmp(field_name, "feature_codegen")) { | |
301 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_CODEGEN; | |
302 | } else if (!strcmp(field_name, "feature_raw")) { | |
303 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_RAW; | |
304 | } else if (!strcmp(field_name, "feature_text")) { | |
305 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_TEXT; | |
306 | } else if (!strcmp(field_name, "feature_ber")) { | |
307 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_BER; | |
308 | } else if (!strcmp(field_name, "feature_per")) { | |
309 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_PER; | |
310 | } else if (!strcmp(field_name, "feature_xer")) { | |
311 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_XER; | |
312 | } else if (!strcmp(field_name, "feature_tpgen")) { | |
313 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_TPGEN; | |
314 | } else if (!strcmp(field_name, "feature_single")) { | |
315 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_SINGLE; | |
316 | } else if (!strcmp(field_name, "feature_mctr")) { | |
317 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_MCTR; | |
318 | } else if (!strcmp(field_name, "feature_hc")) { | |
319 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_HC; | |
320 | } else if (!strcmp(field_name, "feature_logformat")) { | |
321 | if (!strcmp(row[i], "Yes")) plic->feature_list |= FEATURE_LOGFORMAT; | |
322 | } else if (!strcmp(field_name, "limit_host")) { | |
323 | if (!strcmp(row[i], "Yes")) plic->limitation_type |= LIMIT_HOST; | |
324 | } else if (!strcmp(field_name, "limit_user")) { | |
325 | if (!strcmp(row[i], "Yes")) plic->limitation_type |= LIMIT_USER; | |
326 | } else if (!strcmp(field_name, "max_ptcs")) { | |
327 | plic->max_ptcs = atoi(row[i]); | |
328 | } | |
329 | } /* next */ | |
330 | ||
331 | if (plic->valid_from > current_time) { | |
332 | error("The beginning of validity is in the future: %s", | |
333 | ctime(&plic->valid_from)); | |
334 | } | |
335 | ||
336 | if (plic->valid_until < current_time) { | |
337 | error("The license has already expired on %s", | |
338 | ctime(&plic->valid_until)); | |
339 | } else if (plic->valid_until < current_time + SECS_IN_DAY) { | |
340 | error("The license is valid for less than one day"); | |
341 | } else if (plic->valid_until > current_time + 380 * SECS_IN_DAY && | |
342 | !privileged_user) { | |
343 | error("You are not authorized to generate a license that is valid for " | |
344 | "more than one year (%ld days)", | |
345 | (plic->valid_until - current_time) / SECS_IN_DAY); | |
346 | } | |
347 | ||
348 | if (plic->limitation_type & LIMIT_HOST && plic->host_id == 0) { | |
349 | error("Cannot generate HOST limited license for zero host ID"); | |
350 | } | |
351 | ||
352 | if (plic->limitation_type & LIMIT_USER && !strcmp(plic->login_name, "")) { | |
353 | error("Cannot generate USER limited license for empty login name"); | |
354 | } | |
355 | ||
356 | if (plic->limitation_type == 0 && !privileged_user) { | |
357 | error("You are not authorized to generate unrestricted licenses"); | |
358 | } | |
359 | mysql_free_result(result); | |
360 | } | |
361 | ||
362 | static void fill_from_database(MYSQL *mysql, license_raw *lraw, int unique_id) | |
363 | { | |
364 | ||
365 | license_struct lstr; | |
366 | memset(&lstr, 0, sizeof(lstr)); | |
367 | ||
368 | fill_from_database_c(mysql, &lstr, unique_id); | |
369 | ||
370 | encode_license(lraw, &lstr); | |
371 | ||
372 | } | |
373 | ||
374 | static const char *get_email_address(void) | |
375 | { | |
376 | switch (my_uid) { | |
377 | case 34217: /* ethjra */ | |
378 | return "Julianna.Rozsa@ericsson.com"; | |
379 | case 34385: /* ethgasz */ | |
380 | return "Gabor.Szalai@ericsson.com"; | |
381 | case 45719: /* etccadmi1 */ | |
382 | return "Julianna.Rozsa@ericsson.com"; | |
383 | default: | |
384 | return "???"; | |
385 | } | |
386 | } | |
387 | ||
388 | static const char *get_first_name(void) | |
389 | { | |
390 | switch (my_uid) { | |
391 | case 34217: /* ethjra */ | |
392 | return "Julianna"; | |
393 | case 34385: /* ethgasz */ | |
d44e3c4f | 394 | return "Gábor"; |
970ed795 EL |
395 | case 45719: /* etccadmi1 */ |
396 | return "Admin"; | |
397 | default: | |
398 | return "???"; | |
399 | } | |
400 | } | |
401 | ||
402 | static const char *get_email_signature(void) | |
403 | { | |
404 | switch (my_uid) { | |
405 | case 34217: /* ethjra */ | |
406 | return | |
d44e3c4f | 407 | "Julianna Rózsa Ericsson Hungary Ltd.\n" |
408 | "Configuration Manager H-1117 Budapest, Irinyi József u.4-20.\n" | |
970ed795 EL |
409 | "Test Competence Center Phone: +36 1 437 7895\n" |
410 | "Julianna.Rozsa@ericsson.com Fax: +36 1 439 5176\n"; | |
411 | case 34385: /* ethgasz */ | |
412 | return | |
d44e3c4f | 413 | "Gábor Szalai Gabor.Szalai@ericsson.com\n" |
970ed795 EL |
414 | "Test Competence Center Tel: +36-1-437-7591\n" |
415 | "Ericsson Telecommunications Ltd. Fax: +36-1-439-5176\n" | |
416 | "H-1037 Budapest, Laborc u. 1., Hungary Mob: +36-30-743-7669\n" | |
417 | "Intranet: http://ttcn.ericsson.se/ ECN: 831-7591\n"; | |
418 | case 45719: /* etccadmi1 */ | |
419 | return | |
420 | "TCC License Administrator Julianna.Rozsa@ericsson.com\n" | |
421 | "Test Competence Center \n" | |
422 | "Ericsson Telecommunications Ltd. Fax: +36-1-439-5176\n" | |
423 | "H-1037 Budapest, Laborc u. 1., Hungary \n" | |
424 | "Intranet: http://ttcn.ericsson.se/ \n"; | |
425 | default: | |
426 | return ""; | |
427 | } | |
428 | } | |
429 | ||
430 | static void mail_license(const license_struct *lstr, const license_raw *lptr) | |
431 | { | |
432 | /* administrator's email address */ | |
433 | const char *email_addr; | |
434 | /* licensee's email address, or empty if sent only to contact */ | |
435 | const char *maybe_licensee_email = (SENDTO_CONTACT != lstr->send_to) ? lstr->licensee_email : ""; | |
436 | /* contact's email address, or empty if sent only to licensee */ | |
437 | const char *maybe_contact_email = (SENDTO_LICENSEE != lstr->send_to) ? lstr->contact_email : ""; | |
438 | char *sendmail_cmd, *first_name, *mime_boundary; | |
439 | FILE *fp; | |
440 | size_t i; | |
441 | time_t current_time; | |
442 | struct tm *formatted_time; | |
443 | int return_status; | |
444 | ||
445 | email_addr = get_email_address(); | |
446 | ||
447 | sendmail_cmd = mprintf("/usr/lib/sendmail %s %s %s", maybe_licensee_email, maybe_contact_email, | |
448 | email_addr); | |
449 | fp = popen(sendmail_cmd, "w"); | |
450 | Free(sendmail_cmd); | |
451 | if (fp == NULL) error("Cannot mail license: %s", strerror(errno)); | |
452 | ||
453 | first_name = memptystr(); | |
454 | for (i = 0; lstr->licensee_name[i] != '\0'; i++) { | |
455 | if (lstr->licensee_name[i] == ' ') { | |
456 | if (first_name[0] != '\0') break; | |
457 | } else first_name = mputc(first_name, lstr->licensee_name[i]); | |
458 | } | |
459 | mime_boundary = mcopystr("__"); | |
460 | for (i = 0; i < 16; i++) { | |
461 | unsigned char uc; | |
462 | if (!RAND_pseudo_bytes(&uc, 1)) error("Random number generation " | |
463 | "failed: %s", ERR_error_string(ERR_get_error(), NULL)); | |
464 | mime_boundary = mputprintf(mime_boundary, "%02X", uc); | |
465 | } | |
466 | mime_boundary = mputstr(mime_boundary, "__"); | |
467 | ||
468 | fprintf(fp, "From: TTCN-3 License Generator <%s>\n" | |
469 | "To: %s <%s>\n" | |
470 | "Subject: TTCN-3 license key\n" | |
471 | "MIME-Version: 1.0\n" | |
472 | "Content-Type: multipart/mixed; boundary=\"%s\"\n" | |
473 | "\n" | |
474 | "This is a multi-part message in MIME format.\n" | |
475 | "--%s\n" | |
476 | "Content-Type: text/plain; charset=ISO-8859-1\n" | |
477 | "\n" | |
478 | "Dear %s,\n" | |
479 | "\n", email_addr, lstr->licensee_name, lstr->licensee_email, | |
480 | mime_boundary, mime_boundary, first_name); | |
481 | Free(first_name); | |
482 | ||
483 | current_time = time(NULL); | |
484 | formatted_time = localtime(&lstr->valid_until); | |
485 | if (formatted_time == NULL) { | |
486 | error("Cannot format time: %s", strerror(errno)); | |
487 | } | |
488 | if (current_time - lstr->valid_from < SECS_IN_DAY) { | |
489 | fprintf(fp, "this is your license key for the TTCN-3 " | |
490 | "Test Executor. Please save the entire attachment " | |
491 | "(including the header and trailing lines) and " | |
492 | "follow the instructions of the Installation Guide " | |
493 | "(Section 4.1.1) to proceed with the installation.\n" | |
494 | "\n" | |
495 | "The Unique ID of your license key is %d. Please refer to " | |
496 | "this number if you have any licensing-related problems.\n" | |
497 | "\n" | |
498 | "The license key is valid till %04d-%02d-%02d beginning from today.\n" | |
499 | "\n" | |
500 | "Do not hesitate to contact us if you have any questions about " | |
501 | "the TTCN-3 language or the test executor.\n", lstr->unique_id, | |
502 | formatted_time->tm_year + 1900, formatted_time->tm_mon + 1, | |
503 | formatted_time->tm_mday); | |
504 | } else { | |
505 | fprintf(fp, "your existing license key with Unique ID %d has been " | |
506 | "prolonged so that it will expire on %04d-%02d-%02d. " | |
507 | "Please find the updated license file in the attachment. " | |
508 | "The only thing you have to do is to replace your old " | |
509 | "license file with this one.\n", lstr->unique_id, | |
510 | formatted_time->tm_year + 1900, formatted_time->tm_mon + 1, | |
511 | formatted_time->tm_mday); | |
512 | } | |
513 | fprintf(fp, "\n" | |
514 | "With best regards,\n" | |
515 | "%s\n" | |
516 | "\n" | |
517 | "PS: This is an automatically generated e-mail, please reply to its " | |
518 | "sender in case of problems!\n" | |
519 | "\n", get_first_name()); | |
520 | if (SENDTO_CONTACT == lstr->send_to) { | |
521 | fprintf (stderr, "%s, please forward this email to %s (%s)\n\n", | |
522 | lstr->contact_name, lstr->licensee_name, lstr->licensee_email); | |
523 | } | |
524 | fprintf(fp, "--\n" | |
525 | "%s" | |
526 | "--%s\n" | |
527 | "Content-Type: application/octet-stream\n" | |
528 | "Content-Transfer-Encoding: 7bit\n" | |
529 | "Content-Disposition: attachment; filename=\"license_%d.dat\"\n" | |
530 | "\n", get_email_signature(), mime_boundary, | |
531 | lstr->unique_id); | |
532 | if (!PEM_write(fp, "TTCN-3 LICENSE FILE", "", (unsigned char*)lptr, | |
533 | sizeof(*lptr))) { | |
534 | error("Attaching license file failed: %s", | |
535 | ERR_error_string(ERR_get_error(), NULL)); | |
536 | } | |
537 | fprintf(fp, "\n" | |
538 | "--%s--\n", mime_boundary); | |
539 | Free(mime_boundary); | |
540 | return_status = pclose(fp); | |
541 | if (!WIFEXITED(return_status) || | |
542 | WEXITSTATUS(return_status) != EXIT_SUCCESS) { | |
543 | error("Sendmail invocation failed"); | |
544 | } | |
545 | } | |
546 | ||
547 | static int get_unique_id(const char *str) | |
548 | { | |
549 | int unique_id = atoi(str); | |
550 | if (unique_id <= 0) { | |
551 | error("Invalid unique id: %s", str); | |
552 | } | |
553 | return unique_id; | |
554 | } | |
555 | ||
556 | int main(int argc, char *argv[]) | |
557 | { | |
558 | license_struct lstr; | |
559 | license_raw lraw; | |
560 | char *file_name; | |
561 | int unique_id; | |
562 | MYSQL mysql; | |
563 | int send_email; | |
564 | ||
565 | fputs("License generator for the TTCN-3 Test Executor.\n", stderr); | |
566 | check_user(); | |
567 | ||
568 | switch (argc) { | |
569 | case 2: | |
570 | unique_id = get_unique_id(argv[1]); | |
571 | send_email = 0; | |
572 | break; | |
573 | case 3: | |
574 | if (!strcmp(argv[1], "-m")) { | |
575 | unique_id = get_unique_id(argv[2]); | |
576 | send_email = 1; | |
577 | break; | |
578 | } | |
579 | /* no break */ | |
580 | default: | |
581 | error("Usage: %s [-m] unique_id", argv[0]); | |
582 | } | |
583 | ||
584 | init_openssl(); | |
585 | ||
586 | connect_database(&mysql); | |
587 | fill_from_database(&mysql, &lraw, unique_id); | |
588 | disconnect_database(&mysql); | |
589 | ||
590 | sign_license(&lraw, PRIVATE_KEY); | |
591 | ||
592 | file_name = mprintf(LICENSE_DIR "/license_%d.dat", unique_id); | |
593 | write_license(file_name, &lraw); | |
594 | fprintf(stderr, "License file %s was generated.\n", file_name); | |
595 | ||
596 | fputs("License information:\n", stderr); | |
597 | load_license_from_file(&lstr, file_name); | |
598 | Free(file_name); | |
599 | print_license(&lstr); | |
600 | if (send_email) { | |
601 | license_struct lstr2; | |
602 | connect_database(&mysql); | |
603 | fill_from_database_c(&mysql, &lstr2, unique_id); | |
604 | disconnect_database(&mysql); | |
605 | mail_license(&lstr2, &lraw); | |
606 | fputs("E-mail was sent.\n", stderr); | |
607 | /* do not free_license(lstr2) */ | |
608 | } | |
609 | free_openssl(); | |
610 | free_license(&lstr); | |
611 | check_mem_leak(argv[0]); | |
612 | ||
613 | return EXIT_SUCCESS; | |
614 | } |