From e5e6c6f43ce143978a97b332b6279cd25f22bd29 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 10 Sep 2009 11:18:41 +0200 Subject: [PATCH] use generic option parsing with usage information --- src/pki/pki.c | 454 ++++++++++++++++++++++---------------------------- 1 file changed, 202 insertions(+), 252 deletions(-) diff --git a/src/pki/pki.c b/src/pki/pki.c index 2410d69440..ffc0c5b1d9 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -32,189 +32,198 @@ #include #include -static void print_gen(FILE *out) -{ - fprintf(out, " pki --gen [--type rsa|ecdsa] [--size bits] [--outform der|pem|pgp]\n"); - fprintf(out, " generate a new private key\n"); - fprintf(out, " --type type of key, default: rsa\n"); - fprintf(out, " --size keylength in bits, default: rsa 2048, ecdsa 384\n"); - fprintf(out, " --outform encoding of generated private key\n"); -} - -static void print_pub(FILE *out) -{ - fprintf(out, " pki --pub [--in file] [--type rsa|ecdsa|x509] [--outform der|pem|pgp]\n"); - fprintf(out, " extract the public key from a private key/certificate\n"); - fprintf(out, " --in input file, default: stdin\n"); - fprintf(out, " --type type of credential, default: rsa\n"); - fprintf(out, " --outform encoding of extracted public key\n"); -} +static int help(int argc, char *argv[]); +static int gen(int argc, char *argv[]); +static int pub(int argc, char *argv[]); +static int keyid(int argc, char *argv[]); +static int self(int argc, char *argv[]); +static int issue(int argc, char *argv[]); +static int verify(int argc, char *argv[]); -static void print_keyid(FILE *out) -{ - fprintf(out, " pki --keyid [--in file] [--type rsa-priv|ecdsa-priv|pub|x509]\n"); - fprintf(out, " calculate key identifiers of a key/certificate\n"); - fprintf(out, " --in input file, default: stdin\n"); - fprintf(out, " --type type of key, default: rsa-priv\n"); -} +typedef enum { + CMD_HELP = 0, + CMD_GEN, + CMD_PUB, + CMD_KEYID, + CMD_SELF, + CMD_ISSUE, + CMD_VERIFY, + CMD_MAX +} cmd_t; -static void print_self(FILE *out) -{ - fprintf(out, " pki --self [--in file] [--type rsa|ecdsa]\n"); - fprintf(out, " --dn distinguished-name [--san subjectAltName]+\n"); - fprintf(out, " [--lifetime days] [--serial hex] [--ca]\n"); - fprintf(out, " [--digest md5|sha1|sha224|sha256|sha384|sha512]\n"); - fprintf(out, " [--options file]\n"); - fprintf(out, " create a self signed certificate\n"); - fprintf(out, " --in private key input file, default: stdin\n"); - fprintf(out, " --type type of input key, default: rsa\n"); - fprintf(out, " --dn subject and issuer distinguished name\n"); - fprintf(out, " --san subjectAltName to include in certificate\n"); - fprintf(out, " --lifetime days the certificate is valid, default: 1080\n"); - fprintf(out, " --serial serial number in hex, default: random\n"); - fprintf(out, " --ca include CA basicConstraint, default: no\n"); - fprintf(out, " --digest digest for signature creation, default: sha1\n"); - fprintf(out, " --options read command line options from file\n"); -} +#define MAX_OPTIONS 14 -static void print_issue(FILE *out) -{ - fprintf(out, " pki --issue [--in file] [--type pub|pkcs10]\n"); - fprintf(out, " --cacert file --cakey file\n"); - fprintf(out, " --dn subject-dn [--san subjectAltName]+\n"); - fprintf(out, " [--lifetime days] [--serial hex] [--ca]\n"); - fprintf(out, " [--digest md5|sha1|sha224|sha256|sha384|sha512]\n"); - fprintf(out, " [--options file]\n"); - fprintf(out, " issue a certificate using a CA certificate and key\n"); - fprintf(out, " --in public key/request file to issue, default: stdin\n"); - fprintf(out, " --type type of input, default: pub\n"); - fprintf(out, " --cacert CA certificate file\n"); - fprintf(out, " --cakey CA private key file\n"); - fprintf(out, " --dn distinguished name to include as subject\n"); - fprintf(out, " --san subjectAltName to include in certificate\n"); - fprintf(out, " --lifetime days the certificate is valid, default: 1080\n"); - fprintf(out, " --serial serial number in hex, default: random\n"); - fprintf(out, " --ca include CA basicConstraint, default: no\n"); - fprintf(out, " --digest digest for signature creation, default: sha1\n"); - fprintf(out, " --options read command line options from file\n"); -} - -static void print_verify(FILE *out) -{ - fprintf(out, " pki --verify [--in file] [--ca file]\n"); - fprintf(out, " verify a certificate using the CA certificate\n"); - fprintf(out, " --in x509 certifcate to verify, default: stdin\n"); - fprintf(out, " --cacert CA certificate, default: verify self signed\n"); -} - -static void print_version(FILE *out, char *name) -{ - fprintf(out, "strongSwan %s PKI tool\n", VERSION); - fprintf(out, "usage:\n"); - fprintf(out, " pki%s --help\n", name); - fprintf(out, " show this usage information\n"); -} - -static int usage(char *error) -{ - FILE *out = stdout; - - if (error) - { - out = stderr; - fprintf(out, "Error: %s\n", error); - } - print_version(out, ""); - print_gen(out); - print_pub(out); - print_keyid(out); - print_self(out); - print_issue(out); - print_verify(out); - return error != NULL; -} - -static int usage_gen(char *error) -{ - FILE *out = stdout; +static struct { + int (*call)(int, char*[]); + char op; + char *cmd; + char *description; + char *line[8]; + struct { + char *name; + char op; + int arg; + char *desc; + } options[MAX_OPTIONS]; +} cmds[] = { + [CMD_HELP] = { help, 'h', "help", + "show usage information" + }, + [CMD_GEN] = { gen, 'g', "gen", "generate a new private key", + {"[--type rsa|ecdsa] [--size bits] [--outform der|pem|pgp]"}, + { + {"help", 'h', 0, "show usage information"}, + {"type", 't', 1, "type of key, default: rsa"}, + {"size", 's', 1, "keylength in bits, default: rsa 2048, ecdsa 384"}, + {"outform", 'f', 1, "encoding of generated private key"}, + } + }, + [CMD_PUB] = { pub, 'p', "pub", + "extract the public key from a private key/certificate", + {"[--in file] [--type rsa|ecdsa|x509] [--outform der|pem|pgp]"}, + { + {"help", 'h', 0, "show usage information"}, + {"in", 'i', 1, "input file, default: stdin"}, + {"type", 't', 1, "type of credential, default: rsa"}, + {"outform", 'f', 1, "encoding of extracted public key"}, + } + }, + [CMD_KEYID] = { keyid, 'k', "keyid", + "calculate key identifiers of a key/certificate", + {"[--in file] [--type rsa-priv|ecdsa-priv|pub|x509]"}, + { + {"help", 'h', 0, "show usage information"}, + {"in", 'i', 1, "input file, default: stdin"}, + {"type", 't', 1, "type of key, default: rsa-priv"}, + } + }, + [CMD_SELF] = { self, 's', "self", + "create a self signed certificate", + {"[--in file] [--type rsa|ecdsa]", + " --dn distinguished-name [--san subjectAltName]+", + "[--lifetime days] [--serial hex] [--ca]", + "[--digest md5|sha1|sha224|sha256|sha384|sha512]", + "[--options file]"}, + { + {"help", 'h', 0, "show usage information"}, + {"in", 'i', 1, "private key input file, default: stdin"}, + {"type", 't', 1, "type of input key, default: rsa"}, + {"dn", 'd', 1, "subject and issuer distinguished name"}, + {"san", 'a', 1, "subjectAltName to include in certificate"}, + {"lifetime",'l', 1, "days the certificate is valid, default: 1080"}, + {"serial", 's', 1, "serial number in hex, default: random"}, + {"ca", 'b', 0, "include CA basicConstraint, default: no"}, + {"digest", 'g', 1, "digest for signature creation, default: sha1"}, + {"options", '+', 1, "read command line options from file"}, + } + }, + [CMD_ISSUE] = { issue, 'i', "issue", + "issue a certificate using a CA certificate and key", + {"[--in file] [--type pub|pkcs10]", + " --cacert file --cakey file", + " --dn subject-dn [--san subjectAltName]+", + "[--lifetime days] [--serial hex] [--ca]", + "[--digest md5|sha1|sha224|sha256|sha384|sha512]", + "[--options file]"}, + { + {"help", 'h', 0, "show usage information"}, + {"in", 'i', 1, "public key/request file to issue, default: stdin"}, + {"type", 't', 1, "type of input, default: pub"}, + {"cacert", 'c', 1, "CA certificate file"}, + {"cakey", 'k', 1, "CA private key file"}, + {"dn", 'd', 1, "distinguished name to include as subject"}, + {"san", 'a', 1, "subjectAltName to include in certificate"}, + {"lifetime",'l', 1, "days the certificate is valid, default: 1080"}, + {"serial", 's', 1, "serial number in hex, default: random"}, + {"ca", 'b', 0, "include CA basicConstraint, default: no"}, + {"digest", 'g', 1, "digest for signature creation, default: sha1"}, + {"options", '+', 1, "read command line options from file"}, + } + }, + [CMD_VERIFY] = { verify, 'v', "verify", + "verify a certificate using the CA certificate", + {"[--in file] [--ca file]"}, + { + {"help", 'h', 0, "show usage information"}, + {"in", 'i', 1, "x509 certifcate to verify, default: stdin"}, + {"cacert", 'c', 1, "CA certificate, default: verify self signed"}, + } + }, +}; - if (error) - { - out = stderr; - fprintf(out, "Error: %s\n", error); - } - print_version(out, " --gen"); - print_gen(out); - return error != NULL; -} +/** + * Global options used by all subcommands + */ +static struct option long_opts[countof(cmds) > MAX_OPTIONS ?: MAX_OPTIONS]; -static int usage_pub(char *error) +/** + * Build long_opts for a specific command + */ +static void build_opts(cmd_t cmd) { - FILE *out = stdout; + int i; - if (error) + memset(long_opts, 0, sizeof(long_opts)); + if (cmd == CMD_HELP) { - out = stderr; - fprintf(out, "Error: %s\n", error); + for (i = 0; i < CMD_MAX; i++) + { + long_opts[i].name = cmds[i].cmd; + long_opts[i].val = cmds[i].op; + } } - print_version(out, " --pub"); - print_pub(out); - return error != NULL; -} - -static int usage_keyid(char *error) -{ - FILE *out = stdout; - - if (error) + else { - out = stderr; - fprintf(out, "Error: %s\n", error); + for (i = 0; cmds[cmd].options[i].name; i++) + { + long_opts[i].name = cmds[cmd].options[i].name; + long_opts[i].has_arg = cmds[cmd].options[i].arg; + long_opts[i].val = cmds[cmd].options[i].op; + } } - print_version(out, " --keyid"); - print_keyid(out); - return error != NULL; } -static int usage_self(char *error) +/** + * Print usage text, with an optional error + */ +static int usage(cmd_t cmd, char *error) { FILE *out = stdout; + int i; if (error) { out = stderr; fprintf(out, "Error: %s\n", error); } - print_version(out, " --self"); - print_self(out); - return error != NULL; -} - -static int usage_issue(char *error) -{ - FILE *out = stdout; - - if (error) + fprintf(out, "strongSwan %s PKI tool\n", VERSION); + fprintf(out, "usage:\n"); + if (cmd == CMD_HELP) { - out = stderr; - fprintf(out, "Error: %s\n", error); + for (i = 0; i < CMD_MAX; i++) + { + fprintf(out, " pki --%-6s %s\n", cmds[i].cmd, cmds[i].description); + } } - print_version(out, " --issue"); - print_issue(out); - return error != NULL; -} - -static int usage_verify(char *error) -{ - FILE *out = stdout; - - if (error) + else { - out = stderr; - fprintf(out, "Error: %s\n", error); + for (i = 0; cmds[cmd].line[i]; i++) + { + if (i == 0) + { + fprintf(out, " pki --%s %s\n", cmds[cmd].cmd, cmds[cmd].line[i]); + } + else + { + fprintf(out, " %s\n", cmds[cmd].line[i]); + } + } + for (i = 0; cmds[cmd].options[i].name; i++) + { + fprintf(out, " --%-8s %s\n", + cmds[cmd].options[i].name, cmds[cmd].options[i].desc); + } } - print_version(out, " --verify"); - print_verify(out); return error != NULL; } @@ -275,6 +284,14 @@ static hash_algorithm_t get_digest(char *name) return HASH_UNKNOWN; } +/** + * Show usage information + */ +static int help(int argc, char *argv[]) +{ + return usage(CMD_HELP, NULL); +} + /** * Generate a private key */ @@ -286,19 +303,12 @@ static int gen(int argc, char *argv[]) private_key_t *key; chunk_t encoding; - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "type", required_argument, NULL, 't' }, - { "size", required_argument, NULL, 's' }, - { "outform", required_argument, NULL, 'o' }, - { 0,0,0,0 } - }; while (TRUE) { switch (getopt_long(argc, argv, "", long_opts, NULL)) { case 'h': - return usage_gen(NULL); + return usage(CMD_GEN, NULL); case 't': if (streq(optarg, "rsa")) { @@ -310,26 +320,26 @@ static int gen(int argc, char *argv[]) } else { - return usage_gen("invalid key type"); + return usage(CMD_GEN, "invalid key type"); } continue; case 'o': if (!get_form(optarg, &form, FALSE)) { - return usage_gen("invalid key output format"); + return usage(CMD_GEN, "invalid key output format"); } continue; case 's': size = atoi(optarg); if (!size) { - return usage_gen("invalid key size"); + return usage(CMD_GEN, "invalid key size"); } continue; case EOF: break; default: - return usage_gen("invalid --gen option"); + return usage(CMD_GEN, "invalid --gen option"); } break; } @@ -387,19 +397,12 @@ static int pub(int argc, char *argv[]) char *file = NULL; void *cred; - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "type", required_argument, NULL, 't' }, - { "outform", required_argument, NULL, 'f' }, - { "in", required_argument, NULL, 'i' }, - { 0,0,0,0 } - }; while (TRUE) { switch (getopt_long(argc, argv, "", long_opts, NULL)) { case 'h': - return usage_pub(NULL); + return usage(CMD_PUB, NULL); case 't': if (streq(optarg, "rsa")) { @@ -418,13 +421,13 @@ static int pub(int argc, char *argv[]) } else { - return usage_pub("invalid input type"); + return usage(CMD_PUB, "invalid input type"); } continue; case 'f': if (!get_form(optarg, &form, TRUE)) { - return usage_pub("invalid output format"); + return usage(CMD_PUB, "invalid output format"); } continue; case 'i': @@ -433,7 +436,7 @@ static int pub(int argc, char *argv[]) case EOF: break; default: - return usage_pub("invalid --pub option"); + return usage(CMD_PUB, "invalid --pub option"); } break; } @@ -506,18 +509,12 @@ static int keyid(int argc, char *argv[]) void *cred; chunk_t id; - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "type", required_argument, NULL, 't' }, - { "in", required_argument, NULL, 'i' }, - { 0,0,0,0 } - }; while (TRUE) { switch (getopt_long(argc, argv, "", long_opts, NULL)) { case 'h': - return usage_keyid(NULL); + return usage(CMD_KEYID, NULL); case 't': if (streq(optarg, "rsa-priv")) { @@ -541,7 +538,7 @@ static int keyid(int argc, char *argv[]) } else { - return usage_keyid("invalid input type"); + return usage(CMD_KEYID, "invalid input type"); } continue; case 'i': @@ -550,7 +547,7 @@ static int keyid(int argc, char *argv[]) case EOF: break; default: - return usage_keyid("invalid --keyid option"); + return usage(CMD_KEYID, "invalid --keyid option"); } break; } @@ -639,20 +636,6 @@ static int self(int argc, char *argv[]) x509_flag_t flags = 0; options_t *options; - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "options", required_argument, NULL, '+' }, - { "type", required_argument, NULL, 't' }, - { "in", required_argument, NULL, 'i' }, - { "dn", required_argument, NULL, 'd' }, - { "san", required_argument, NULL, 'a' }, - { "lifetime", required_argument, NULL, 'l' }, - { "serial", required_argument, NULL, 's' }, - { "digest", required_argument, NULL, 'g' }, - { "ca", no_argument, NULL, 'c' }, - { 0,0,0,0 } - }; - options = options_create(); san = linked_list_create(); @@ -817,7 +800,7 @@ end: usage: san->destroy_offset(san, offsetof(identification_t, destroy)); options->destroy(options); - return usage_self(error); + return usage(CMD_SELF, error); } /** @@ -841,22 +824,6 @@ static int issue(int argc, char *argv[]) x509_t *x509; options_t *options; - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "options", required_argument, NULL, '+' }, - { "type", required_argument, NULL, 't' }, - { "in", required_argument, NULL, 'i' }, - { "cacert", required_argument, NULL, 'c' }, - { "cakey", required_argument, NULL, 'k' }, - { "dn", required_argument, NULL, 'd' }, - { "san", required_argument, NULL, 'a' }, - { "lifetime", required_argument, NULL, 'l' }, - { "serial", required_argument, NULL, 's' }, - { "digest", required_argument, NULL, 'g' }, - { "ca", no_argument, NULL, 'b' }, - { 0,0,0,0 } - }; - options = options_create(); san = linked_list_create(); @@ -1061,7 +1028,7 @@ end: usage: san->destroy_offset(san, offsetof(identification_t, destroy)); options->destroy(options); - return usage_issue(error); + return usage(CMD_ISSUE, error); } /** @@ -1085,7 +1052,7 @@ static int verify(int argc, char *argv[]) switch (getopt_long(argc, argv, "", long_opts, NULL)) { case 'h': - return usage_verify(NULL); + return usage(CMD_VERIFY, NULL); case 'i': file = optarg; continue; @@ -1095,7 +1062,7 @@ static int verify(int argc, char *argv[]) case EOF: break; default: - return usage_verify("invalid --verify option"); + return usage(CMD_VERIFY, "invalid --verify option"); } break; } @@ -1174,16 +1141,7 @@ static int verify(int argc, char *argv[]) */ int main(int argc, char *argv[]) { - struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "gen", no_argument, NULL, 'g' }, - { "pub", no_argument, NULL, 'p' }, - { "keyid", no_argument, NULL, 'k' }, - { "self", no_argument, NULL, 's' }, - { "issue", no_argument, NULL, 'i' }, - { "verify", no_argument, NULL, 'v' }, - { 0,0,0,0 } - }; + int op, i; atexit(library_deinit); if (!library_init(STRONGSWAN_CONF)) @@ -1202,24 +1160,16 @@ int main(int argc, char *argv[]) exit(SS_RC_INITIALIZATION_FAILED); } - switch (getopt_long(argc, argv, "", long_opts, NULL)) - { - case 'h': - return usage(NULL); - case 'g': - return gen(argc, argv); - case 'p': - return pub(argc, argv); - case 'k': - return keyid(argc, argv); - case 's': - return self(argc, argv); - case 'i': - return issue(argc, argv); - case 'v': - return verify(argc, argv); - default: - return usage("invalid operation"); + build_opts(CMD_HELP); + op = getopt_long(argc, argv, "", long_opts, NULL); + for (i = 0; i < CMD_MAX; i++) + { + if (cmds[i].op == op) + { + build_opts(i); + return cmds[i].call(argc, argv); + } } + return usage(CMD_HELP, "invalid operation"); } -- 2.47.2