00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <ctype.h>
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <unistd.h>
00039 #include <errno.h>
00040 #include <assert.h>
00041
00042 #ifdef HAVE_LIBXML2
00043 #include <libxml/tree.h>
00044 #include <libxml/xpath.h>
00045 #endif
00046
00047 #define MODULE "eurephia::Certificates"
00048 #include <eurephia_nullsafe.h>
00049 #include <eurephia_context.h>
00050 #include <eurephia_log.h>
00051 #include <eurephia_xml.h>
00052 #include <eurephia_values_struct.h>
00053 #include <eurephiadb_session_struct.h>
00054 #include <eurephiadb_mapping.h>
00055 #include <eurephiadb_driver.h>
00056 #include <certinfo.h>
00057
00058 #include "../argparser.h"
00059 #include "../get_console_input.h"
00060 #include "../parse_certificate_files.h"
00061 #include "../xsltparser.h"
00062
00063
00069 void display_certs_help(int page) {
00070 switch( page ) {
00071 case 'A':
00072 printf("The add mode will register a new certificate.\n\n"
00073 " -d | --depth Certificate depth, required.\n"
00074 " -D | --digest SHA1 fingerprint/digest of the new certificate\n"
00075 " -C | --common-name Common name (CN) field of the certificate\n"
00076 " -O | --organisation Organisation (O) field of the certificate\n"
00077 " -E | --email e-mail address (emailAddress) of the certificate\n"
00078 "\n"
00079 "Usually the certificate depth value needs to be 0, if you are registering user\n"
00080 "account certificates. CA certificates usually have a value bigger than 0.\n\n");
00081 #ifdef HAVE_OPENSSL
00082 printf("If you have the certificate file available, you can use the following\n"
00083 "options to retrieve the needed information directly from a certificate file.\n\n"
00084 " -f | --certfile File name of the certificate file.\n"
00085 " -p | --pkcs12 If the file is in PKCS#12 format.\n"
00086 "\n"
00087 "The default format is PEM format, unless --pkcs12 is given. These two options\n"
00088 "cannot be used together with -D, -C, -O or -E. But the certificate depth must\n"
00089 "be given to indicate the certificate depth.\n\n");
00090 #endif
00091 break;
00092 case 'D':
00093 printf("The delete mode will remove a certificate from the certificate database.\n\n"
00094 " -i | --certid Indicates a unique certificate ID\n"
00095 " -d | --digest A unique SHA1 fingerprint/digest value\n"
00096 " -C | --common-name Common Name (CN) field of a certificate\n"
00097 " -O | --organisation Organisation (O) field of a certificate\n"
00098 " -E | --email e-mail address (emailAddress) of a certificate\n"
00099 "\n"
00100 "You can use any of these parameters to indicate a search criteria for the\n"
00101 "certificate (or certificates) you want to delete. You will be provided with\n"
00102 "a list over certificates which matches your search criteria and you will need\n"
00103 "to approve the deletion of the matching certificate(s).\n\n");
00104 break;
00105
00106 case 'l':
00107 printf("The list mode will list all registered certificates. It accepts one parameter:\n\n"
00108 " -S | --sort <sort key> Decide the sort order of the certificate list\n"
00109 "\n"
00110 "Available sort keys are: certid, depth, digest, cname, org, email and registered.\n\n");
00111 break;
00112 default:
00113 printf("Available modes for the certificate command are:\n\n"
00114 " -A | --add Register a new certificate\n"
00115 " -D | --delete Delete a registered certificate\n"
00116 " -l | --list List all registered certificates\n"
00117 " -h | --help <mode> Help about a specific mode\n\n");
00118 break;
00119 }
00120 }
00121
00122
00126 void help_Certificates() {
00127 display_certs_help(0);
00128 }
00129
00130
00142 int help_Certificates2(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) {
00143 e_options helpargs[] = {
00144 {"--list", "-l", 0},
00145 {"--add", "-A", 0},
00146 {"--delete", "-D", 0},
00147 {NULL, NULL, 0}
00148 };
00149
00150 int i = 1;
00151 display_certs_help(eurephia_getopt(&i, argc, argv, helpargs));
00152 return 0;
00153 }
00154
00167 int register_certificate(eurephiaCTX *ctx, int depth, const char *digest,
00168 const char *cname, const char *org, const char *email)
00169 {
00170 xmlDoc *cert_xml = NULL, *res_xml = NULL;
00171 xmlNode *cert_n = NULL;
00172 eurephiaRESULT *res = NULL;
00173 char tmp[66], *cname_cp = NULL, *org_cp = NULL;
00174 int certid = 0;
00175
00176 assert( ctx != NULL );
00177
00178 eurephiaXML_CreateDoc(ctx, 1, "certificates", &cert_xml, &cert_n);
00179 assert( (cert_xml != NULL) || (cert_n != NULL) );
00180 xmlNewProp(cert_n, (xmlChar *) "mode", (xmlChar *) "register");
00181
00182 cert_n = xmlNewChild(cert_n, NULL, (xmlChar *) "fieldMapping", NULL);
00183 xmlNewProp(cert_n, (xmlChar *) "table", (xmlChar *) "certificates");
00184
00185 memset(&tmp, 0, 66);
00186 snprintf(tmp, 64, "%i", depth);
00187
00188 cname_cp = strdup_nullsafe(cname);
00189 org_cp = strdup_nullsafe(org);
00190
00191 xmlNewChild(cert_n, NULL, (xmlChar *) "depth", (xmlChar *) tmp);
00192 xmlNewChild(cert_n, NULL, (xmlChar *) "digest", (xmlChar *) digest);
00193 xmlNewChild(cert_n, NULL, (xmlChar *) "cname", (xmlChar *) cname_cp);
00194 xmlNewChild(cert_n, NULL, (xmlChar *) "org", (xmlChar *) org_cp);
00195 xmlNewChild(cert_n, NULL, (xmlChar *) "email", (xmlChar *) email);
00196
00197
00198 res_xml = eDBadminCertificate(ctx, cert_xml);
00199 if( res_xml == NULL ) {
00200 fprintf(stderr, "%s: Failed to register certificate\n", MODULE);
00201 } else {
00202 res = eurephiaXML_ParseResultMsg(ctx, res_xml);
00203 if( res == NULL ) {
00204 fprintf(stderr, "%s: Failed to register certificate. No results available\n", MODULE);
00205 certid = 0;
00206 } else if( res->resultType == exmlRESULT ) {
00207 cert_n = xmlFindNode(res->details, "certificate");
00208 if( cert_n == NULL ) {
00209 fprintf(stderr, "%s: Did not receive certificate ID of the newly registered"
00210 " certificate\n", MODULE);
00211 certid = 0;
00212 } else {
00213 certid = atoi_nullsafe(xmlGetAttrValue(cert_n->properties, "certid"));
00214 fprintf(stdout, "%s: %s\n", MODULE, res->message);
00215 }
00216 } else {
00217 fprintf(stderr, "%s: %s\n", MODULE, res->message);
00218 certid = 0;
00219 }
00220 free_nullsafe(ctx, res);
00221 }
00222 xmlFreeDoc(cert_xml);
00223 free_nullsafe(ctx, cname_cp);
00224 free_nullsafe(ctx, org_cp);
00225
00226 return certid;
00227 }
00228
00229
00241 int add_cert(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) {
00242 char *digest = NULL, *cname = NULL, *org = NULL, *email = NULL, *certfile = NULL;
00243 int depth = -1, i = 0, j = 0, chk = 0, certfile_format = 0, rc = 0;
00244 #ifdef HAVE_OPENSSL
00245 struct stat cert_stat;
00246 #endif
00247
00248 e_options addcertargs[] = {
00249 {"--depth", "-d", 1},
00250 {"--digest", "-D", 1},
00251 {"--common-name", "-C", 1},
00252 {"--organisation", "-O", 1},
00253 {"--email", "-E", 1},
00254 #ifdef HAVE_OPENSSL
00255 {"--certfile", "-f", 1},
00256 {"--pkcs12", "-p", 0},
00257 #endif
00258 {"--help", "-h", 0},
00259 {NULL, NULL, 0}
00260 };
00261
00262 certfile = NULL;
00263 certfile_format = CERTFILE_PEM;
00264 for( i = 1; i < argc ; i++ ) {
00265 switch( eurephia_getopt(&i, argc, argv, addcertargs) ) {
00266 case 'd':
00267
00268
00269 chk = 1;
00270 for( j = 0; j < strlen_nullsafe(optargs[0]); j++ ) {
00271 if( !isdigit(optargs[0][j]) ) {
00272 chk = 0;
00273 break;
00274 }
00275 }
00276 if( chk == 0 ) {
00277 fprintf(stderr, "%s: Certificate depth must be a number\n", MODULE);
00278 return 1;
00279 }
00280
00281 depth = atoi_nullsafe(optargs[0]);
00282 if( (depth < 0) || (depth > 99) ) {
00283 fprintf(stderr, "%s: Certificate depth must be between 0-99\n", MODULE);
00284 return 1;
00285 }
00286 break;
00287
00288 case 'D':
00289 if( strlen_nullsafe(optargs[0]) < 59 ) {
00290 fprintf(stderr, "%s: Certificate digest is too short\n", MODULE);
00291 return 1;
00292 }
00293 digest = strdup_nullsafe(optargs[0]);
00294 break;
00295 case 'C':
00296 cname = strdup_nullsafe(optargs[0]);
00297 break;
00298 case 'O':
00299 org = strdup_nullsafe(optargs[0]);
00300 break;
00301 case 'E':
00302 email = strdup_nullsafe(optargs[0]);
00303 break;
00304
00305 #ifdef HAVE_OPENSSL
00306 case 'p':
00307 certfile_format = CERTFILE_PKCS12;
00308 break;
00309
00310 case 'f':
00311 if( strlen_nullsafe(optargs[0]) < 1 ) {
00312 fprintf(stderr, "%s: certfile is too short\n", MODULE);
00313 return 1;
00314 }
00315 certfile = optargs[0];
00316
00317 if( stat(certfile, &cert_stat) == -1 ) {
00318 fprintf(stderr, "%s: Could not access certfile: %s (%s)\n", MODULE,
00319 certfile, strerror(errno));
00320 return 1;
00321 }
00322
00323 if( cert_stat.st_size == 0 ) {
00324 fprintf(stderr, "%s: certfile '%s' is empty\n", MODULE, certfile);
00325 return 1;
00326 }
00327 break;
00328 #endif
00329 case 'h':
00330 display_certs_help('A');
00331 break;
00332 default:
00333 return 2;
00334 }
00335 }
00336
00337
00338 if( depth < 0 ) {
00339 fprintf(stderr, "%s: You must set certificate depth (possibly, it needs to be 0)\n", MODULE);
00340 return 1;
00341 }
00342
00343 if( (certfile != NULL) && ((digest != NULL) || (cname != NULL) || (org != NULL) || (email != NULL)) ){
00344 fprintf(stderr,
00345 "%s: You cannot combine --certfile with --depth, --common-name,\n"
00346 "--organisation or --email\n", MODULE);
00347 return 1;
00348 }
00349
00350 if( (certfile == NULL) && ((digest == NULL) || (cname == NULL) || (org == NULL) || (email == NULL)) ) {
00351 fprintf(stderr,
00352 "%s: You must use either --certfile or --depth, --common-name,\n"
00353 "--organisation and --email\n", MODULE);
00354 return 1;
00355 }
00356
00357 #ifdef HAVE_OPENSSL
00358
00359 if( certfile != NULL ) {
00360 certinfo *ci = NULL;
00361 if( (ci = Cert_ParseFile(certfile, certfile_format)) == NULL ) {
00362 fprintf(stderr, "%s: Failed to parse certificate file\n", MODULE);
00363 rc = 1;
00364 goto exit;
00365 }
00366 digest = strdup_nullsafe(ci->digest);
00367 cname = strdup_nullsafe(ci->common_name);
00368 org = strdup_nullsafe(ci->org);
00369 email = strdup_nullsafe(ci->email);
00370 free_certinfo(ci); ci = NULL;
00371
00372 }
00373 #endif
00374
00375 rc = (register_certificate(ctx, depth, digest, cname, org, email) < 1);
00376 exit:
00377 free_nullsafe(ctx, digest);
00378 free_nullsafe(ctx, cname);
00379 free_nullsafe(ctx, org);
00380 free_nullsafe(ctx, email);
00381 return rc;
00382 }
00383
00384
00396 int delete_cert(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) {
00397 xmlDoc *cert_xml = NULL, *delete_xml = NULL, *certlist = NULL, *res_xml = NULL;
00398 xmlNode *cert_n = NULL, *search_n = NULL, *delete_n = NULL;
00399 eurephiaRESULT *res = NULL;
00400 char *digest = NULL, *cname = NULL, *org = NULL, *email = NULL, *certid = NULL, confirm[5];
00401 const char *xsltparams[] = {"view_digest", "'1'", "firewall", "'0'", NULL};
00402 int i, rc = 0, count = 0;
00403 e_options addcertargs[] = {
00404 {"--certid", "-i", 1},
00405 {"--digest", "-d", 1},
00406 {"--common-name", "-C", 1},
00407 {"--organisation", "-O", 1},
00408 {"--email", "-E", 1},
00409 {"--help", "-h", 0},
00410 {NULL, NULL, 0}
00411 };
00412
00413 for( i = 1; i < argc ; i++ ) {
00414 switch( eurephia_getopt(&i, argc, argv, addcertargs) ) {
00415 case 'i':
00416 if( atoi_nullsafe(optargs[0]) < 1 ) {
00417 fprintf(stderr, "%s: Certificate ID (certid) must be > 0\n", MODULE);
00418 return 1;
00419 }
00420 certid = optargs[0];
00421 break;
00422 case 'd':
00423 if( strlen_nullsafe(optargs[0]) < 59 ) {
00424 fprintf(stderr, "%s: Certificate digest is too short\n", MODULE);
00425 return 1;
00426 }
00427 digest = optargs[0];
00428 break;
00429 case 'C':
00430 cname = strdup_nullsafe(optargs[0]);
00431 break;
00432 case 'O':
00433 org = strdup_nullsafe(optargs[0]);
00434 break;
00435 case 'E':
00436 email = optargs[0];
00437 break;
00438 case 'h':
00439 display_certs_help('D');
00440 break;
00441 default:
00442 return 1;
00443 }
00444 }
00445
00446
00447 if( (certid == NULL) && (digest == NULL) && (cname == NULL) && (org == NULL) && (email == NULL) ) {
00448 fprintf(stderr,
00449 "%s: You must add at least one search criteria to delete a certificate\n",
00450 MODULE);
00451 return 1;
00452 }
00453
00454
00455 eurephiaXML_CreateDoc(ctx, 1, "certificates", &cert_xml, &cert_n);
00456 assert( (cert_xml != NULL) && (cert_n != NULL));
00457 xmlNewProp(cert_n, (xmlChar *) "mode", (xmlChar *) "list");
00458 xmlNewChild(cert_n, NULL, (xmlChar *) "sortkeys", (xmlChar *) "certid");
00459
00460 search_n = xmlNewChild(cert_n, NULL, (xmlChar *) "fieldMapping", NULL);
00461 xmlNewProp(search_n, (xmlChar *) "table", (xmlChar *) "certificates");
00462
00463 if( certid != NULL ) {
00464 xmlNewChild(search_n, NULL, (xmlChar *) "certid", (xmlChar *) certid);
00465 }
00466 if( digest != NULL ) {
00467 xmlNewChild(search_n, NULL, (xmlChar *) "digest", (xmlChar *) digest);
00468 }
00469 if( cname != NULL ) {
00470 xmlNewChild(search_n, NULL, (xmlChar *) "cname", (xmlChar *) cname);
00471 }
00472 if( org!= NULL ) {
00473 xmlNewChild(search_n, NULL, (xmlChar *) "org", (xmlChar *) org);
00474 }
00475 if( email != NULL ) {
00476 xmlNewChild(search_n, NULL, (xmlChar *) "email", (xmlChar *) email);
00477 }
00478
00479
00480 certlist = eDBadminCertificate(ctx, cert_xml);
00481 if( certlist == NULL ) {
00482 return 0;
00483 }
00484
00485 delete_n = eurephiaXML_getRoot(ctx, certlist, "certificates", 1);
00486 if( atoi_nullsafe(xmlGetAttrValue(delete_n->properties, "certificates")) == 0 ) {
00487 printf("%s: No certificates found\n", MODULE);
00488 goto exit;
00489 }
00490
00491
00492 xslt_print_xmldoc(stdout, cfg, certlist, "certificates.xsl", xsltparams);
00493
00494
00495 memset(&confirm, 0, 5);
00496 printf("\n");
00497 get_console_input(confirm, 3, "Do you want to delete the listed certificate(s)? [y/N] ", 0);
00498 if( (confirm[0] != 'y') && (confirm[0] != 'Y') ) {
00499 printf("%s: Aborted certificate deletion\n", MODULE);
00500 rc = 0;
00501 goto exit;
00502 }
00503
00504
00505 eurephiaXML_CreateDoc(ctx, 1, "certificates", &delete_xml, &delete_n);
00506 assert( (delete_xml != NULL) && (delete_n != NULL));
00507 xmlNewProp(delete_n, (xmlChar *) "mode", (xmlChar *) "delete");
00508 xmlAddChild(delete_n, xmlCopyNode(search_n, 1));
00509
00510 res_xml = eDBadminCertificate(ctx, delete_xml);
00511 if( res_xml == NULL ) {
00512 fprintf(stderr, "%s: Failed to delete the certificate%s\n", MODULE, (count != 1 ? "s" : ""));
00513 rc = 1;
00514 } else {
00515 res = eurephiaXML_ParseResultMsg(ctx, res_xml);
00516 if( res == NULL ) {
00517 fprintf(stderr, "%s: Failed to delete the certificate%s\n", MODULE,
00518 (count != 1 ? "s" : ""));
00519 rc = 1;
00520 } else if( res->resultType == exmlERROR ) {
00521 fprintf(stderr, "%s: %s\n", MODULE, res->message);
00522 rc = 1;
00523 } else {
00524 fprintf(stdout, "%s: %s\n", MODULE, res->message);
00525 rc = 0;
00526 }
00527 free_nullsafe(ctx, res);
00528 }
00529 xmlFreeDoc(delete_xml);
00530
00531 exit:
00532 xmlFreeDoc(certlist);
00533 xmlFreeDoc(cert_xml);
00534 free_nullsafe(ctx, cname);
00535 free_nullsafe(ctx, org);
00536 return rc;
00537 }
00538
00539
00551 int list_certs(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) {
00552 xmlDoc *srch_xml = NULL, *certlist = NULL;
00553 xmlNode *cert_n = NULL, *srch_n = NULL;
00554 const char *xsltparams[] = {"view_digest", "'1'", "firewall", "'0'", NULL};
00555 int i, rc = 0;
00556 char *sortkeys = NULL;
00557
00558 e_options listargs[] = {
00559 {"--sort", "-S", 1},
00560 {"--help", "-h", 0},
00561 {NULL, NULL, 0}
00562 };
00563
00564
00565 for( i = 1; i < argc; i++ ) {
00566 switch( eurephia_getopt(&i, argc, argv, listargs) ) {
00567 case 'S':
00568 sortkeys = optargs[0];
00569 i++;
00570 break;
00571
00572 case 'h':
00573 display_certs_help('l');
00574 return 0;
00575
00576 default:
00577 return 1;
00578 }
00579 }
00580
00581 if( sortkeys == NULL ) {
00582 sortkeys = "certid";
00583 }
00584
00585
00586 eurephiaXML_CreateDoc(ctx, 1, "certificates", &srch_xml, &srch_n);
00587 assert( (srch_xml != NULL) && (srch_n != NULL));
00588 xmlNewProp(srch_n, (xmlChar *) "mode", (xmlChar *) "list");
00589 xmlNewChild(srch_n, NULL, (xmlChar *) "sortkeys", (xmlChar *) sortkeys);
00590
00591 srch_n = xmlNewChild(srch_n, NULL, (xmlChar *) "fieldMapping", NULL);
00592 xmlNewProp(srch_n, (xmlChar *) "table", (xmlChar *) "certificates");
00593
00594
00595 certlist = eDBadminCertificate(ctx, srch_xml);
00596 if( certlist == NULL ) {
00597 xmlFreeDoc(srch_xml);
00598 fprintf(stderr, "%s: Failed to query for certificates\n", MODULE);
00599 return 1;
00600 }
00601
00602 cert_n = eurephiaXML_getRoot(ctx, certlist, "certificates", 1);
00603 if( (cert_n == NULL) || atoi_nullsafe(xmlGetAttrValue(cert_n->properties, "certificates")) == 0 ) {
00604 printf("%s: No certificates found\n", MODULE);
00605 rc = 0;
00606 goto exit;
00607 }
00608
00609
00610 xslt_print_xmldoc(stdout, cfg, certlist, "certificates.xsl", xsltparams);
00611 rc = 0;
00612 exit:
00613 xmlFreeDoc(certlist);
00614 xmlFreeDoc(srch_xml);
00615 return rc;
00616 }
00617
00618
00630 int cmd_Certificates(eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv) {
00631 char **mode_argv;
00632 int i, mode_argc = 0, rc = 0;
00633 int (*mode_fnc) (eurephiaCTX *ctx, eurephiaSESSION *sess, eurephiaVALUES *cfg, int argc, char **argv);
00634
00635 e_options modeargs[] = {
00636 {"--list", "-l", 0},
00637 {"--add", "-A", 0},
00638 {"--delete", "-D", 0},
00639 {"--help", "-h", 0},
00640 {NULL, NULL, 0}
00641 };
00642
00643 assert((ctx != NULL) && (ctx->dbc != NULL) && (ctx->dbc->config != NULL));
00644 mode_fnc = NULL;
00645 for( i = 1; i < argc; i++ ) {
00646 switch( eurephia_getopt(&i, argc, argv, modeargs) ) {
00647 case 'l':
00648 mode_fnc = list_certs;
00649 break;
00650
00651 case 'h':
00652 mode_fnc = help_Certificates2;
00653 break;
00654
00655 case 'A':
00656 mode_fnc = add_cert;
00657 break;
00658
00659 case 'D':
00660 mode_fnc = delete_cert;
00661 break;
00662
00663 default:
00664 break;
00665 }
00666 if( mode_fnc != NULL ) {
00667 break;
00668 }
00669 }
00670
00671
00672 if( mode_fnc == NULL ) {
00673 fprintf(stderr, "%s: Unknown argument. No mode given\n", MODULE);
00674 return 1;
00675 }
00676
00677
00678 mode_argv = (char **) calloc(sizeof(char *), (argc - i)+2);
00679 assert(mode_argv != NULL);
00680
00681
00682 mode_argc = eurephia_arraycp(i, argc, argv, mode_argv, (argc - i));
00683
00684
00685 rc = mode_fnc(ctx, sess, cfg, mode_argc, mode_argv);
00686 free_nullsafe(ctx, mode_argv);
00687
00688 return rc;
00689 }