[BACK]Return to certhash.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

Annotation of src/usr.bin/openssl/certhash.c, Revision 1.17

1.1       jsing       1: /*
                      2:  * Copyright (c) 2014, 2015 Joel Sing <jsing@openbsd.org>
                      3:  *
                      4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16:
                     17: #include <sys/types.h>
                     18: #include <sys/stat.h>
                     19:
                     20: #include <errno.h>
                     21: #include <dirent.h>
                     22: #include <fcntl.h>
1.2       bcook      23: #include <limits.h>
1.1       jsing      24: #include <stdio.h>
                     25: #include <string.h>
                     26: #include <unistd.h>
                     27:
                     28: #include <openssl/bio.h>
                     29: #include <openssl/evp.h>
                     30: #include <openssl/pem.h>
                     31: #include <openssl/x509.h>
                     32:
                     33: #include "apps.h"
                     34:
                     35: static struct {
                     36:        int dryrun;
                     37:        int verbose;
                     38: } certhash_config;
                     39:
1.17    ! guenther   40: static const struct option certhash_options[] = {
1.1       jsing      41:        {
                     42:                .name = "n",
                     43:                .desc = "Perform a dry-run - do not make any changes",
                     44:                .type = OPTION_FLAG,
                     45:                .opt.flag = &certhash_config.dryrun,
                     46:        },
                     47:        {
                     48:                .name = "v",
                     49:                .desc = "Verbose",
                     50:                .type = OPTION_FLAG,
                     51:                .opt.flag = &certhash_config.verbose,
                     52:        },
                     53:        { NULL },
                     54: };
                     55:
                     56: struct hashinfo {
                     57:        char *filename;
                     58:        char *target;
                     59:        unsigned long hash;
                     60:        unsigned int index;
                     61:        unsigned char fingerprint[EVP_MAX_MD_SIZE];
                     62:        int is_crl;
                     63:        int is_dup;
                     64:        int exists;
                     65:        int changed;
                     66:        struct hashinfo *reference;
                     67:        struct hashinfo *next;
                     68: };
                     69:
                     70: static struct hashinfo *
                     71: hashinfo(const char *filename, unsigned long hash, unsigned char *fingerprint)
                     72: {
                     73:        struct hashinfo *hi;
                     74:
                     75:        if ((hi = calloc(1, sizeof(*hi))) == NULL)
                     76:                return (NULL);
                     77:        if (filename != NULL) {
                     78:                if ((hi->filename = strdup(filename)) == NULL) {
                     79:                        free(hi);
                     80:                        return (NULL);
                     81:                }
                     82:        }
                     83:        hi->hash = hash;
                     84:        if (fingerprint != NULL)
                     85:                memcpy(hi->fingerprint, fingerprint, sizeof(hi->fingerprint));
                     86:
                     87:        return (hi);
                     88: }
                     89:
                     90: static void
                     91: hashinfo_free(struct hashinfo *hi)
                     92: {
1.6       doug       93:        if (hi == NULL)
                     94:                return;
                     95:
1.1       jsing      96:        free(hi->filename);
                     97:        free(hi->target);
                     98:        free(hi);
                     99: }
                    100:
                    101: #ifdef DEBUG
                    102: static void
                    103: hashinfo_print(struct hashinfo *hi)
                    104: {
                    105:        int i;
                    106:
                    107:        printf("hashinfo %s %08lx %u %i\n", hi->filename, hi->hash,
                    108:            hi->index, hi->is_crl);
                    109:        for (i = 0; i < (int)EVP_MAX_MD_SIZE; i++) {
                    110:                printf("%02X%c", hi->fingerprint[i],
                    111:                    (i + 1 == (int)EVP_MAX_MD_SIZE) ? '\n' : ':');
                    112:        }
                    113: }
                    114: #endif
                    115:
                    116: static int
                    117: hashinfo_compare(const void *a, const void *b)
                    118: {
                    119:        struct hashinfo *hia = *(struct hashinfo **)a;
                    120:        struct hashinfo *hib = *(struct hashinfo **)b;
                    121:        int rv;
                    122:
1.8       tedu      123:        rv = hia->hash < hib->hash ? -1 : hia->hash > hib->hash;
1.1       jsing     124:        if (rv != 0)
                    125:                return (rv);
1.3       guenther  126:        rv = memcmp(hia->fingerprint, hib->fingerprint,
                    127:            sizeof(hia->fingerprint));
1.1       jsing     128:        if (rv != 0)
                    129:                return (rv);
                    130:        return strcmp(hia->filename, hib->filename);
                    131: }
                    132:
                    133: static struct hashinfo *
                    134: hashinfo_chain(struct hashinfo *head, struct hashinfo *entry)
                    135: {
                    136:        struct hashinfo *hi = head;
                    137:
                    138:        if (hi == NULL)
                    139:                return (entry);
                    140:        while (hi->next != NULL)
                    141:                hi = hi->next;
                    142:        hi->next = entry;
                    143:
                    144:        return (head);
                    145: }
                    146:
                    147: static void
                    148: hashinfo_chain_free(struct hashinfo *hi)
                    149: {
                    150:        struct hashinfo *next;
                    151:
                    152:        while (hi != NULL) {
                    153:                next = hi->next;
                    154:                hashinfo_free(hi);
                    155:                hi = next;
                    156:        }
                    157: }
                    158:
                    159: static size_t
                    160: hashinfo_chain_length(struct hashinfo *hi)
                    161: {
                    162:        int len = 0;
                    163:
                    164:        while (hi != NULL) {
                    165:                len++;
                    166:                hi = hi->next;
                    167:        }
                    168:        return (len);
                    169: }
                    170:
                    171: static int
                    172: hashinfo_chain_sort(struct hashinfo **head)
                    173: {
                    174:        struct hashinfo **list, *entry;
                    175:        size_t len;
                    176:        int i;
                    177:
                    178:        if (*head == NULL)
                    179:                return (0);
                    180:
                    181:        len = hashinfo_chain_length(*head);
                    182:        if ((list = reallocarray(NULL, len, sizeof(struct hashinfo *))) == NULL)
                    183:                return (-1);
                    184:
                    185:        for (entry = *head, i = 0; entry != NULL; entry = entry->next, i++)
                    186:                list[i] = entry;
                    187:        qsort(list, len, sizeof(struct hashinfo *), hashinfo_compare);
                    188:
                    189:        *head = entry = list[0];
                    190:        for (i = 1; i < len; i++) {
                    191:                entry->next = list[i];
                    192:                entry = list[i];
                    193:        }
                    194:        entry->next = NULL;
                    195:
1.4       beck      196:        free(list);
1.1       jsing     197:        return (0);
                    198: }
                    199:
                    200: static char *
                    201: hashinfo_linkname(struct hashinfo *hi)
                    202: {
                    203:        char *filename;
                    204:
                    205:        if (asprintf(&filename, "%08lx.%s%u", hi->hash,
                    206:            (hi->is_crl ? "r" : ""), hi->index) == -1)
                    207:                return (NULL);
                    208:
                    209:        return (filename);
                    210: }
                    211:
                    212: static int
                    213: filename_is_hash(const char *filename)
                    214: {
                    215:        const char *p = filename;
                    216:
                    217:        while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f'))
                    218:                p++;
                    219:        if (*p++ != '.')
                    220:                return (0);
                    221:        if (*p == 'r')          /* CRL format. */
                    222:                p++;
                    223:        while (*p >= '0' && *p <= '9')
                    224:                p++;
                    225:        if (*p != '\0')
                    226:                return (0);
                    227:
                    228:        return (1);
                    229: }
                    230:
                    231: static int
                    232: filename_is_pem(const char *filename)
                    233: {
                    234:        const char *q, *p = filename;
                    235:
                    236:        if ((q = strchr(p, '\0')) == NULL)
                    237:                return (0);
                    238:        if ((q - p) < 4)
                    239:                return (0);
                    240:        if (strncmp((q - 4), ".pem", 4) != 0)
                    241:                return (0);
                    242:
                    243:        return (1);
                    244: }
                    245:
                    246: static struct hashinfo *
                    247: hashinfo_from_linkname(const char *linkname, const char *target)
                    248: {
                    249:        struct hashinfo *hi = NULL;
                    250:        const char *errstr;
                    251:        char *l, *p, *ep;
                    252:        long long val;
                    253:
                    254:        if ((l = strdup(linkname)) == NULL)
                    255:                goto err;
                    256:        if ((p = strchr(l, '.')) == NULL)
                    257:                goto err;
                    258:        *p++ = '\0';
                    259:
                    260:        if ((hi = hashinfo(linkname, 0, NULL)) == NULL)
                    261:                goto err;
                    262:        if ((hi->target = strdup(target)) == NULL)
                    263:                goto err;
                    264:
                    265:        errno = 0;
                    266:        val = strtoll(l, &ep, 16);
                    267:        if (l[0] == '\0' || *ep != '\0')
                    268:                goto err;
1.9       beck      269:        if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN))
1.1       jsing     270:                goto err;
                    271:        if (val < 0 || val > ULONG_MAX)
                    272:                goto err;
                    273:        hi->hash = (unsigned long)val;
                    274:
                    275:        if (*p == 'r') {
                    276:                hi->is_crl = 1;
                    277:                p++;
                    278:        }
                    279:
                    280:        val = strtonum(p, 0, 0xffffffff, &errstr);
                    281:        if (errstr != NULL)
                    282:                goto err;
                    283:
                    284:        hi->index = (unsigned int)val;
                    285:
                    286:        goto done;
                    287:
1.16      jsing     288:  err:
1.1       jsing     289:        hashinfo_free(hi);
                    290:        hi = NULL;
                    291:
1.16      jsing     292:  done:
1.1       jsing     293:        free(l);
                    294:
                    295:        return (hi);
                    296: }
                    297:
                    298: static struct hashinfo *
                    299: certhash_cert(BIO *bio, const char *filename)
                    300: {
                    301:        unsigned char fingerprint[EVP_MAX_MD_SIZE];
                    302:        struct hashinfo *hi = NULL;
                    303:        const EVP_MD *digest;
                    304:        X509 *cert = NULL;
                    305:        unsigned long hash;
                    306:        unsigned int len;
                    307:
                    308:        if ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL)
                    309:                goto err;
                    310:
                    311:        hash = X509_subject_name_hash(cert);
                    312:
                    313:        digest = EVP_sha256();
                    314:        if (X509_digest(cert, digest, fingerprint, &len) != 1) {
                    315:                fprintf(stderr, "out of memory\n");
                    316:                goto err;
                    317:        }
                    318:
                    319:        hi = hashinfo(filename, hash, fingerprint);
                    320:
1.16      jsing     321:  err:
1.1       jsing     322:        X509_free(cert);
                    323:
                    324:        return (hi);
                    325: }
                    326:
                    327: static struct hashinfo *
                    328: certhash_crl(BIO *bio, const char *filename)
                    329: {
                    330:        unsigned char fingerprint[EVP_MAX_MD_SIZE];
                    331:        struct hashinfo *hi = NULL;
                    332:        const EVP_MD *digest;
                    333:        X509_CRL *crl = NULL;
                    334:        unsigned long hash;
                    335:        unsigned int len;
                    336:
                    337:        if ((crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) == NULL)
                    338:                return (NULL);
                    339:
                    340:        hash = X509_NAME_hash(X509_CRL_get_issuer(crl));
                    341:
                    342:        digest = EVP_sha256();
                    343:        if (X509_CRL_digest(crl, digest, fingerprint, &len) != 1) {
                    344:                fprintf(stderr, "out of memory\n");
                    345:                goto err;
                    346:        }
                    347:
                    348:        hi = hashinfo(filename, hash, fingerprint);
                    349:
1.16      jsing     350:  err:
1.1       jsing     351:        X509_CRL_free(crl);
                    352:
                    353:        return (hi);
                    354: }
                    355:
                    356: static int
                    357: certhash_addlink(struct hashinfo **links, struct hashinfo *hi)
                    358: {
                    359:        struct hashinfo *link = NULL;
                    360:
                    361:        if ((link = hashinfo(NULL, hi->hash, hi->fingerprint)) == NULL)
                    362:                goto err;
                    363:
                    364:        if ((link->filename = hashinfo_linkname(hi)) == NULL)
                    365:                goto err;
                    366:
                    367:        link->reference = hi;
                    368:        link->changed = 1;
                    369:        *links = hashinfo_chain(*links, link);
                    370:        hi->reference = link;
                    371:
                    372:        return (0);
                    373:
1.16      jsing     374:  err:
1.1       jsing     375:        hashinfo_free(link);
                    376:        return (-1);
                    377: }
                    378:
                    379: static void
                    380: certhash_findlink(struct hashinfo *links, struct hashinfo *hi)
                    381: {
                    382:        struct hashinfo *link;
                    383:
                    384:        for (link = links; link != NULL; link = link->next) {
                    385:                if (link->is_crl == hi->is_crl &&
                    386:                    link->hash == hi->hash &&
                    387:                    link->index == hi->index &&
                    388:                    link->reference == NULL) {
                    389:                        link->reference = hi;
                    390:                        if (link->target == NULL ||
                    391:                            strcmp(link->target, hi->filename) != 0)
                    392:                                link->changed = 1;
                    393:                        hi->reference = link;
                    394:                        break;
                    395:                }
                    396:        }
                    397: }
                    398:
                    399: static void
                    400: certhash_index(struct hashinfo *head, const char *name)
                    401: {
                    402:        struct hashinfo *last, *entry;
                    403:        int index = 0;
                    404:
                    405:        last = NULL;
                    406:        for (entry = head; entry != NULL; entry = entry->next) {
                    407:                if (last != NULL) {
                    408:                        if (entry->hash == last->hash) {
1.3       guenther  409:                                if (memcmp(entry->fingerprint,
                    410:                                    last->fingerprint,
1.1       jsing     411:                                    sizeof(entry->fingerprint)) == 0) {
                    412:                                        fprintf(stderr, "WARNING: duplicate %s "
                    413:                                            "in %s (using %s), ignoring...\n",
                    414:                                            name, entry->filename,
                    415:                                            last->filename);
                    416:                                        entry->is_dup = 1;
                    417:                                        continue;
                    418:                                }
                    419:                                index++;
                    420:                        } else {
                    421:                                index = 0;
                    422:                        }
                    423:                }
                    424:                entry->index = index;
                    425:                last = entry;
                    426:        }
                    427: }
                    428:
                    429: static int
                    430: certhash_merge(struct hashinfo **links, struct hashinfo **certs,
                    431:     struct hashinfo **crls)
                    432: {
                    433:        struct hashinfo *cert, *crl;
                    434:
                    435:        /* Pass 1 - sort and index entries. */
                    436:        if (hashinfo_chain_sort(certs) == -1)
                    437:                return (-1);
                    438:        if (hashinfo_chain_sort(crls) == -1)
                    439:                return (-1);
                    440:        certhash_index(*certs, "certificate");
                    441:        certhash_index(*crls, "CRL");
                    442:
                    443:        /* Pass 2 - map to existing links. */
                    444:        for (cert = *certs; cert != NULL; cert = cert->next) {
                    445:                if (cert->is_dup == 1)
                    446:                        continue;
                    447:                certhash_findlink(*links, cert);
                    448:        }
                    449:        for (crl = *crls; crl != NULL; crl = crl->next) {
                    450:                if (crl->is_dup == 1)
                    451:                        continue;
                    452:                certhash_findlink(*links, crl);
                    453:        }
                    454:
                    455:        /* Pass 3 - determine missing links. */
                    456:        for (cert = *certs; cert != NULL; cert = cert->next) {
                    457:                if (cert->is_dup == 1 || cert->reference != NULL)
                    458:                        continue;
                    459:                if (certhash_addlink(links, cert) == -1)
                    460:                        return (-1);
                    461:        }
                    462:        for (crl = *crls; crl != NULL; crl = crl->next) {
                    463:                if (crl->is_dup == 1 || crl->reference != NULL)
                    464:                        continue;
                    465:                if (certhash_addlink(links, crl) == -1)
                    466:                        return (-1);
                    467:        }
                    468:
                    469:        return (0);
                    470: }
                    471:
                    472: static int
1.5       guenther  473: certhash_link(struct dirent *dep, struct hashinfo **links)
1.1       jsing     474: {
                    475:        struct hashinfo *hi = NULL;
1.11      deraadt   476:        char target[PATH_MAX];
1.1       jsing     477:        struct stat sb;
                    478:        int n;
                    479:
1.5       guenther  480:        if (lstat(dep->d_name, &sb) == -1) {
1.1       jsing     481:                fprintf(stderr, "failed to stat %s\n", dep->d_name);
                    482:                return (-1);
                    483:        }
                    484:        if (!S_ISLNK(sb.st_mode))
                    485:                return (0);
                    486:
1.5       guenther  487:        n = readlink(dep->d_name, target, sizeof(target) - 1);
1.1       jsing     488:        if (n == -1) {
                    489:                fprintf(stderr, "failed to readlink %s\n", dep->d_name);
                    490:                return (-1);
                    491:        }
                    492:        target[n] = '\0';
                    493:
                    494:        hi = hashinfo_from_linkname(dep->d_name, target);
                    495:        if (hi == NULL) {
                    496:                fprintf(stderr, "failed to get hash info %s\n", dep->d_name);
                    497:                return (-1);
                    498:        }
                    499:        hi->exists = 1;
                    500:        *links = hashinfo_chain(*links, hi);
                    501:
                    502:        return (0);
                    503: }
                    504:
                    505: static int
1.5       guenther  506: certhash_file(struct dirent *dep, struct hashinfo **certs,
1.1       jsing     507:     struct hashinfo **crls)
                    508: {
                    509:        struct hashinfo *hi = NULL;
                    510:        int has_cert, has_crl;
1.5       guenther  511:        int ret = -1;
1.1       jsing     512:        BIO *bio = NULL;
                    513:        FILE *f;
                    514:
                    515:        has_cert = has_crl = 0;
                    516:
1.5       guenther  517:        if ((f = fopen(dep->d_name, "r")) == NULL) {
                    518:                fprintf(stderr, "failed to fopen %s\n", dep->d_name);
1.1       jsing     519:                goto err;
                    520:        }
                    521:        if ((bio = BIO_new_fp(f, BIO_CLOSE)) == NULL) {
                    522:                fprintf(stderr, "failed to create bio\n");
1.5       guenther  523:                fclose(f);
1.1       jsing     524:                goto err;
                    525:        }
                    526:
                    527:        if ((hi = certhash_cert(bio, dep->d_name)) != NULL) {
                    528:                has_cert = 1;
                    529:                *certs = hashinfo_chain(*certs, hi);
                    530:        }
                    531:
                    532:        if (BIO_reset(bio) != 0) {
                    533:                fprintf(stderr, "BIO_reset failed\n");
                    534:                goto err;
                    535:        }
                    536:
                    537:        if ((hi = certhash_crl(bio, dep->d_name)) != NULL) {
                    538:                has_crl = hi->is_crl = 1;
                    539:                *crls = hashinfo_chain(*crls, hi);
                    540:        }
                    541:
                    542:        if (!has_cert && !has_crl)
                    543:                fprintf(stderr, "PEM file %s does not contain a certificate "
                    544:                    "or CRL, ignoring...\n", dep->d_name);
                    545:
                    546:        ret = 0;
                    547:
1.16      jsing     548:  err:
1.1       jsing     549:        BIO_free(bio);
                    550:
                    551:        return (ret);
                    552: }
                    553:
                    554: static int
                    555: certhash_directory(const char *path)
                    556: {
                    557:        struct hashinfo *links = NULL, *certs = NULL, *crls = NULL, *link;
1.5       guenther  558:        int ret = 0;
1.1       jsing     559:        struct dirent *dep;
                    560:        DIR *dip = NULL;
                    561:
1.5       guenther  562:        if ((dip = opendir(".")) == NULL) {
1.1       jsing     563:                fprintf(stderr, "failed to open directory %s\n", path);
                    564:                goto err;
                    565:        }
                    566:
                    567:        if (certhash_config.verbose)
                    568:                fprintf(stdout, "scanning directory %s\n", path);
                    569:
                    570:        /* Create lists of existing hash links, certs and CRLs. */
                    571:        while ((dep = readdir(dip)) != NULL) {
                    572:                if (filename_is_hash(dep->d_name)) {
1.5       guenther  573:                        if (certhash_link(dep, &links) == -1)
1.1       jsing     574:                                goto err;
                    575:                }
                    576:                if (filename_is_pem(dep->d_name)) {
1.5       guenther  577:                        if (certhash_file(dep, &certs, &crls) == -1)
1.1       jsing     578:                                goto err;
                    579:                }
                    580:        }
                    581:
                    582:        if (certhash_merge(&links, &certs, &crls) == -1) {
                    583:                fprintf(stderr, "certhash merge failed\n");
                    584:                goto err;
                    585:        }
                    586:
                    587:        /* Remove spurious links. */
                    588:        for (link = links; link != NULL; link = link->next) {
                    589:                if (link->exists == 0 ||
                    590:                    (link->reference != NULL && link->changed == 0))
                    591:                        continue;
                    592:                if (certhash_config.verbose)
                    593:                        fprintf(stdout, "%s link %s -> %s\n",
                    594:                            (certhash_config.dryrun ? "would remove" :
                    595:                                "removing"), link->filename, link->target);
                    596:                if (certhash_config.dryrun)
                    597:                        continue;
1.5       guenther  598:                if (unlink(link->filename) == -1) {
1.1       jsing     599:                        fprintf(stderr, "failed to remove link %s\n",
                    600:                            link->filename);
                    601:                        goto err;
                    602:                }
                    603:        }
                    604:
                    605:        /* Create missing links. */
                    606:        for (link = links; link != NULL; link = link->next) {
                    607:                if (link->exists == 1 && link->changed == 0)
                    608:                        continue;
                    609:                if (certhash_config.verbose)
                    610:                        fprintf(stdout, "%s link %s -> %s\n",
                    611:                            (certhash_config.dryrun ? "would create" :
                    612:                                "creating"), link->filename,
                    613:                            link->reference->filename);
                    614:                if (certhash_config.dryrun)
                    615:                        continue;
1.5       guenther  616:                if (symlink(link->reference->filename, link->filename) == -1) {
1.1       jsing     617:                        fprintf(stderr, "failed to create link %s -> %s\n",
                    618:                            link->filename, link->reference->filename);
                    619:                        goto err;
                    620:                }
                    621:        }
                    622:
                    623:        goto done;
                    624:
1.16      jsing     625:  err:
1.1       jsing     626:        ret = 1;
                    627:
1.16      jsing     628:  done:
1.1       jsing     629:        hashinfo_chain_free(certs);
                    630:        hashinfo_chain_free(crls);
                    631:        hashinfo_chain_free(links);
                    632:
                    633:        if (dip != NULL)
                    634:                closedir(dip);
                    635:        return (ret);
                    636: }
                    637:
                    638: static void
                    639: certhash_usage(void)
                    640: {
                    641:        fprintf(stderr, "usage: certhash [-nv] dir ...\n");
                    642:        options_usage(certhash_options);
                    643: }
                    644:
                    645: int
                    646: certhash_main(int argc, char **argv)
                    647: {
                    648:        int argsused;
1.5       guenther  649:        int i, cwdfd, ret = 0;
1.1       jsing     650:
1.12      doug      651:        if (single_execution) {
1.15      deraadt   652:                if (pledge("stdio cpath wpath rpath", NULL) == -1) {
1.12      doug      653:                        perror("pledge");
1.13      doug      654:                        exit(1);
                    655:                }
1.12      doug      656:        }
                    657:
1.1       jsing     658:        memset(&certhash_config, 0, sizeof(certhash_config));
                    659:
                    660:        if (options_parse(argc, argv, certhash_options, NULL, &argsused) != 0) {
                    661:                 certhash_usage();
                    662:                 return (1);
                    663:         }
                    664:
1.7       millert   665:        if ((cwdfd = open(".", O_RDONLY)) == -1) {
1.5       guenther  666:                perror("failed to open current directory");
                    667:                return (1);
                    668:        }
                    669:
                    670:        for (i = argsused; i < argc; i++) {
                    671:                if (chdir(argv[i]) == -1) {
                    672:                        fprintf(stderr,
                    673:                            "failed to change to directory %s: %s\n",
                    674:                            argv[i], strerror(errno));
                    675:                        ret = 1;
                    676:                        continue;
                    677:                }
1.1       jsing     678:                ret |= certhash_directory(argv[i]);
1.5       guenther  679:                if (fchdir(cwdfd) == -1) {
                    680:                        perror("failed to restore current directory");
                    681:                        ret = 1;
                    682:                        break;          /* can't continue safely */
                    683:                }
                    684:        }
                    685:        close(cwdfd);
1.1       jsing     686:
                    687:        return (ret);
                    688: }