b02c610903bae329e0d7c9039cba77c93be27258
1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2014 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 ///////////////////////////////////////////////////////////////////////////////
13 #include <sys/types.h>
19 #include <openssl/rand.h>
20 #include <openssl/sha.h>
21 #include <openssl/dsa.h>
22 #include <openssl/pem.h>
23 #include <openssl/err.h>
25 #include "../common/memory.h"
26 #include "../common/license.h"
28 #define MYSQL_HOST "mwlx122.eth.ericsson.se"
29 #define MYSQL_USER "ttcn3"
30 #define MYSQL_PASSWORD "ttcn3"
31 #define MYSQL_DATABASE "ttcn3"
33 #define LICENSE_DIR "/mnt/TTCN/license"
34 #define PRIVATE_KEY LICENSE_DIR "/key.pem"
36 #define SECS_IN_DAY 86400
38 __attribute__ ((__format__ (__printf__
, 1, 2), __noreturn__
))
39 static void error(const char *fmt
, ...)
42 fputs("ERROR: ", stderr
);
44 vfprintf(stderr
, fmt
, pvar
);
51 static void encode_int(unsigned char *to
, unsigned int from
)
62 static void encode_string(char *to
, const char *from
, size_t length
)
64 strncpy(to
, from
, length
);
67 static void encode_license(license_raw
*to
, const license_struct
*from
)
69 memset(to
, 0, sizeof(*to
));
70 encode_int(to
->unique_id
, from
->unique_id
);
71 encode_string(to
->licensee_name
, from
->licensee_name
,
72 sizeof(to
->licensee_name
));
73 encode_string(to
->licensee_email
, from
->licensee_email
,
74 sizeof(to
->licensee_email
));
75 encode_string(to
->licensee_company
, from
->licensee_company
,
76 sizeof(to
->licensee_company
));
77 encode_string(to
->licensee_department
, from
->licensee_department
,
78 sizeof(to
->licensee_department
));
79 encode_int(to
->valid_from
, from
->valid_from
);
80 encode_int(to
->valid_until
, from
->valid_until
);
81 encode_int(to
->host_id
, from
->host_id
);
82 encode_string(to
->login_name
, from
->login_name
, sizeof(to
->login_name
));
83 encode_int(to
->from_major
, from
->from_major
);
84 encode_int(to
->from_minor
, from
->from_minor
);
85 encode_int(to
->from_patchlevel
, from
->from_patchlevel
);
86 encode_int(to
->to_major
, from
->to_major
);
87 encode_int(to
->to_minor
, from
->to_minor
);
88 encode_int(to
->to_patchlevel
, from
->to_patchlevel
);
89 encode_int(to
->feature_list
, from
->feature_list
);
90 encode_int(to
->limitation_type
, from
->limitation_type
);
91 encode_int(to
->max_ptcs
, from
->max_ptcs
);
94 static void sign_license(license_raw
*lptr
, const char *dsa_key_file
)
96 unsigned char message_digest
[20];
98 unsigned int signature_len
= sizeof(lptr
->dsa_signature
);
101 FILE *fp
= fopen(dsa_key_file
, "r");
103 error("Cannot open DSA private key file `%s' for reading: %s",
104 dsa_key_file
, strerror(errno
));
107 dsa
= PEM_read_DSAPrivateKey(fp
, NULL
, NULL
, NULL
);
111 error("Cannot read DSA private key from `%s': %s",
112 dsa_key_file
, ERR_error_string(ERR_get_error(), NULL
));
116 SHA1_Update(&sha_ctx
, lptr
, sizeof(*lptr
) - sizeof(lptr
->dsa_signature
));
117 SHA1_Final(message_digest
, &sha_ctx
);
119 if ((int)signature_len
!= DSA_size(dsa
)) {
120 error("Invalid DSA signature size: %d", DSA_size(dsa
));
123 if (!DSA_sign(0, message_digest
, sizeof(message_digest
),
124 lptr
->dsa_signature
, &signature_len
, dsa
)) {
125 error("DSA signature generation failed: %s",
126 ERR_error_string(ERR_get_error(), NULL
));
132 static void write_license(const char *file_name
, const license_raw
*lptr
)
134 FILE *fp
= fopen(file_name
, "w");
136 error("Cannot open license file `%s' for writing: %s", file_name
,
139 if (!PEM_write(fp
, "TTCN-3 LICENSE FILE", "", (unsigned char *)lptr
,
141 error("Writing to license file `%s' failed: %s", file_name
,
142 ERR_error_string(ERR_get_error(), NULL
));
147 static int privileged_user
= 0;
148 static uid_t my_uid
= -1;
150 static void check_user(void)
152 if (geteuid() != 45719) {
153 error("This program must have set-uid to user etccadmi1 (uid 45719)");
157 case 45719: /* etccadmi1 */
159 case 34217: /* ethjra */
160 case 34385: /* ethgasz */
163 error("You are not allowed to use this program");
167 static void connect_database(MYSQL
*mysql
)
169 if (!mysql_init(mysql
)) {
170 error("MySQL structure initialization failed");
172 if (!mysql_real_connect(mysql
, MYSQL_HOST
, MYSQL_USER
, MYSQL_PASSWORD
,
173 MYSQL_DATABASE
, 0, NULL
, 0)) {
174 error("MySQL database connection failed: %s", mysql_error(mysql
));
176 fputs("Connected to MySQL database.\n", stderr
);
180 static void disconnect_database(MYSQL
*mysql
)
183 fputs("Disconnected from MySQL database.\n", stderr
);
186 static void fill_from_database_c(MYSQL
*mysql
, license_struct
*plic
, int unique_id
)
189 my_ulonglong num_rows
;
190 unsigned int i
, num_fields
;
193 time_t current_time
= time(NULL
);
194 char *query
= mprintf("SELECT * FROM licenses WHERE unique_id = %d", unique_id
);
195 if (mysql_query(mysql
, query
)) {
196 error("Execution of MySQL query `%s' failed: %s", query
,
201 result
= mysql_store_result(mysql
);
202 if (result
== NULL
) {
203 error("MySQL query result fetching failed: %s", mysql_error(mysql
));
206 num_rows
= mysql_num_rows(result
);
208 error("There is no license in the database with unique id %d",
210 } else if (num_rows
> 1) {
211 error("There are %llu licenses in the database with unique id %d",
212 num_rows
, unique_id
);
215 num_fields
= mysql_num_fields(result
);
216 fields
= mysql_fetch_fields(result
);
217 row
= mysql_fetch_row(result
);
219 fprintf(stderr
, "License data was fetched for unique id %d.\n", unique_id
);
221 for (i
= 0; i
< num_fields
; i
++) {
222 const char *field_name
= fields
[i
].name
;
223 if (!strcmp(field_name
, "unique_id")) {
224 plic
->unique_id
= atoi(row
[i
]);
225 } else if (!strcmp(field_name
, "licensee_name")) {
226 plic
->licensee_name
= row
[i
] != NULL
? row
[i
] : "";
227 } else if (!strcmp(field_name
, "licensee_email")) {
228 plic
->licensee_email
= row
[i
] != NULL
? row
[i
] : "";
229 } else if (!strcmp(field_name
, "contact_name")) {
230 plic
->contact_name
= row
[i
] != NULL
? row
[i
] : "";
231 } else if (!strcmp(field_name
, "contact_email")) {
232 plic
->contact_email
= row
[i
] != NULL
? row
[i
] : "";
233 } else if (!strcmp(field_name
, "send_to")) {
234 if (!strcmp(row
[i
], "Contact")) plic
->send_to
= SENDTO_CONTACT
;
235 else if (!strcmp(row
[i
], "Both")) plic
->send_to
= SENDTO_BOTH
;
236 else /*if (!strcmp(row[i], "Licensee"))*/ plic
->send_to
= SENDTO_LICENSEE
;
237 /* SENDTO_LICENSEE is the default */
238 } else if (!strcmp(field_name
, "licensee_company")) {
239 plic
->licensee_company
= row
[i
] != NULL
? row
[i
] : "";
240 } else if (!strcmp(field_name
, "licensee_department")) {
241 plic
->licensee_department
= row
[i
] != NULL
? row
[i
] : "";
242 } else if (!strcmp(field_name
, "valid_from")) {
243 int year
, month
, day
;
245 if (sscanf(row
[i
], "%4d-%2d-%2d", &year
, &month
, &day
) != 3) {
246 error("Invalid date format: `%s'", row
[i
]);
248 tm_struct
.tm_year
= year
- 1900;
249 tm_struct
.tm_mon
= month
- 1;
250 tm_struct
.tm_mday
= day
;
251 tm_struct
.tm_hour
= 0;
252 tm_struct
.tm_min
= 0;
253 tm_struct
.tm_sec
= 0;
254 tm_struct
.tm_isdst
= -1;
255 plic
->valid_from
= mktime(&tm_struct
);
256 } else if (!strcmp(field_name
, "valid_until")) {
257 int year
, month
, day
;
259 if (sscanf(row
[i
], "%4d-%2d-%2d", &year
, &month
, &day
) != 3) {
260 error("Invalid date format: `%s'", row
[i
]);
262 tm_struct
.tm_year
= year
- 1900;
263 tm_struct
.tm_mon
= month
- 1;
264 tm_struct
.tm_mday
= day
;
265 tm_struct
.tm_hour
= 23;
266 tm_struct
.tm_min
= 59;
267 tm_struct
.tm_sec
= 59;
268 tm_struct
.tm_isdst
= -1;
269 plic
->valid_until
= mktime(&tm_struct
);
270 } else if (!strcmp(field_name
, "host_id")) {
271 if (row
[i
] == NULL
|| sscanf(row
[i
], "%lx", &plic
->host_id
) != 1)
273 } else if (!strcmp(field_name
, "login_name")) {
274 plic
->login_name
= row
[i
] != NULL
? row
[i
] : "";
275 } else if (!strcmp(field_name
, "from_major")) {
276 plic
->from_major
= atoi(row
[i
]);
277 } else if (!strcmp(field_name
, "from_minor")) {
278 plic
->from_minor
= atoi(row
[i
]);
279 } else if (!strcmp(field_name
, "from_patchlevel")) {
280 plic
->from_patchlevel
= atoi(row
[i
]);
281 } else if (!strcmp(field_name
, "to_major")) {
282 plic
->to_major
= atoi(row
[i
]);
283 } else if (!strcmp(field_name
, "to_minor")) {
284 plic
->to_minor
= atoi(row
[i
]);
285 } else if (!strcmp(field_name
, "to_patchlevel")) {
286 plic
->to_patchlevel
= atoi(row
[i
]);
287 } else if (!strcmp(field_name
, "feature_ttcn3")) {
288 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_TTCN3
;
289 } else if (!strcmp(field_name
, "feature_asn1")) {
290 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_ASN1
;
291 } else if (!strcmp(field_name
, "feature_codegen")) {
292 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_CODEGEN
;
293 } else if (!strcmp(field_name
, "feature_raw")) {
294 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_RAW
;
295 } else if (!strcmp(field_name
, "feature_text")) {
296 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_TEXT
;
297 } else if (!strcmp(field_name
, "feature_ber")) {
298 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_BER
;
299 } else if (!strcmp(field_name
, "feature_per")) {
300 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_PER
;
301 } else if (!strcmp(field_name
, "feature_xer")) {
302 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_XER
;
303 } else if (!strcmp(field_name
, "feature_tpgen")) {
304 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_TPGEN
;
305 } else if (!strcmp(field_name
, "feature_single")) {
306 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_SINGLE
;
307 } else if (!strcmp(field_name
, "feature_mctr")) {
308 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_MCTR
;
309 } else if (!strcmp(field_name
, "feature_hc")) {
310 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_HC
;
311 } else if (!strcmp(field_name
, "feature_logformat")) {
312 if (!strcmp(row
[i
], "Yes")) plic
->feature_list
|= FEATURE_LOGFORMAT
;
313 } else if (!strcmp(field_name
, "limit_host")) {
314 if (!strcmp(row
[i
], "Yes")) plic
->limitation_type
|= LIMIT_HOST
;
315 } else if (!strcmp(field_name
, "limit_user")) {
316 if (!strcmp(row
[i
], "Yes")) plic
->limitation_type
|= LIMIT_USER
;
317 } else if (!strcmp(field_name
, "max_ptcs")) {
318 plic
->max_ptcs
= atoi(row
[i
]);
322 if (plic
->valid_from
> current_time
) {
323 error("The beginning of validity is in the future: %s",
324 ctime(&plic
->valid_from
));
327 if (plic
->valid_until
< current_time
) {
328 error("The license has already expired on %s",
329 ctime(&plic
->valid_until
));
330 } else if (plic
->valid_until
< current_time
+ SECS_IN_DAY
) {
331 error("The license is valid for less than one day");
332 } else if (plic
->valid_until
> current_time
+ 380 * SECS_IN_DAY
&&
334 error("You are not authorized to generate a license that is valid for "
335 "more than one year (%ld days)",
336 (plic
->valid_until
- current_time
) / SECS_IN_DAY
);
339 if (plic
->limitation_type
& LIMIT_HOST
&& plic
->host_id
== 0) {
340 error("Cannot generate HOST limited license for zero host ID");
343 if (plic
->limitation_type
& LIMIT_USER
&& !strcmp(plic
->login_name
, "")) {
344 error("Cannot generate USER limited license for empty login name");
347 if (plic
->limitation_type
== 0 && !privileged_user
) {
348 error("You are not authorized to generate unrestricted licenses");
350 mysql_free_result(result
);
353 static void fill_from_database(MYSQL
*mysql
, license_raw
*lraw
, int unique_id
)
357 memset(&lstr
, 0, sizeof(lstr
));
359 fill_from_database_c(mysql
, &lstr
, unique_id
);
361 encode_license(lraw
, &lstr
);
365 static const char *get_email_address(void)
368 case 34217: /* ethjra */
369 return "Julianna.Rozsa@ericsson.com";
370 case 34385: /* ethgasz */
371 return "Gabor.Szalai@ericsson.com";
372 case 45719: /* etccadmi1 */
373 return "Julianna.Rozsa@ericsson.com";
379 static const char *get_first_name(void)
382 case 34217: /* ethjra */
384 case 34385: /* ethgasz */
386 case 45719: /* etccadmi1 */
393 static const char *get_email_signature(void)
396 case 34217: /* ethjra */
398 "Julianna Rózsa Ericsson Hungary Ltd.\n"
399 "Configuration Manager H-1117 Budapest, Irinyi József u.4-20.\n"
400 "Test Competence Center Phone: +36 1 437 7895\n"
401 "Julianna.Rozsa@ericsson.com Fax: +36 1 439 5176\n";
402 case 34385: /* ethgasz */
404 "Gábor Szalai Gabor.Szalai@ericsson.com\n"
405 "Test Competence Center Tel: +36-1-437-7591\n"
406 "Ericsson Telecommunications Ltd. Fax: +36-1-439-5176\n"
407 "H-1037 Budapest, Laborc u. 1., Hungary Mob: +36-30-743-7669\n"
408 "Intranet: http://ttcn.ericsson.se/ ECN: 831-7591\n";
409 case 45719: /* etccadmi1 */
411 "TCC License Administrator Julianna.Rozsa@ericsson.com\n"
412 "Test Competence Center \n"
413 "Ericsson Telecommunications Ltd. Fax: +36-1-439-5176\n"
414 "H-1037 Budapest, Laborc u. 1., Hungary \n"
415 "Intranet: http://ttcn.ericsson.se/ \n";
421 static void mail_license(const license_struct
*lstr
, const license_raw
*lptr
)
423 /* administrator's email address */
424 const char *email_addr
;
425 /* licensee's email address, or empty if sent only to contact */
426 const char *maybe_licensee_email
= (SENDTO_CONTACT
!= lstr
->send_to
) ? lstr
->licensee_email
: "";
427 /* contact's email address, or empty if sent only to licensee */
428 const char *maybe_contact_email
= (SENDTO_LICENSEE
!= lstr
->send_to
) ? lstr
->contact_email
: "";
429 char *sendmail_cmd
, *first_name
, *mime_boundary
;
433 struct tm
*formatted_time
;
436 email_addr
= get_email_address();
438 sendmail_cmd
= mprintf("/usr/lib/sendmail %s %s %s", maybe_licensee_email
, maybe_contact_email
,
440 fp
= popen(sendmail_cmd
, "w");
442 if (fp
== NULL
) error("Cannot mail license: %s", strerror(errno
));
444 first_name
= memptystr();
445 for (i
= 0; lstr
->licensee_name
[i
] != '\0'; i
++) {
446 if (lstr
->licensee_name
[i
] == ' ') {
447 if (first_name
[0] != '\0') break;
448 } else first_name
= mputc(first_name
, lstr
->licensee_name
[i
]);
450 mime_boundary
= mcopystr("__");
451 for (i
= 0; i
< 16; i
++) {
453 if (!RAND_pseudo_bytes(&uc
, 1)) error("Random number generation "
454 "failed: %s", ERR_error_string(ERR_get_error(), NULL
));
455 mime_boundary
= mputprintf(mime_boundary
, "%02X", uc
);
457 mime_boundary
= mputstr(mime_boundary
, "__");
459 fprintf(fp
, "From: TTCN-3 License Generator <%s>\n"
461 "Subject: TTCN-3 license key\n"
462 "MIME-Version: 1.0\n"
463 "Content-Type: multipart/mixed; boundary=\"%s\"\n"
465 "This is a multi-part message in MIME format.\n"
467 "Content-Type: text/plain; charset=ISO-8859-1\n"
470 "\n", email_addr
, lstr
->licensee_name
, lstr
->licensee_email
,
471 mime_boundary
, mime_boundary
, first_name
);
474 current_time
= time(NULL
);
475 formatted_time
= localtime(&lstr
->valid_until
);
476 if (formatted_time
== NULL
) {
477 error("Cannot format time: %s", strerror(errno
));
479 if (current_time
- lstr
->valid_from
< SECS_IN_DAY
) {
480 fprintf(fp
, "this is your license key for the TTCN-3 "
481 "Test Executor. Please save the entire attachment "
482 "(including the header and trailing lines) and "
483 "follow the instructions of the Installation Guide "
484 "(Section 4.1.1) to proceed with the installation.\n"
486 "The Unique ID of your license key is %d. Please refer to "
487 "this number if you have any licensing-related problems.\n"
489 "The license key is valid till %04d-%02d-%02d beginning from today.\n"
491 "Do not hesitate to contact us if you have any questions about "
492 "the TTCN-3 language or the test executor.\n", lstr
->unique_id
,
493 formatted_time
->tm_year
+ 1900, formatted_time
->tm_mon
+ 1,
494 formatted_time
->tm_mday
);
496 fprintf(fp
, "your existing license key with Unique ID %d has been "
497 "prolonged so that it will expire on %04d-%02d-%02d. "
498 "Please find the updated license file in the attachment. "
499 "The only thing you have to do is to replace your old "
500 "license file with this one.\n", lstr
->unique_id
,
501 formatted_time
->tm_year
+ 1900, formatted_time
->tm_mon
+ 1,
502 formatted_time
->tm_mday
);
505 "With best regards,\n"
508 "PS: This is an automatically generated e-mail, please reply to its "
509 "sender in case of problems!\n"
510 "\n", get_first_name());
511 if (SENDTO_CONTACT
== lstr
->send_to
) {
512 fprintf (stderr
, "%s, please forward this email to %s (%s)\n\n",
513 lstr
->contact_name
, lstr
->licensee_name
, lstr
->licensee_email
);
518 "Content-Type: application/octet-stream\n"
519 "Content-Transfer-Encoding: 7bit\n"
520 "Content-Disposition: attachment; filename=\"license_%d.dat\"\n"
521 "\n", get_email_signature(), mime_boundary
,
523 if (!PEM_write(fp
, "TTCN-3 LICENSE FILE", "", (unsigned char*)lptr
,
525 error("Attaching license file failed: %s",
526 ERR_error_string(ERR_get_error(), NULL
));
529 "--%s--\n", mime_boundary
);
531 return_status
= pclose(fp
);
532 if (!WIFEXITED(return_status
) ||
533 WEXITSTATUS(return_status
) != EXIT_SUCCESS
) {
534 error("Sendmail invocation failed");
538 static int get_unique_id(const char *str
)
540 int unique_id
= atoi(str
);
541 if (unique_id
<= 0) {
542 error("Invalid unique id: %s", str
);
547 int main(int argc
, char *argv
[])
556 fputs("License generator for the TTCN-3 Test Executor.\n", stderr
);
561 unique_id
= get_unique_id(argv
[1]);
565 if (!strcmp(argv
[1], "-m")) {
566 unique_id
= get_unique_id(argv
[2]);
572 error("Usage: %s [-m] unique_id", argv
[0]);
577 connect_database(&mysql
);
578 fill_from_database(&mysql
, &lraw
, unique_id
);
579 disconnect_database(&mysql
);
581 sign_license(&lraw
, PRIVATE_KEY
);
583 file_name
= mprintf(LICENSE_DIR
"/license_%d.dat", unique_id
);
584 write_license(file_name
, &lraw
);
585 fprintf(stderr
, "License file %s was generated.\n", file_name
);
587 fputs("License information:\n", stderr
);
588 load_license_from_file(&lstr
, file_name
);
590 print_license(&lstr
);
592 license_struct lstr2
;
593 connect_database(&mysql
);
594 fill_from_database_c(&mysql
, &lstr2
, unique_id
);
595 disconnect_database(&mysql
);
596 mail_license(&lstr2
, &lraw
);
597 fputs("E-mail was sent.\n", stderr
);
598 /* do not free_license(lstr2) */
602 check_mem_leak(argv
[0]);
This page took 0.045277 seconds and 5 git commands to generate.