Merge pull request #66 from BenceJanosSzabo/master
[deliverable/titan.core.git] / licensegen / license_gen.c
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 ******************************************************************************/
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 */
394 return "Gábor";
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
407 "Julianna Rózsa Ericsson Hungary Ltd.\n"
408 "Configuration Manager H-1117 Budapest, Irinyi József u.4-20.\n"
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
413 "Gábor Szalai Gabor.Szalai@ericsson.com\n"
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 }
This page took 0.044516 seconds and 5 git commands to generate.