[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.18

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