Handle pki --debug and --options in a generic way for all command
authorMartin Willi <martin@strongswan.org>
Tue, 15 Sep 2009 09:49:14 +0000 (11:49 +0200)
committerMartin Willi <martin@strongswan.org>
Tue, 15 Sep 2009 09:53:46 +0000 (11:53 +0200)
src/pki/command.c
src/pki/command.h
src/pki/commands/gen.c
src/pki/commands/issue.c
src/pki/commands/keyid.c
src/pki/commands/pub.c
src/pki/commands/self.c
src/pki/commands/verify.c

index 2cf1365..8f5bc14 100644 (file)
  */
 
 #include "command.h"
+#include "pki.h"
 
-
+#define _GNU_SOURCE
+#include <getopt.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
+#include <library.h>
+#include <debug.h>
+#include <utils/optionsfrom.h>
+
 /**
  * Registered commands.
  */
@@ -40,15 +46,21 @@ static int registered = 0;
  */
 static int help_idx;
 
+static int argc;
+
+static char **argv;
+
+static options_t *options;
+
 /**
  * Global options used by all subcommands
  */
-struct option command_opts[MAX_COMMANDS > MAX_OPTIONS ?: MAX_OPTIONS];
+static struct option command_opts[MAX_COMMANDS > MAX_OPTIONS ?: MAX_OPTIONS];
 
 /**
  * Global optstring used by all subcommands
  */
-char command_optstring[(MAX_COMMANDS > MAX_OPTIONS ?: MAX_OPTIONS) * 3];
+static char command_optstring[(MAX_COMMANDS > MAX_OPTIONS ?: MAX_OPTIONS) * 3];
 
 /**
  * Build command_opts/command_optstr for the active command
@@ -93,11 +105,61 @@ static void build_opts()
 }
 
 /**
+ * getopt_long wrapper
+ */
+int command_getopt(char **arg)
+{
+       int op;
+
+       while (TRUE)
+       {
+               op = getopt_long(argc, argv, command_optstring, command_opts, NULL);
+               switch (op)
+               {
+                       case '+':
+                               if (!options->from(options, optarg, &argc, &argv, optind))
+                               {
+                                       /* a error value */
+                                       return 255;
+                               }
+                               continue;
+                       case 'v':
+                               dbg_level = atoi(optarg);
+                               continue;
+                       default:
+                               *arg = optarg;
+                               return op;
+               }
+       }
+}
+
+/**
  * Register a command
  */
 void command_register(command_t command)
 {
-       cmds[registered++] = command;
+       int i;
+
+       cmds[registered] = command;
+       /* append default options, but not to --help */
+       if (!active)
+       {
+               for (i = 0; i < countof(cmds[registered].options); i++)
+               {
+                       if (cmds[registered].options[i].name)
+                       {
+                               continue;
+                       }
+                       cmds[registered].options[i++] = (command_option_t) {
+                               "debug",        'v', 1, "set debug level, default: 1"
+                       };
+                       cmds[registered].options[i++] = (command_option_t) {
+                               "options",      '+', 1, "read command line options from file"
+                       };
+                       break;
+               }
+       }
+       registered++;
 }
 
 /**
@@ -159,24 +221,36 @@ static int help(int argc, char *argv[])
 }
 
 /**
+ * Dispatch cleanup hook
+ */
+static void cleanup()
+{
+       options->destroy(options);
+}
+
+/**
  * Dispatch commands.
  */
-int command_dispatch(int argc, char *argv[])
+int command_dispatch(int c, char *v[])
 {
        int op, i;
 
+       options = options_create();
+       atexit(cleanup);
        active = help_idx = registered;
+       argc = c;
+       argv = v;
        command_register((command_t){help, 'h', "help", "show usage information"});
 
        build_opts();
-       op = getopt_long(argc, argv, command_optstring, command_opts, NULL);
+       op = getopt_long(c, v, command_optstring, command_opts, NULL);
        for (i = 0; cmds[i].cmd; i++)
        {
                if (cmds[i].op == op)
                {
                        active = i;
                        build_opts();
-                       return cmds[i].call(argc, argv);
+                       return cmds[i].call();
                }
        }
        return command_usage("invalid operation");
index 874bdaa..fad598c 100644 (file)
@@ -21,9 +21,6 @@
 #ifndef COMMAND_H_
 #define COMMAND_H_
 
-#define _GNU_SOURCE
-#include <getopt.h>
-
 /**
  * Maximum number of commands.
  */
 #define MAX_LINES 10
 
 typedef struct command_t command_t;
+typedef struct command_option_t command_option_t;
 typedef enum command_type_t command_type_t;
 
 /**
+ * Option specification
+ */
+struct command_option_t {
+       /** long option string of the option */
+       char *name;
+       /** short option character of the option */
+       char op;
+       /** expected argument to option, no/req/opt_argument */
+       int arg;
+       /** description of the option */
+       char *desc;
+};
+
+/**
  * Command specification.
  */
 struct command_t {
        /** Function implementing the command */
-       int (*call)(int, char*[]);
+       int (*call)();
        /** short option character */
        char op;
        /** long option string */
@@ -57,27 +69,13 @@ struct command_t {
        /** usage summary of the command */
        char *line[MAX_LINES];
        /** list of options the command accepts */
-       struct {
-               /** long option string of the option */
-               char *name;
-               /** short option character of the option */
-               char op;
-               /** expected argument to option, no/req/opt_argument */
-               int arg;
-               /** description of the option */
-               char *desc;
-       } options[MAX_OPTIONS];
+       command_option_t options[MAX_OPTIONS];
 };
 
 /**
- * Options of the active command.
- */
-extern struct option command_opts[];
-
-/**
- * Short option string of the active command.
+ * Get the next option, as with getopt.
  */
-extern char command_optstring[];
+int command_getopt(char **arg);
 
 /**
  * Register a command.
index fcdb50a..47eb5fa 100644 (file)
 /**
  * Generate a private key
  */
-static int gen(int argc, char *argv[])
+static int gen()
 {
        key_encoding_type_t form = KEY_PRIV_ASN1_DER;
        key_type_t type = KEY_RSA;
        u_int size = 0;
        private_key_t *key;
        chunk_t encoding;
+       char *arg;
 
        while (TRUE)
        {
-               switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
+               switch (command_getopt(&arg))
                {
                        case 'h':
                                return command_usage(NULL);
                        case 'v':
-                               dbg_level = atoi(optarg);
+                               dbg_level = atoi(arg);
                                continue;
                        case 't':
-                               if (streq(optarg, "rsa"))
+                               if (streq(arg, "rsa"))
                                {
                                        type = KEY_RSA;
                                }
-                               else if (streq(optarg, "ecdsa"))
+                               else if (streq(arg, "ecdsa"))
                                {
                                        type = KEY_ECDSA;
                                }
@@ -50,13 +51,13 @@ static int gen(int argc, char *argv[])
                                }
                                continue;
                        case 'o':
-                               if (!get_form(optarg, &form, FALSE))
+                               if (!get_form(arg, &form, FALSE))
                                {
                                        return command_usage("invalid key output format");
                                }
                                continue;
                        case 's':
-                               size = atoi(optarg);
+                               size = atoi(arg);
                                if (!size)
                                {
                                        return command_usage("invalid key size");
@@ -121,7 +122,6 @@ static void __attribute__ ((constructor))reg()
                        {"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"},
-                       {"debug",       'v', 1, "set debug level, default: 1"},
                }
        });
 }
index d62de39..3e1835d 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <debug.h>
 #include <utils/linked_list.h>
-#include <utils/optionsfrom.h>
 #include <credentials/certificates/certificate.h>
 #include <credentials/certificates/x509.h>
 #include <credentials/certificates/pkcs10.h>
@@ -27,7 +26,7 @@
 /**
  * Issue a certificate using a CA certificate and key
  */
-static int issue(int argc, char *argv[])
+static int issue()
 {
        hash_algorithm_t digest = HASH_SHA1;
        certificate_t *cert_req = NULL, *cert = NULL, *ca =NULL;
@@ -44,42 +43,31 @@ static int issue(int argc, char *argv[])
        time_t not_before, not_after;
        x509_flag_t flags = 0;
        x509_t *x509;
-       options_t *options;
+       char *arg;
 
-       options = options_create();
        san = linked_list_create();
        cdps = linked_list_create();
        ocsp = linked_list_create();
 
        while (TRUE)
        {
-               switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
+               switch (command_getopt(&arg))
                {
                        case 'h':
                                goto usage;
-                       case 'v':
-                               dbg_level = atoi(optarg);
-                               continue;
-                       case '+':
-                               if (!options->from(options, optarg, &argc, &argv, optind))
-                               {
-                                       error = "invalid options file";
-                                       goto usage;
-                               }
-                               continue;
                        case 't':
-                               if (streq(optarg, "pkcs10"))
+                               if (streq(arg, "pkcs10"))
                                {
                                        pkcs10 = TRUE;
                                }
-                               else if (!streq(optarg, "pub"))
+                               else if (!streq(arg, "pub"))
                                {
                                        error = "invalid input type";
                                        goto usage;
                                }
                                continue;
                        case 'g':
-                               digest = get_digest(optarg);
+                               digest = get_digest(arg);
                                if (digest == HASH_UNKNOWN)
                                {
                                        error = "invalid --digest type";
@@ -87,22 +75,22 @@ static int issue(int argc, char *argv[])
                                }
                                continue;
                        case 'i':
-                               file = optarg;
+                               file = arg;
                                continue;
                        case 'c':
-                               cacert = optarg;
+                               cacert = arg;
                                continue;
                        case 'k':
-                               cakey = optarg;
+                               cakey = arg;
                                continue;
                        case 'd':
-                               dn = optarg;
+                               dn = arg;
                                continue;
                        case 'a':
-                               san->insert_last(san, identification_create_from_string(optarg));
+                               san->insert_last(san, identification_create_from_string(arg));
                                continue;
                        case 'l':
-                               lifetime = atoi(optarg);
+                               lifetime = atoi(arg);
                                if (!lifetime)
                                {
                                        error = "invalid --lifetime value";
@@ -110,16 +98,16 @@ static int issue(int argc, char *argv[])
                                }
                                continue;
                        case 's':
-                               hex = optarg;
+                               hex = arg;
                                continue;
                        case 'b':
                                flags |= X509_CA;
                                continue;
                        case 'u':
-                               cdps->insert_last(cdps, optarg);
+                               cdps->insert_last(cdps, arg);
                                continue;
                        case 'o':
-                               ocsp->insert_last(ocsp, optarg);
+                               ocsp->insert_last(ocsp, arg);
                                continue;
                        case EOF:
                                break;
@@ -311,7 +299,6 @@ end:
        san->destroy_offset(san, offsetof(identification_t, destroy));
        cdps->destroy(cdps);
        ocsp->destroy(ocsp);
-       options->destroy(options);
        free(encoding.ptr);
        free(serial.ptr);
 
@@ -326,7 +313,6 @@ usage:
        san->destroy_offset(san, offsetof(identification_t, destroy));
        cdps->destroy(cdps);
        ocsp->destroy(ocsp);
-       options->destroy(options);
        return command_usage(error);
 }
 
@@ -341,8 +327,7 @@ static void __attribute__ ((constructor))reg()
                {"[--in file] [--type pub|pkcs10]",
                 " --cacert file --cakey file --dn subject-dn [--san subjectAltName]+",
                 "[--lifetime days] [--serial hex] [--ca] [--crl uri]+ [--ocsp uri]+",
-                "[--digest md5|sha1|sha224|sha256|sha384|sha512]",
-                "[--options file]"},
+                "[--digest md5|sha1|sha224|sha256|sha384|sha512]"},
                {
                        {"help",        'h', 0, "show usage information"},
                        {"in",          'i', 1, "public key/request file to issue, default: stdin"},
@@ -357,8 +342,6 @@ static void __attribute__ ((constructor))reg()
                        {"crl",         'u', 1, "CRL distribution point URI to include"},
                        {"ocsp",        'o', 1, "OCSP AuthorityInfoAccess URI to include"},
                        {"digest",      'g', 1, "digest for signature creation, default: sha1"},
-                       {"debug",       'v', 1, "set debug level, default: 1"},
-                       {"options",     '+', 1, "read command line options from file"},
                }
        });
 }
index b856a06..c15c119 100644 (file)
@@ -21,7 +21,7 @@
 /**
  * Calculate the keyid of a key/certificate
  */
-static int keyid(int argc, char *argv[])
+static int keyid()
 {
        credential_type_t type = CRED_PRIVATE_KEY;
        int subtype = KEY_RSA;
@@ -31,38 +31,36 @@ static int keyid(int argc, char *argv[])
        char *file = NULL;
        void *cred;
        chunk_t id;
+       char *arg;
 
        while (TRUE)
        {
-               switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
+               switch (command_getopt(&arg))
                {
                        case 'h':
                                return command_usage(NULL);
-                       case 'v':
-                               dbg_level = atoi(optarg);
-                               continue;
                        case 't':
-                               if (streq(optarg, "rsa-priv"))
+                               if (streq(arg, "rsa-priv"))
                                {
                                        type = CRED_PRIVATE_KEY;
                                        subtype = KEY_RSA;
                                }
-                               else if (streq(optarg, "ecdsa-priv"))
+                               else if (streq(arg, "ecdsa-priv"))
                                {
                                        type = CRED_PRIVATE_KEY;
                                        subtype = KEY_ECDSA;
                                }
-                               else if (streq(optarg, "pub"))
+                               else if (streq(arg, "pub"))
                                {
                                        type = CRED_PUBLIC_KEY;
                                        subtype = KEY_ANY;
                                }
-                               else if (streq(optarg, "pkcs10"))
+                               else if (streq(arg, "pkcs10"))
                                {
                                        type = CRED_CERTIFICATE;
                                        subtype = CERT_PKCS10_REQUEST;
                                }
-                               else if (streq(optarg, "x509"))
+                               else if (streq(arg, "x509"))
                                {
                                        type = CRED_CERTIFICATE;
                                        subtype = CERT_X509;
@@ -73,7 +71,7 @@ static int keyid(int argc, char *argv[])
                                }
                                continue;
                        case 'i':
-                               file = optarg;
+                               file = arg;
                                continue;
                        case EOF:
                                break;
@@ -155,13 +153,11 @@ static void __attribute__ ((constructor))reg()
        command_register((command_t)
                { keyid, 'k', "keyid",
                "calculate key identifiers of a key/certificate",
-               {"[--in file] [--type rsa-priv|ecdsa-priv|pub|pkcs10|x509]",
-                "[--debug 0|1|2|3|4]"},
+               {"[--in file] [--type rsa-priv|ecdsa-priv|pub|pkcs10|x509]"},
                {
                        {"help",        'h', 0, "show usage information"},
                        {"in",          'i', 1, "input file, default: stdin"},
                        {"type",        't', 1, "type of key, default: rsa-priv"},
-                       {"debug",       'v', 1, "set debug level, default: 1"},
                }
        });
 }
index 7294179..de0444c 100644 (file)
@@ -21,7 +21,7 @@
 /**
  * Extract a public key from a private key/certificate
  */
-static int pub(int argc, char *argv[])
+static int pub()
 {
        key_encoding_type_t form = KEY_PUB_SPKI_ASN1_DER;
        credential_type_t type = CRED_PRIVATE_KEY;
@@ -32,33 +32,31 @@ static int pub(int argc, char *argv[])
        chunk_t encoding;
        char *file = NULL;
        void *cred;
+       char *arg;
 
        while (TRUE)
        {
-               switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
+               switch (command_getopt(&arg))
                {
                        case 'h':
                                return command_usage(NULL);
-                       case 'v':
-                               dbg_level = atoi(optarg);
-                               continue;
                        case 't':
-                               if (streq(optarg, "rsa"))
+                               if (streq(arg, "rsa"))
                                {
                                        type = CRED_PRIVATE_KEY;
                                        subtype = KEY_RSA;
                                }
-                               else if (streq(optarg, "ecdsa"))
+                               else if (streq(arg, "ecdsa"))
                                {
                                        type = CRED_PRIVATE_KEY;
                                        subtype = KEY_ECDSA;
                                }
-                               else if (streq(optarg, "pkcs10"))
+                               else if (streq(arg, "pkcs10"))
                                {
                                        type = CRED_CERTIFICATE;
                                        subtype = CERT_PKCS10_REQUEST;
                                }
-                               else if (streq(optarg, "x509"))
+                               else if (streq(arg, "x509"))
                                {
                                        type = CRED_CERTIFICATE;
                                        subtype = CERT_X509;
@@ -69,13 +67,13 @@ static int pub(int argc, char *argv[])
                                }
                                continue;
                        case 'f':
-                               if (!get_form(optarg, &form, TRUE))
+                               if (!get_form(arg, &form, TRUE))
                                {
                                        return command_usage("invalid output format");
                                }
                                continue;
                        case 'i':
-                               file = optarg;
+                               file = arg;
                                continue;
                        case EOF:
                                break;
@@ -147,14 +145,12 @@ static void __attribute__ ((constructor))reg()
        command_register((command_t) {
                pub, 'p', "pub",
                "extract the public key from a private key/certificate",
-               {"[--in file] [--type rsa|ecdsa|pkcs10|x509] [--outform der|pem|pgp]",
-                "[--debug 0|1|2|3|4]"},
+               {"[--in file] [--type rsa|ecdsa|pkcs10|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"},
-                       {"debug",       'v', 1, "set debug level, default: 1"},
                }
        });
 }
index 97eb783..5d11acc 100644 (file)
 #include "pki.h"
 
 #include <utils/linked_list.h>
-#include <utils/optionsfrom.h>
 #include <credentials/certificates/certificate.h>
 #include <credentials/certificates/x509.h>
 
 /**
  * Create a self signed certificate.
  */
-static int self(int argc, char *argv[])
+static int self()
 {
        key_type_t type = KEY_RSA;
        hash_algorithm_t digest = HASH_SHA1;
@@ -40,34 +39,26 @@ static int self(int argc, char *argv[])
        chunk_t encoding = chunk_empty;
        time_t not_before, not_after;
        x509_flag_t flags = 0;
-       options_t *options;
+       char *arg;
 
-       options = options_create();
        san = linked_list_create();
        ocsp = linked_list_create();
 
        while (TRUE)
        {
-               switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
+               switch (command_getopt(&arg))
                {
                        case 'h':
                                goto usage;
                        case 'v':
-                               dbg_level = atoi(optarg);
-                               continue;
-                       case '+':
-                               if (!options->from(options, optarg, &argc, &argv, optind))
-                               {
-                                       error = "invalid options file";
-                                       goto usage;
-                               }
+                               dbg_level = atoi(arg);
                                continue;
                        case 't':
-                               if (streq(optarg, "rsa"))
+                               if (streq(arg, "rsa"))
                                {
                                        type = KEY_RSA;
                                }
-                               else if (streq(optarg, "ecdsa"))
+                               else if (streq(arg, "ecdsa"))
                                {
                                        type = KEY_ECDSA;
                                }
@@ -78,7 +69,7 @@ static int self(int argc, char *argv[])
                                }
                                continue;
                        case 'g':
-                               digest = get_digest(optarg);
+                               digest = get_digest(arg);
                                if (digest == HASH_UNKNOWN)
                                {
                                        error = "invalid --digest type";
@@ -86,16 +77,16 @@ static int self(int argc, char *argv[])
                                }
                                continue;
                        case 'i':
-                               file = optarg;
+                               file = arg;
                                continue;
                        case 'd':
-                               dn = optarg;
+                               dn = arg;
                                continue;
                        case 'a':
-                               san->insert_last(san, identification_create_from_string(optarg));
+                               san->insert_last(san, identification_create_from_string(arg));
                                continue;
                        case 'l':
-                               lifetime = atoi(optarg);
+                               lifetime = atoi(arg);
                                if (!lifetime)
                                {
                                        error = "invalid --lifetime value";
@@ -103,13 +94,13 @@ static int self(int argc, char *argv[])
                                }
                                continue;
                        case 's':
-                               hex = optarg;
+                               hex = arg;
                                continue;
                        case 'b':
                                flags |= X509_CA;
                                continue;
                        case 'o':
-                               ocsp->insert_last(ocsp, optarg);
+                               ocsp->insert_last(ocsp, arg);
                                continue;
                        case EOF:
                                break;
@@ -201,7 +192,6 @@ end:
        DESTROY_IF(private);
        san->destroy_offset(san, offsetof(identification_t, destroy));
        ocsp->destroy(ocsp);
-       options->destroy(options);
        free(encoding.ptr);
        free(serial.ptr);
 
@@ -215,7 +205,6 @@ end:
 usage:
        san->destroy_offset(san, offsetof(identification_t, destroy));
        ocsp->destroy(ocsp);
-       options->destroy(options);
        return command_usage(error);
 }
 
@@ -230,8 +219,7 @@ static void __attribute__ ((constructor))reg()
                {"[--in file] [--type rsa|ecdsa]",
                 " --dn distinguished-name [--san subjectAltName]+",
                 "[--lifetime days] [--serial hex] [--ca] [--ocsp uri]+",
-                "[--digest md5|sha1|sha224|sha256|sha384|sha512]",
-                "[--options file]"},
+                "[--digest md5|sha1|sha224|sha256|sha384|sha512]"},
                {
                        {"help",        'h', 0, "show usage information"},
                        {"in",          'i', 1, "private key input file, default: stdin"},
@@ -243,8 +231,6 @@ static void __attribute__ ((constructor))reg()
                        {"ca",          'b', 0, "include CA basicConstraint, default: no"},
                        {"ocsp",        'o', 1, "OCSP AuthorityInfoAccess URI to include"},
                        {"digest",      'g', 1, "digest for signature creation, default: sha1"},
-                       {"debug",       'v', 1, "set debug level, default: 1"},
-                       {"options",     '+', 1, "read command line options from file"},
                }
        });
 }
index 26a6dca..c0595e0 100644 (file)
 /**
  * Verify a certificate signature
  */
-static int verify(int argc, char *argv[])
+static int verify()
 {
        certificate_t *cert, *ca;
        char *file = NULL, *cafile = NULL;
        bool good = FALSE;
+       char *arg;
 
        while (TRUE)
        {
-               switch (getopt_long(argc, argv, command_optstring, command_opts, NULL))
+               switch (command_getopt(&arg))
                {
                        case 'h':
                                return command_usage(NULL);
-                       case 'v':
-                               dbg_level = atoi(optarg);
-                               continue;
                        case 'i':
-                               file = optarg;
+                               file = arg;
                                continue;
                        case 'c':
-                               cafile = optarg;
+                               cafile = arg;
                                continue;
                        case EOF:
                                break;
@@ -132,7 +130,6 @@ static void __attribute__ ((constructor))reg()
                        {"help",        'h', 0, "show usage information"},
                        {"in",          'i', 1, "x509 certifcate to verify, default: stdin"},
                        {"cacert",      'c', 1, "CA certificate, default: verify self signed"},
-                       {"debug",       'v', 1, "set debug level, default: 1"},
                }
        });
 }