changed tab spacing from 8 to 4
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 10 Apr 2007 19:31:42 +0000 (19:31 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 10 Apr 2007 19:31:42 +0000 (19:31 -0000)
src/openac/build.c
src/openac/openac.c

index bd3df6f..0c6a2be 100644 (file)
 #include "build.h"
 
 static u_char ASN1_group_oid_str[] = {
-    0x06, 0x08,
-          0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04
+       0x06, 0x08,
+                 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x0a ,0x04
 };
 
 static const chunk_t ASN1_group_oid = strchunk(ASN1_group_oid_str);
 
 static u_char ASN1_authorityKeyIdentifier_oid_str[] = {
-    0x06, 0x03,
-          0x55, 0x1d, 0x23
+       0x06, 0x03,
+                 0x55, 0x1d, 0x23
 };
 
 static const chunk_t ASN1_authorityKeyIdentifier_oid
          = strchunk(ASN1_authorityKeyIdentifier_oid_str);
 
 static u_char ASN1_noRevAvail_ext_str[] = {
-    0x30, 0x09,
-          0x06, 0x03,
-               0x55, 0x1d, 0x38,
-         0x04, 0x02,
-               0x05, 0x00
+       0x30, 0x09,
+                 0x06, 0x03,
+                               0x55, 0x1d, 0x38,
+                 0x04, 0x02,
+                               0x05, 0x00
 };
 
 static const chunk_t ASN1_noRevAvail_ext = strchunk(ASN1_noRevAvail_ext_str);
 
-/*
+/**
  * build directoryName
  */
-static chunk_t
-build_directoryName(asn1_t tag, chunk_t name)
+static chunk_t build_directoryName(asn1_t tag, chunk_t name)
 {
-    return asn1_wrap(tag, "m"
-               , asn1_simple_object(ASN1_CONTEXT_C_4, name));
+       return asn1_wrap(tag, "m",
+                               asn1_simple_object(ASN1_CONTEXT_C_4, name));
 }
 
-/*
+/**
  * build holder
  */
-static chunk_t
-build_holder(void)
+static chunk_t build_holder(void)
 {
-    return asn1_wrap(ASN1_SEQUENCE, "mm"
-               , asn1_wrap(ASN1_CONTEXT_C_0, "mm"
-                   , build_directoryName(ASN1_SEQUENCE, user->issuer)
-                   , asn1_simple_object(ASN1_INTEGER, user->serialNumber)
-                 )
-               , build_directoryName(ASN1_CONTEXT_C_1, user->subject));
+       return asn1_wrap(ASN1_SEQUENCE, "mm",
+                               asn1_wrap(ASN1_CONTEXT_C_0, "mm",
+                                       build_directoryName(ASN1_SEQUENCE, user->issuer),
+                                       asn1_simple_object(ASN1_INTEGER, user->serialNumber)
+                               ),
+                               build_directoryName(ASN1_CONTEXT_C_1, user->subject));
 }
 
-/*
+/**
  * build v2Form
  */
-static chunk_t
-build_v2_form(void)
+static chunk_t build_v2_form(void)
 {
-    return asn1_wrap(ASN1_CONTEXT_C_0, "m"
-               , build_directoryName(ASN1_SEQUENCE, signer->subject));
+       return asn1_wrap(ASN1_CONTEXT_C_0, "m",
+                               build_directoryName(ASN1_SEQUENCE, signer->subject));
 }
 
-/*
+/**
  * build attrCertValidityPeriod
  */
-static chunk_t
-build_attr_cert_validity(void)
+static chunk_t build_attr_cert_validity(void)
 {
-    return asn1_wrap(ASN1_SEQUENCE, "mm"
-               , timetoasn1(&notBefore, ASN1_GENERALIZEDTIME) 
-               , timetoasn1(&notAfter,  ASN1_GENERALIZEDTIME));
+       return asn1_wrap(ASN1_SEQUENCE, "mm",
+                               timetoasn1(&notBefore, ASN1_GENERALIZEDTIME),
+                               timetoasn1(&notAfter,  ASN1_GENERALIZEDTIME));
 }
 
-/*
+/**
  * build attributes
  */
-static chunk_t
-build_ietfAttributes(ietfAttrList_t *list)
+static chunk_t build_ietfAttributes(ietfAttrList_t *list)
 {
-    chunk_t ietfAttributes;
-    ietfAttrList_t *item = list;
-    size_t size = 0;
-    u_char *pos;
-
-    /* precalculate the total size of all values */
-    while (item != NULL)
-    {
-       size_t len = item->attr->value.len;
-
-       size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
-       item = item->next;
-    }
-    pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
-
-    while (list != NULL)
-    {
-       ietfAttr_t *attr = list->attr;
-       asn1_t type = ASN1_NULL;
-
-       switch (attr->kind)
+       chunk_t ietfAttributes;
+       ietfAttrList_t *item = list;
+       size_t size = 0;
+       u_char *pos;
+
+       /* precalculate the total size of all values */
+       while (item != NULL)
        {
-       case IETF_ATTRIBUTE_OCTETS:
-           type = ASN1_OCTET_STRING;
-           break;
-       case IETF_ATTRIBUTE_STRING:
-           type = ASN1_UTF8STRING;
-           break;
-       case IETF_ATTRIBUTE_OID:
-           type = ASN1_OID;
-           break;
+               size_t len = item->attr->value.len;
+
+               size += 1 + (len > 0) + (len >= 128) + (len >= 256) + (len >= 65536) + len;
+               item = item->next;
        }
-       mv_chunk(&pos, asn1_simple_object(type, attr->value));
+       pos = build_asn1_object(&ietfAttributes, ASN1_SEQUENCE, size);
 
-       list = list->next;
-    }
+       while (list != NULL)
+       {
+               ietfAttr_t *attr = list->attr;
+               asn1_t type = ASN1_NULL;
+
+               switch (attr->kind)
+               {
+                       case IETF_ATTRIBUTE_OCTETS:
+                               type = ASN1_OCTET_STRING;
+                               break;
+                       case IETF_ATTRIBUTE_STRING:
+                               type = ASN1_UTF8STRING;
+                               break;
+                       case IETF_ATTRIBUTE_OID:
+                               type = ASN1_OID;
+                               break;
+               }
+               mv_chunk(&pos, asn1_simple_object(type, attr->value));
+
+               list = list->next;
+       }
 
-    return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
+       return asn1_wrap(ASN1_SEQUENCE, "m", ietfAttributes);
 }
 
-/*
+/**
  * build attribute type
  */
-static chunk_t
-build_attribute_type(const chunk_t type, chunk_t content)
+static chunk_t build_attribute_type(const chunk_t type, chunk_t content)
 {
-    return asn1_wrap(ASN1_SEQUENCE, "cm"
-               , type
-               , asn1_wrap(ASN1_SET, "m", content));
+       return asn1_wrap(ASN1_SEQUENCE, "cm",
+                               type,
+                               asn1_wrap(ASN1_SET, "m", content));
 }
 
-/*
+/**
  * build attributes
  */
-static chunk_t
-build_attributes(void)
+static chunk_t build_attributes(void)
 {
-     return asn1_wrap(ASN1_SEQUENCE, "m"
-               , build_attribute_type(ASN1_group_oid
-                   , build_ietfAttributes(groups)));
+       return asn1_wrap(ASN1_SEQUENCE, "m",
+                               build_attribute_type(ASN1_group_oid,
+                                       build_ietfAttributes(groups)));
 }
 
-/*
+/**
  * build authorityKeyIdentifier
  */
-static chunk_t
-build_authorityKeyID(x509cert_t *signer)
+static chunk_t build_authorityKeyID(x509cert_t *signer)
 {
-    chunk_t keyIdentifier = (signer->subjectKeyID.ptr == NULL)
-                       ? empty_chunk
-                       : asn1_simple_object(ASN1_CONTEXT_S_0
-                               , signer->subjectKeyID);
-
-    chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1
-                               , signer->issuer);
-
-    chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2
-                               , signer->serialNumber);
-
-    return asn1_wrap(ASN1_SEQUENCE, "cm"
-               , ASN1_authorityKeyIdentifier_oid
-               , asn1_wrap(ASN1_OCTET_STRING, "m"
-                   , asn1_wrap(ASN1_SEQUENCE, "mmm"
-                       , keyIdentifier
-                       , authorityCertIssuer
-                       , authorityCertSerialNumber
-                     )
-                 )
-          );
+       chunk_t keyIdentifier = (signer->subjectKeyID.ptr == NULL)
+                               ? empty_chunk
+                               : asn1_simple_object(ASN1_CONTEXT_S_0,
+                                               signer->subjectKeyID);
+
+       chunk_t authorityCertIssuer = build_directoryName(ASN1_CONTEXT_C_1,
+                                               signer->issuer);
+
+       chunk_t authorityCertSerialNumber = asn1_simple_object(ASN1_CONTEXT_S_2,
+                                               signer->serialNumber);
+
+       return asn1_wrap(ASN1_SEQUENCE, "cm",
+                               ASN1_authorityKeyIdentifier_oid,
+                               asn1_wrap(ASN1_OCTET_STRING, "m",
+                                       asn1_wrap(ASN1_SEQUENCE, "mmm",
+                                               keyIdentifier,
+                                               authorityCertIssuer,
+                                               authorityCertSerialNumber
+                                       )
+                               )
+                  );
 }
 
-/*
+/**
  * build extensions
  */
-static chunk_t
-build_extensions(void)
+static chunk_t build_extensions(void)
 {
-    return asn1_wrap(ASN1_SEQUENCE, "mc"
-               , build_authorityKeyID(signer)
-               , ASN1_noRevAvail_ext);
+       return asn1_wrap(ASN1_SEQUENCE, "mc",
+                               build_authorityKeyID(signer),
+                               ASN1_noRevAvail_ext);
 }
 
-/*
+/**
  * build attributeCertificateInfo
  */
-static chunk_t
-build_attr_cert_info(void)
+static chunk_t build_attr_cert_info(void)
 {
-    return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm"
-               , ASN1_INTEGER_1
-               , build_holder()
-               , build_v2_form()
-               , ASN1_sha1WithRSA_id
-               , asn1_simple_object(ASN1_INTEGER, serial)
-               , build_attr_cert_validity()
-               , build_attributes()
-               , build_extensions());
+       return asn1_wrap(ASN1_SEQUENCE, "cmmcmmmm",
+                               ASN1_INTEGER_1,
+                               build_holder(),
+                               build_v2_form(),
+                               ASN1_sha1WithRSA_id,
+                               asn1_simple_object(ASN1_INTEGER, serial),
+                               build_attr_cert_validity(),
+                               build_attributes(),
+                               build_extensions());
 }
 
-/*
+/**
  * build an X.509 attribute certificate
  */
-chunk_t
-build_attr_cert(void)
+chunk_t build_attr_cert(void)
 {
-    chunk_t attributeCertificateInfo = build_attr_cert_info();
-    chunk_t signatureValue = pkcs1_build_signature(attributeCertificateInfo
-                               , OID_SHA1, signerkey, TRUE);
-
-    return asn1_wrap(ASN1_SEQUENCE, "mcm"
-               , attributeCertificateInfo
-               , ASN1_sha1WithRSA_id
-               , signatureValue);
+       chunk_t attributeCertificateInfo = build_attr_cert_info();
+       chunk_t signatureValue = pkcs1_build_signature(attributeCertificateInfo,
+                                                               OID_SHA1, signerkey, TRUE);
+
+       return asn1_wrap(ASN1_SEQUENCE, "mcm",
+                               attributeCertificateInfo,
+                               ASN1_sha1WithRSA_id,
+                               signatureValue);
 }
index 00f287b..e3f92fb 100755 (executable)
@@ -57,107 +57,113 @@ bool pkcs11_keep_state = FALSE;
 static void
 usage(const char *mess)
 {
-    if (mess != NULL && *mess != '\0')
-       fprintf(stderr, "%s\n", mess);
-    fprintf(stderr
-       , "Usage: openac"
-           " [--help]"
-           " [--version]"
-           " [--optionsfrom <filename>]"
-           " [--quiet]"
+       if (mess != NULL && *mess != '\0')
+       {
+               fprintf(stderr, "%s\n", mess);
+       }
+       fprintf(stderr, "Usage: openac"
+               " [--help]"
+               " [--version]"
+               " [--optionsfrom <filename>]"
+               " [--quiet]"
 #ifdef DEBUG
-           " \\\n\t"
-           "      [--debug-all]"
-           " [--debug-parsing]"
-           " [--debug-raw]"
-           " [--debug-private]"
+               " \\\n\t"
+               "      [--debug-all]"
+               " [--debug-parsing]"
+               " [--debug-raw]"
+               " [--debug-private]"
 #endif
-           " \\\n\t"
-           "      [--days <days>]"
-           " [--hours <hours>]"
-           " \\\n\t"
-           "      [--startdate <YYYYMMDDHHMMSSZ>]"
-           " [--enddate <YYYYMMDDHHMMSSZ>]"
-           " \\\n\t"
-           "      --cert <certfile>"
-           " --key <keyfile>"
-           " [--password <password>]"
-           " \\\n\t"
-           "      --usercert <certfile>"
-           " --groups <attr1,attr2,..>"
-           " --out <filename>"
-           "\n"
-    );
-    exit(mess == NULL? 0 : 1);
+               " \\\n\t"
+               "      [--days <days>]"
+               " [--hours <hours>]"
+               " \\\n\t"
+               "      [--startdate <YYYYMMDDHHMMSSZ>]"
+               " [--enddate <YYYYMMDDHHMMSSZ>]"
+               " \\\n\t"
+               "      --cert <certfile>"
+               " --key <keyfile>"
+               " [--password <password>]"
+               " \\\n\t"
+               "      --usercert <certfile>"
+               " --groups <attr1,attr2,..>"
+               " --out <filename>"
+               "\n"
+       );
+       exit(mess == NULL? 0 : 1);
 }
 
-/*
+/**
  * read the last serial number from file
  */
-static chunk_t
-read_serial(void)
+static chunk_t read_serial(void)
 {
-    MP_INT number;
+       MP_INT number;
 
-    char buf[BUF_LEN];
-    char bytes[BUF_LEN];
+       char buf[BUF_LEN];
+       char bytes[BUF_LEN];
 
-    FILE *fd = fopen(OPENAC_SERIAL, "r");
+       FILE *fd = fopen(OPENAC_SERIAL, "r");
 
-    /* serial number defaults to 0 */
-    size_t len = 1;
-    bytes[0] = 0x00;
+       /* serial number defaults to 0 */
+       size_t len = 1;
+       bytes[0] = 0x00;
 
-    if (fd)
-    {
-       if (fscanf(fd, "%s", buf))
+       if (fd)
        {
-           err_t ugh = ttodata(buf, 0, 16, bytes, BUF_LEN, &len);
-
-           if (ugh != NULL)
-               plog("  error reading serial number from %s: %s"
-                   , OPENAC_SERIAL, ugh);
+               if (fscanf(fd, "%s", buf))
+               {
+                       err_t ugh = ttodata(buf, 0, 16, bytes, BUF_LEN, &len);
+
+                       if (ugh != NULL)
+                       {
+                               plog("  error reading serial number from %s: %s"
+                       , OPENAC_SERIAL, ugh);
+                       }
+               }
+               fclose(fd);
        }
-       fclose(fd);
-    }
-    else
-       plog("  file '%s' does not exist yet - serial number set to 01"
+       else
+       {
+               plog("  file '%s' does not exist yet - serial number set to 01"
            , OPENAC_SERIAL);
+       }
 
-    /* conversion of read serial number to a multiprecision integer
-     * and incrementing it by one
-     * and representing it as a two's complement octet string
-     */
-    n_to_mpz(&number, bytes, len);
-    mpz_add_ui(&number, &number, 0x01);
-    serial = mpz_to_n(&number, 1 + mpz_sizeinbase(&number, 2)/BITS_PER_BYTE);
-    mpz_clear(&number);
-
-    return serial;
+       /**
+        * conversion of read serial number to a multiprecision integer
+        * and incrementing it by one
+        * and representing it as a two's complement octet string
+        */
+       n_to_mpz(&number, bytes, len);
+       mpz_add_ui(&number, &number, 0x01);
+       serial = mpz_to_n(&number, 1 + mpz_sizeinbase(&number, 2)/BITS_PER_BYTE);
+       mpz_clear(&number);
+
+       return serial;
 }
 
-/*
+/**
  * write back the last serial number to file
  */
-static void
-write_serial(chunk_t serial)
+static void write_serial(chunk_t serial)
 {
-    char buf[BUF_LEN];
-
-    FILE *fd = fopen(OPENAC_SERIAL, "w");
-
-    if (fd)
-    {
-       datatot(serial.ptr, serial.len, 16, buf, BUF_LEN);
-       plog("  serial number is %s", buf);
-       fprintf(fd, "%s\n", buf);
-       fclose(fd);
-    }
-    else
-       plog("  could not open file '%s' for writing", OPENAC_SERIAL);
+       char buf[BUF_LEN];
+
+       FILE *fd = fopen(OPENAC_SERIAL, "w");
+
+       if (fd)
+       {
+               datatot(serial.ptr, serial.len, 16, buf, BUF_LEN);
+               plog("  serial number is %s", buf);
+               fprintf(fd, "%s\n", buf);
+               fclose(fd);
+       }
+       else
+       {
+               plog("  could not open file '%s' for writing", OPENAC_SERIAL);
+       }
 }
 
-/*
+/**
  * global variables accessible by both main() and build.c
  */
 x509cert_t *user   = NULL;
@@ -171,268 +177,264 @@ time_t notAfter = 0;
 
 chunk_t serial;
 
-
-int
-main(int argc, char **argv)
+int main(int argc, char **argv)
 {
-    char *keyfile = NULL;
-    char *certfile = NULL;
-    char *usercertfile = NULL;
-    char *outfile = NULL;
+       char *keyfile = NULL;
+       char *certfile = NULL;
+       char *usercertfile = NULL;
+       char *outfile = NULL;
 
-    cert_t signercert = empty_cert;
-    cert_t usercert = empty_cert;
+       cert_t signercert = empty_cert;
+       cert_t usercert = empty_cert;
 
-    chunk_t attr_cert = empty_chunk;
-    x509acert_t *ac = NULL;
+       chunk_t attr_cert = empty_chunk;
+       x509acert_t *ac = NULL;
 
-    const time_t default_validity = 24*3600;   /* 24 hours */
-    time_t validity = 0;
+       const time_t default_validity = 24*3600;        /* 24 hours */
+       time_t validity = 0;
 
-    prompt_pass_t pass;
+       prompt_pass_t pass;
 
-    pass.secret[0] = '\0';
-    pass.prompt = TRUE;
-    pass.fd = STDIN_FILENO;
+       pass.secret[0] = '\0';
+       pass.prompt = TRUE;
+       pass.fd = STDIN_FILENO;
 
-    log_to_stderr = TRUE;
+       log_to_stderr = TRUE;
 
-    /* handle arguments */
-    for (;;)
-    {
+       /* handle arguments */
+       for (;;)
+       {
 #      define DBG_OFFSET 256
-       static const struct option long_opts[] = {
-           /* name, has_arg, flag, val */
-           { "help", no_argument, NULL, 'h' },
-           { "version", no_argument, NULL, 'v' },
-           { "optionsfrom", required_argument, NULL, '+' },
-           { "quiet", no_argument, NULL, 'q' },
-           { "cert", required_argument, NULL, 'c' },
-           { "key", required_argument, NULL, 'k' },
-           { "password", required_argument, NULL, 'p' },
-           { "usercert", required_argument, NULL, 'u' },
-           { "groups", required_argument, NULL, 'g' },
-           { "days", required_argument, NULL, 'D' },
-           { "hours", required_argument, NULL, 'H' },
-           { "startdate", required_argument, NULL, 'S' },
-           { "enddate", required_argument, NULL, 'E' },
-           { "out", required_argument, NULL, 'o' },
+               static const struct option long_opts[] = {
+                       /* name, has_arg, flag, val */
+                       { "help", no_argument, NULL, 'h' },
+                       { "version", no_argument, NULL, 'v' },
+                       { "optionsfrom", required_argument, NULL, '+' },
+                       { "quiet", no_argument, NULL, 'q' },
+                       { "cert", required_argument, NULL, 'c' },
+                               { "key", required_argument, NULL, 'k' },
+                       { "password", required_argument, NULL, 'p' },
+                       { "usercert", required_argument, NULL, 'u' },
+                       { "groups", required_argument, NULL, 'g' },
+                       { "days", required_argument, NULL, 'D' },
+                       { "hours", required_argument, NULL, 'H' },
+                       { "startdate", required_argument, NULL, 'S' },
+                       { "enddate", required_argument, NULL, 'E' },
+                       { "out", required_argument, NULL, 'o' },
 #ifdef DEBUG
-           { "debug-all", no_argument, NULL, 'A' },
-           { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
-           { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
-           { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },
+                       { "debug-all", no_argument, NULL, 'A' },
+                       { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET },
+                       { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET },
+                       { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET },
 #endif
-           { 0,0,0,0 }
-       };
+                       { 0,0,0,0 }
+               };
        
-       int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:", long_opts, NULL);
-
-       /* Note: "breaking" from case terminates loop */
-       switch (c)
-       {
-       case EOF:       /* end of flags */
-           break;
-
-       case 0: /* long option already handled */
-           continue;
-
-       case ':':       /* diagnostic already printed by getopt_long */
-       case '?':       /* diagnostic already printed by getopt_long */
-           usage(NULL);
-           break;   /* not actually reached */
-
-       case 'h':       /* --help */
-           usage(NULL);
-           break;      /* not actually reached */
-
-       case 'v':       /* --version */
-               printf("%s\n", openac_version);
-           exit(0);
-           break;      /* not actually reached */
-
-       case '+':       /* --optionsfrom <filename> */
-           {
-               char path[BUF_LEN];
-
-               if (*optarg == '/')     /* absolute pathname */
-                   strncpy(path, optarg, BUF_LEN);
-               else                    /* relative pathname */
-                   snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg);
-               optionsfrom(path, &argc, &argv, optind, stderr);
-               /* does not return on error */
-           }
-           continue;
-
-       case 'q':       /* --quiet */
-           log_to_stderr = TRUE;
-           continue;
-
-       case 'c':       /* --cert */
-           certfile = optarg;
-           continue;
-
-       case 'k':       /* --key */
-           keyfile = optarg;
-           continue;
-
-       case 'p':       /* --key */
-           pass.prompt = FALSE;
-           strncpy(pass.secret, optarg, sizeof(pass.secret));
-           continue;
-
-       case 'u':       /* --usercert */
-           usercertfile = optarg;
-           continue;
-
-       case 'g':       /* --groups */
-           decode_groups(optarg, &groups);
-           continue;
-
-       case 'D':       /* --days */
-            if (optarg == NULL || !isdigit(optarg[0]))
-                usage("missing number of days");
-            {
-                char *endptr;
-                long days = strtol(optarg, &endptr, 0);
-
-                if (*endptr != '\0' || endptr == optarg
-                || days <= 0)
-                    usage("<days> must be a positive number");
-                validity += 24*3600*days;
-            }
-           continue;
-
-       case 'H':       /* --hours */
-            if (optarg == NULL || !isdigit(optarg[0]))
-                usage("missing number of hours");
-            {
-                char *endptr;
-                long hours = strtol(optarg, &endptr, 0);
-
-                if (*endptr != '\0' || endptr == optarg
-                || hours <= 0)
-                    usage("<hours> must be a positive number");
-                validity += 3600*hours;
-            }
-           continue;
-
-       case 'S':       /* --startdate */
-            if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
-                usage("date format must be YYYYMMDDHHMMSSZ");
-           {
-               chunk_t date = { optarg, 15 };
-               notBefore = asn1totime(&date, ASN1_GENERALIZEDTIME);
-           }
-           continue;
-
-       case 'E':       /* --enddate */
-            if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
-                usage("date format must be YYYYMMDDHHMMSSZ");
-           {
-               chunk_t date = { optarg, 15 };
-               notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME);
-           }
-           continue;
-
-       case 'o':       /* --outt */
-           outfile = optarg;
-           continue        ;
+               int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:", long_opts, NULL);
+
+               /* Note: "breaking" from case terminates loop */
+               switch (c)
+               {
+                       case EOF:       /* end of flags */
+                               break;
+
+                       case 0: /* long option already handled */
+                               continue;
+
+                       case ':':       /* diagnostic already printed by getopt_long */
+                       case '?':       /* diagnostic already printed by getopt_long */
+                               usage(NULL);
+                               break;   /* not actually reached */
+
+                       case 'h':       /* --help */
+                               usage(NULL);
+                               break;  /* not actually reached */
+
+                       case 'v':       /* --version */
+                               printf("%s\n", openac_version);
+                               exit(0);
+                               break;  /* not actually reached */
+
+                       case '+':       /* --optionsfrom <filename> */
+                               {
+                                       char path[BUF_LEN];
+
+                                       if (*optarg == '/')     /* absolute pathname */
+                                       strncpy(path, optarg, BUF_LEN);
+                                       else                    /* relative pathname */
+                                       snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg);
+                                       optionsfrom(path, &argc, &argv, optind, stderr);
+                                       /* does not return on error */
+                               }
+                               continue;
+
+                       case 'q':       /* --quiet */
+                               log_to_stderr = TRUE;
+                               continue;
+
+                       case 'c':       /* --cert */
+                               certfile = optarg;
+                               continue;
+
+                       case 'k':       /* --key */
+                               keyfile = optarg;
+                               continue;
+
+                       case 'p':       /* --key */
+                               pass.prompt = FALSE;
+                               strncpy(pass.secret, optarg, sizeof(pass.secret));
+                               continue;
+
+                       case 'u':       /* --usercert */
+                               usercertfile = optarg;
+                               continue;
+
+                       case 'g':       /* --groups */
+                               decode_groups(optarg, &groups);
+                               continue;
+
+                       case 'D':       /* --days */
+                               if (optarg == NULL || !isdigit(optarg[0]))
+                                       usage("missing number of days");
+                               {
+                                       char *endptr;
+                                       long days = strtol(optarg, &endptr, 0);
+
+                                       if (*endptr != '\0' || endptr == optarg || days <= 0)
+                                               usage("<days> must be a positive number");
+                                       validity += 24*3600*days;
+                               }
+                               continue;
+
+                       case 'H':       /* --hours */
+                               if (optarg == NULL || !isdigit(optarg[0]))
+                                       usage("missing number of hours");
+                               {
+                                       char *endptr;
+                                       long hours = strtol(optarg, &endptr, 0);
+
+                                       if (*endptr != '\0' || endptr == optarg || hours <= 0)
+                                               usage("<hours> must be a positive number");
+                                       validity += 3600*hours;
+                               }
+                               continue;
+
+                       case 'S':       /* --startdate */
+                               if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
+                                       usage("date format must be YYYYMMDDHHMMSSZ");
+                               {
+                                       chunk_t date = { optarg, 15 };
+                                       notBefore = asn1totime(&date, ASN1_GENERALIZEDTIME);
+                               }
+                               continue;
+
+                       case 'E':       /* --enddate */
+                               if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z')
+                                       usage("date format must be YYYYMMDDHHMMSSZ");
+                               {
+                                       chunk_t date = { optarg, 15 };
+                                       notAfter = asn1totime(&date, ASN1_GENERALIZEDTIME);
+                               }
+                               continue;
+
+                       case 'o':       /* --outt */
+                               outfile = optarg;
+                               continue;
 
 #ifdef DEBUG
-       case 'A':       /* --debug-all */
-           base_debugging = DBG_ALL;
-           continue;
+                       case 'A':       /* --debug-all */
+                               base_debugging = DBG_ALL;
+                               continue;
 #endif
-       default:
+                       default:
 #ifdef DEBUG
-           if (c >= DBG_OFFSET)
-           {
-               base_debugging |= c - DBG_OFFSET;
-               continue;
-           }
+                               if (c >= DBG_OFFSET)
+                               {
+                                       base_debugging |= c - DBG_OFFSET;
+                                       continue;
+                               }
 #undef     DBG_OFFSET
 #endif
-           bad_case(c);
+                               bad_case(c);
+               }
+               break;
        }
-       break;
-    }
 
-    init_log("openac");
-    cur_debugging = base_debugging;
+       init_log("openac");
+       cur_debugging = base_debugging;
 
-    if (optind != argc)
-       usage("unexpected argument");
+       if (optind != argc)
+               usage("unexpected argument");
 
-    /* load the signer's RSA private key */
-    if (keyfile != NULL)
-    {
-       err_t ugh = NULL;
+       /* load the signer's RSA private key */
+       if (keyfile != NULL)
+       {
+               err_t ugh = NULL;
+
+               signerkey = alloc_thing(RSA_private_key_t, "RSA private key");
+               ugh = load_rsa_private_key(keyfile, &pass, signerkey);
+
+               if (ugh != NULL)
+               {
+                       free_RSA_private_content(signerkey);
+                       pfree(signerkey);
+                       plog("%s", ugh);
+                       exit(1);
+               }
+       }
 
-       signerkey = alloc_thing(RSA_private_key_t, "RSA private key");
-       ugh = load_rsa_private_key(keyfile, &pass, signerkey);
+       /* load the signer's X.509 certificate */
+       if (certfile != NULL)
+       {
+               if (!load_cert(certfile, "signer cert", &signercert))
+                       exit(1);
+               signer = signercert.u.x509;
+       }
 
-       if (ugh != NULL)
+       /* load the users's X.509 certificate */
+       if (usercertfile != NULL)
        {
-           free_RSA_private_content(signerkey);
-           pfree(signerkey);
-           plog("%s", ugh);
-           exit(1);
+               if (!load_cert(usercertfile, "user cert", &usercert))
+                       exit(1);
+               user = usercert.u.x509;
        }
-    }
-
-    /* load the signer's X.509 certificate */
-    if (certfile != NULL)
-    {
-       if (!load_cert(certfile, "signer cert", &signercert))
-           exit(1);
-       signer = signercert.u.x509;
-    }
-
-    /* load the users's X.509 certificate */
-    if (usercertfile != NULL)
-    {
-       if (!load_cert(usercertfile, "user cert", &usercert))
-           exit(1);
-       user = usercert.u.x509;
-    }
-    
-    /* compute validity interval */
-    validity = (validity)? validity : default_validity;
-    notBefore = (notBefore) ? notBefore : time(NULL);
-    notAfter = (notAfter) ? notAfter : notBefore + validity;
-
-    /* build and parse attribute certificate */
-    if (user != NULL && signer != NULL && signerkey != NULL)
-    {
-       /* read the serial number and increment it by one */
-       serial = read_serial();
-
-       attr_cert = build_attr_cert();
-       ac = alloc_thing(x509acert_t, "x509acert");
-       *ac = empty_ac;
-       parse_ac(attr_cert, ac);
+
+       /* compute validity interval */
+       validity = (validity)? validity : default_validity;
+       notBefore = (notBefore) ? notBefore : time(NULL);
+       notAfter = (notAfter) ? notAfter : notBefore + validity;
+
+       /* build and parse attribute certificate */
+       if (user != NULL && signer != NULL && signerkey != NULL)
+       {
+               /* read the serial number and increment it by one */
+               serial = read_serial();
+
+               attr_cert = build_attr_cert();
+               ac = alloc_thing(x509acert_t, "x509acert");
+               *ac = empty_ac;
+               parse_ac(attr_cert, ac);
        
-       /* write the attribute certificate to file */
-       if (write_chunk(outfile, "attribute cert", attr_cert, 0022, TRUE))
-           write_serial(serial);
-    }
-
-    /* delete all dynamic objects */
-    if (signerkey != NULL)
-    {
-       free_RSA_private_content(signerkey);
-       pfree(signerkey);
-    }
-    free_x509cert(signercert.u.x509);
-    free_x509cert(usercert.u.x509);
-    free_ietfAttrList(groups);
-    free_acert(ac);
-    pfree(serial.ptr);
+               /* write the attribute certificate to file */
+               if (write_chunk(outfile, "attribute cert", attr_cert, 0022, TRUE))
+               write_serial(serial);
+       }
+
+       /* delete all dynamic objects */
+       if (signerkey != NULL)
+       {
+               free_RSA_private_content(signerkey);
+               pfree(signerkey);
+       }
+       free_x509cert(signercert.u.x509);
+       free_x509cert(usercert.u.x509);
+       free_ietfAttrList(groups);
+       free_acert(ac);
+       pfree(serial.ptr);
 
 #ifdef LEAK_DETECTIVE
-    report_leaks();
+       report_leaks();
 #endif /* LEAK_DETECTIVE */
-    close_log();
-    exit(0);
+       close_log();
+       exit(0);
 }