"Fossies" - the Fresh Open Source Software Archive

Member "john-1.9.0-jumbo-1/src/keepass2john.c" (30 Mar 2019, 17446 Bytes) of package /linux/privat/john-1.9.0-jumbo-1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "keepass2john.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8.0_vs_1.9.0.

    1 /* keepass2john utility (modified KeeCracker) written in March of 2012
    2  * by Dhiru Kholia. keepass2john processes input KeePass 1.x and 2.x
    3  * database files into a format suitable for use with JtR. This software
    4  * is Copyright (c) 2012, Dhiru Kholia <dhiru.kholia at gmail.com> and it
    5  * is hereby released under GPL license.
    6  *
    7  * KeePass 2.x support is based on KeeCracker - The KeePass 2 Database
    8  * Cracker, http://keecracker.mbw.name/
    9  *
   10  * KeePass 1.x support is based on kppy -  A Python-module to provide
   11  * an API to KeePass 1.x files. https://github.com/raymontag/kppy
   12  * Copyright (C) 2012 Karsten-Kai K├Ânig <kkoenig@posteo.de>
   13  *
   14  * Keyfile support for Keepass 1.x and Keepass 2.x was added by Fist0urs
   15  * <eddy.maaalou at gmail.com>
   16  *
   17  * kppy is free software: you can redistribute it and/or modify it under the terms
   18  * of the GNU General Public License as published by the Free Software Foundation,
   19  * either version 3 of the License, or at your option) any later version.
   20  *
   21  * kppy is distributed in the hope that it will be useful, but WITHOUT ANY
   22  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
   23  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
   24  *
   25  * You should have received a copy of the GNU General Public License along with
   26  * kppy. If not, see <http://www.gnu.org/licenses/>. */
   27 
   28 #if AC_BUILT
   29 #include "autoconfig.h"
   30 #endif
   31 
   32 #include <stdarg.h>
   33 #include <stdio.h>
   34 #include <string.h>
   35 #include <stdlib.h>
   36 #include <stdint.h>
   37 #ifdef _MSC_VER
   38 #include "missing_getopt.h"
   39 #endif
   40 #include <errno.h>
   41 // needs to be above sys/types.h and sys/stat.h for mingw, if -std=c99 used.
   42 #include "jumbo.h"
   43 #include <sys/stat.h>
   44 #include <sys/types.h>
   45 #if  (!AC_BUILT || HAVE_UNISTD_H) && !_MSC_VER
   46 #include <unistd.h> // getopt defined here for unix
   47 #endif
   48 #include "params.h"
   49 #include "memory.h"
   50 
   51 #include "sha2.h"
   52 #include "base64_convert.h"
   53 
   54 const char *extension[] = {".kdbx"};
   55 static char *keyfile = NULL;
   56 
   57 // KeePass 1.x signature
   58 uint32_t FileSignatureOld1 = 0x9AA2D903;
   59 uint32_t FileSignatureOld2 = 0xB54BFB65;
   60 /// <summary>
   61 /// File identifier, first 32-bit value.
   62 /// </summary>
   63 uint32_t FileSignature1 = 0x9AA2D903;
   64 /// <summary>
   65 /// File identifier, second 32-bit value.
   66 /// </summary>
   67 uint32_t FileSignature2 = 0xB54BFB67;
   68 // KeePass 2.x pre-release (alpha and beta) signature
   69 uint32_t FileSignaturePreRelease1 = 0x9AA2D903;
   70 uint32_t FileSignaturePreRelease2 = 0xB54BFB66;
   71 uint32_t FileVersionCriticalMask = 0xFFFF0000;
   72 /// <summary>
   73 /// File version of files saved by the current <c>Kdb4File</c> class.
   74 /// KeePass 2.07 has version 1.01, 2.08 has 1.02, 2.09 has 2.00,
   75 /// 2.10 has 2.02, 2.11 has 2.04, 2.15 has 3.00.
   76 /// The first 2 bytes are critical (i.e. loading will fail, if the
   77 /// file version is too high), the last 2 bytes are informational.
   78 /// </summary>
   79 // uint32_t FileVersion32 = 0x00030000;
   80 uint32_t FileVersion32 = 0x00040000;
   81 uint32_t FileVersion32_4 = 0x00040000;  // from KeePass 2.36 sources
   82 
   83 // We currently support database formats up to KDBX v3.x. KDBX 4.x is not
   84 // supported yet. See "KdbxFile.cs" in KeePass 2.36 for more information on
   85 // KDBX 4.x format.
   86 
   87 enum Kdb4HeaderFieldID
   88 {
   89     EndOfHeader = 0,
   90     CipherID = 2,
   91     MasterSeed = 4,
   92     TransformSeed = 5,  // KDBX 3.1, for backward compatibility only
   93     TransformRounds = 6,  // KDBX 3.1, for backward compatibility only
   94     EncryptionIV = 7,
   95     StreamStartBytes = 9,  // KDBX 3.1, for backward compatibility only
   96     KdfParameters = 11,  // KDBX 4, superseding Transform*
   97 };
   98 
   99 static off_t get_file_size(char * filename)
  100 {
  101     struct stat sb;
  102     if (stat(filename, & sb) != 0) {
  103         fprintf(stderr, "! %s : stat failed, %s\n", filename, strerror(errno));
  104         exit(-2);
  105     }
  106     return sb.st_size;
  107 }
  108 
  109 static void print_hex(unsigned char *str, int len)
  110 {
  111     int i;
  112     for (i = 0; i < len; ++i)
  113         printf("%02x", str[i]);
  114 }
  115 
  116 static uint64_t BytesToUInt64(unsigned char * s, const int s_size)
  117 {
  118     int i;
  119     uint64_t v = 0;
  120 
  121     for (i = 0; i < 8 && i < s_size; i++)
  122         v |= (uint64_t)s[i] << 8 * i;
  123     return v;
  124 }
  125 
  126 static uint32_t fget32(FILE * fp)
  127 {
  128     uint32_t v = (uint32_t)fgetc(fp);
  129     v |= (uint32_t)fgetc(fp) << 8;
  130     v |= (uint32_t)fgetc(fp) << 16;
  131     v |= (uint32_t)fgetc(fp) << 24;
  132     return v;
  133 }
  134 
  135 static uint16_t fget16(FILE * fp)
  136 {
  137     uint32_t v = fgetc(fp);
  138     v |= fgetc(fp) << 8;
  139     return v;
  140 }
  141 
  142 static void warn(const char *fmt, ...)
  143 {
  144     va_list ap;
  145 
  146     va_start(ap, fmt);
  147     if (fmt != NULL)
  148         vfprintf(stderr, fmt, ap);
  149     va_end(ap);
  150     fprintf(stderr, "\n");
  151 
  152     // exit(EXIT_FAILURE);
  153 }
  154 
  155 /* process KeePass 1.x databases */
  156 static void process_old_database(FILE *fp, char* encryptedDatabase)
  157 {
  158     uint32_t enc_flag;
  159     uint32_t version;
  160     unsigned char final_randomseed[16];
  161     unsigned char enc_iv[16];
  162     unsigned char contents_hash[32];
  163     unsigned char transf_randomseed[32];
  164     uint32_t num_groups;
  165     uint32_t num_entries;
  166     uint32_t key_transf_rounds;
  167     unsigned char *buffer;
  168     int64_t filesize = 0;
  169     int64_t datasize;
  170     int algorithm = -1;
  171     char *dbname;
  172     FILE *kfp = NULL;
  173 
  174     /* specific to keyfile handling */
  175     int64_t filesize_keyfile = 0;
  176     SHA256_CTX ctx;
  177     unsigned char hash[32];
  178     int counter;
  179 
  180     enc_flag = fget32(fp);
  181     version = fget32(fp);
  182 
  183     if (fread(final_randomseed, 16, 1, fp) != 1) {
  184         warn("%s: Error: read failed: %s.", encryptedDatabase,
  185             strerror(errno));
  186         return;
  187     }
  188     if (fread(enc_iv, 16, 1, fp) != 1) {
  189         warn("%s: Error: read failed: %s.", encryptedDatabase,
  190             strerror(errno));
  191         return;
  192     }
  193 
  194     num_groups = fget32(fp);
  195     num_entries = fget32(fp);
  196     (void)num_groups;
  197     (void)num_entries;
  198 
  199     if (fread(contents_hash, 32, 1, fp) != 1) {
  200         warn("%s: Error: read failed: %s.", encryptedDatabase,
  201             strerror(errno));
  202         return;
  203     }
  204     if (fread(transf_randomseed, 32, 1, fp) != 1) {
  205         warn("%s: Error: read failed: %s.", encryptedDatabase,
  206             strerror(errno));
  207         return;
  208     }
  209 
  210     key_transf_rounds = fget32(fp);
  211     /* Check if the database is supported */
  212     if ((version & 0xFFFFFF00) != (0x00030002 & 0xFFFFFF00)) {
  213         fprintf(stderr, "! %s : Unsupported file version (%u)!\n", encryptedDatabase, version);
  214         return;
  215     }
  216     /* src/Kdb3Database.cpp from KeePass 0.4.3 is authoritative */
  217     if (enc_flag & 2) {
  218         algorithm = 0; // AES
  219     } else if (enc_flag & 8) {
  220         algorithm = 1; // Twofish
  221     } else {
  222         fprintf(stderr, "! %s : Unsupported file encryption (%u)!\n", encryptedDatabase, enc_flag);
  223         return;
  224     }
  225 
  226     /* keyfile processing */
  227     if (keyfile) {
  228         kfp = fopen(keyfile, "rb");
  229         if (!kfp) {
  230             fprintf(stderr, "! %s : %s\n", keyfile, strerror(errno));
  231             return;
  232         }
  233         filesize_keyfile = (int64_t)get_file_size(keyfile);
  234     }
  235 
  236     dbname = strip_suffixes(basename(encryptedDatabase), extension, 1);
  237     filesize = (int64_t)get_file_size(encryptedDatabase);
  238     datasize = filesize - 124;
  239     if (datasize < 0) {
  240         warn("%s: Error in validating datasize.", encryptedDatabase);
  241         return;
  242     }
  243     // offset (124) field below is not used, we hijack it to convey the
  244     // algorithm.
  245     // printf("%s:$keepass$*1*%d*%d*", dbname, key_transf_rounds, 124);
  246     printf("%s:$keepass$*1*%d*%d*", dbname, key_transf_rounds, algorithm);
  247     print_hex(final_randomseed, 16);
  248     printf("*");
  249     print_hex(transf_randomseed, 32);
  250     printf("*");
  251     print_hex(enc_iv, 16);
  252     printf("*");
  253     print_hex(contents_hash, 32);
  254 
  255     buffer = (unsigned char*)malloc(datasize * sizeof(char));
  256 
  257     /* we inline the content with the hash */
  258     fprintf(stderr, "Inlining %s\n", encryptedDatabase);
  259     printf("*1*%"PRId64"*", datasize);
  260     fseek(fp, 124, SEEK_SET);
  261     if (fread(buffer, datasize, 1, fp) != 1) {
  262         warn("%s: Error: read failed: %s.",
  263                   encryptedDatabase, strerror(errno));
  264         MEM_FREE(buffer);
  265         return;
  266     }
  267 
  268     print_hex(buffer, datasize);
  269     MEM_FREE(buffer);
  270 
  271     if (keyfile) {
  272         buffer = (unsigned char*)malloc(filesize_keyfile * sizeof(char));
  273         printf("*1*64*"); /* inline keyfile content */
  274         if (fread(buffer, filesize_keyfile, 1, kfp) != 1) {
  275             warn("%s: Error: read failed: %s.",
  276                 encryptedDatabase, strerror(errno));
  277             return;
  278         }
  279 
  280         /* as in Keepass 1.x implementation:
  281          *  if filesize_keyfile == 32 then assume byte_array
  282          *  if filesize_keyfile == 64 then assume hex(byte_array)
  283          *  else byte_array = sha256(keyfile_content)
  284          */
  285 
  286         if (filesize_keyfile == 32)
  287             print_hex(buffer, filesize_keyfile);
  288         else if (filesize_keyfile == 64){
  289             for (counter = 0; counter <64; counter++)
  290                 printf("%c", buffer[counter]);
  291         }
  292         else{
  293           /* precompute sha256 to speed-up cracking */
  294           SHA256_Init(&ctx);
  295           SHA256_Update(&ctx, buffer, filesize_keyfile);
  296           SHA256_Final(hash, &ctx);
  297           print_hex(hash, 32);
  298         }
  299         MEM_FREE(buffer);
  300     }
  301     printf("\n");
  302 }
  303 
  304 // Synchronize with KdbxFile.Read.cs from KeePass 2.x
  305 static void process_database(char* encryptedDatabase)
  306 {
  307     // long dataStartOffset;
  308     unsigned long transformRounds = 0;
  309     unsigned char *masterSeed = NULL;
  310     int masterSeedLength = 0;
  311     unsigned char *transformSeed = NULL;
  312     int transformSeedLength = 0;
  313     unsigned char *initializationVectors = NULL;
  314     int initializationVectorsLength = 0;
  315     unsigned char *expectedStartBytes = NULL;
  316     int endReached, expectedStartBytesLength = 0;
  317     uint32_t uSig1, uSig2, uVersion;
  318     FILE *fp;
  319     unsigned char out[32];
  320     char *dbname;
  321     long algorithm = 0;  // 0 -> AES
  322     size_t fsize = 0;
  323 
  324     /* specific to keyfile handling */
  325     unsigned char *buffer;
  326     int64_t filesize_keyfile = 0;
  327     char *p;
  328     char *data;
  329     char b64_decoded[128+1];
  330     FILE *kfp = NULL;
  331     SHA256_CTX ctx;
  332     unsigned char hash[32];
  333     int counter;
  334 
  335     fp = fopen(encryptedDatabase, "rb");
  336     if (!fp) {
  337         fprintf(stderr, "! %s : %s\n", encryptedDatabase, strerror(errno));
  338         return;
  339     }
  340     fseek(fp, 0, SEEK_END);
  341     fsize = ftell(fp);
  342     fseek(fp, 0, SEEK_SET);
  343     uSig1 = fget32(fp);
  344     uSig2 = fget32(fp);
  345     if ((uSig1 == FileSignatureOld1) && (uSig2 == FileSignatureOld2)) {
  346         process_old_database(fp, encryptedDatabase);
  347         fclose(fp);
  348         return;
  349     }
  350     if ((uSig1 == FileSignature1) && (uSig2 == FileSignature2)) {
  351     }
  352     else if ((uSig1 == FileSignaturePreRelease1) && (uSig2 == FileSignaturePreRelease2)) {
  353     }
  354     else {
  355         fprintf(stderr, "! %s : Unknown format: File signature invalid\n", encryptedDatabase);
  356         fclose(fp);
  357         return;
  358     }
  359     uVersion = fget32(fp);
  360     if ((uVersion & FileVersionCriticalMask) > (FileVersion32 & FileVersionCriticalMask)) {
  361         fprintf(stderr, "! %s : Unknown format: File version '%x' unsupported\n", encryptedDatabase, uVersion);
  362         fclose(fp);
  363         return;
  364     }
  365     endReached = 0;
  366     while (!endReached) {
  367         uint32_t uSize;
  368         unsigned char btFieldID = fgetc(fp);
  369         enum Kdb4HeaderFieldID kdbID = btFieldID;
  370         unsigned char *pbData = NULL;
  371 
  372         if (uVersion < FileVersion32_4)
  373             uSize = fget16(fp);
  374         else
  375             uSize = fget32(fp);
  376 
  377         if (fsize * 64 < uSize) {
  378             fprintf(stderr, "uSize too large, is the database corrupt?\n");
  379             goto bailout;
  380         }
  381         if (uSize == 0 && (kdbID != EndOfHeader)) {
  382             fprintf(stderr, "error validating uSize for EndOfHeader, is the database corrupt?\n");
  383             goto bailout;
  384         }
  385         if (uSize > 0) {
  386             pbData = (unsigned char*)malloc(uSize);
  387             if (!pbData || fread(pbData, uSize, 1, fp) != 1) {
  388                 fprintf(stderr, "error allocating / reading pbData, is the database corrupt?\n");
  389                 MEM_FREE(pbData);
  390                 goto bailout;
  391             }
  392         }
  393         switch (kdbID)
  394         {
  395             case EndOfHeader:
  396                 endReached = 1;  // end of header
  397                 MEM_FREE(pbData);
  398                 break;
  399 
  400             case MasterSeed:
  401                 if (masterSeed)
  402                     MEM_FREE(masterSeed);
  403                 masterSeed = pbData;
  404                 masterSeedLength = uSize;
  405                 break;
  406 
  407             case TransformSeed: // Obsolete in FileVersion32_4; for backward compatibility only
  408                 if (transformSeed)
  409                     MEM_FREE(transformSeed);
  410 
  411                 transformSeed = pbData;
  412                 transformSeedLength = uSize;
  413                 break;
  414 
  415             case TransformRounds:  // Obsolete in FileVersion32_4; for backward compatibility only
  416                 if (uSize < 4) {
  417                     fprintf(stderr, "error validating uSize for TransformRounds, is the database corrupt?\n");
  418                     MEM_FREE(pbData);
  419                     goto bailout;
  420                 }
  421                 if (!pbData) {
  422                     fprintf(stderr, "! %s : parsing failed (pbData is NULL), please open a bug if target is valid KeepPass database.\n", encryptedDatabase);
  423                     goto bailout;
  424                 }
  425                 else {
  426                     transformRounds = BytesToUInt64(pbData, uSize);
  427                     MEM_FREE(pbData);
  428                 }
  429                 break;
  430 
  431             case EncryptionIV:
  432                 if (initializationVectors)
  433                     MEM_FREE(initializationVectors);
  434                 initializationVectors = pbData;
  435                 initializationVectorsLength = uSize;
  436                 break;
  437 
  438             case StreamStartBytes:  // Not present in FileVersion32_4
  439                 if (expectedStartBytes)
  440                     MEM_FREE(expectedStartBytes);
  441                 expectedStartBytes = pbData;
  442                 expectedStartBytesLength = uSize;
  443                 break;
  444 
  445             case CipherID:
  446                 // pbData == 31c1f2e6bf714350be5805216afc5aff => AES ("Standard" KDBX 3.1)
  447                 // pbData == d6038a2b8b6f4cb5a524339a31dbb59a => ChaCha20
  448                 // pbData == ad68f29f576f4bb9a36ad47af965346c => TwoFish
  449                 if (uSize < 4) {
  450                     fprintf(stderr, "error validating uSize for CipherID, is the database corrupt?\n");
  451                     MEM_FREE(pbData);
  452                     goto bailout;
  453                 }
  454                 if (memcmp(pbData, "\xd6\x03\x8a\x2b", 4) == 0) {
  455                     // fprintf(stderr, "! %s : ChaCha20 usage is not supported yet!\n", encryptedDatabase);
  456                     // MEM_FREE(pbData);
  457                     algorithm = 2;
  458                     // goto bailout;
  459                 }
  460                 /* if (memcmp(pbData, "\x31\xc1\xf2\xe6", 4) != 0) {
  461                     fprintf(stderr, "! %s : Unsupported CipherID found!\n", encryptedDatabase);
  462                     MEM_FREE(pbData);
  463                     goto bailout;
  464                 } */
  465 
  466             default:
  467                 MEM_FREE(pbData);
  468                 break;
  469         }
  470     }
  471     // dataStartOffset = ftell(fp);
  472     if (transformRounds == 0 && uVersion < FileVersion32_4) {
  473         fprintf(stderr, "! %s : transformRounds can't be 0\n", encryptedDatabase);
  474         goto bailout;
  475     }
  476 #ifdef KEEPASS_DEBUG
  477     fprintf(stderr, "%d, %d, %d, %d\n", masterSeedLength, transformSeedLength, initializationVectorsLength, expectedStartBytesLength);
  478 #endif
  479     if ((uVersion < FileVersion32_4) && (!masterSeed || !transformSeed || !initializationVectors || !expectedStartBytes)) {
  480         fprintf(stderr, "! %s : parsing failed, please open a bug if target is valid KeepPass database.\n", encryptedDatabase);
  481         goto bailout;
  482     }
  483 
  484     if (uVersion >= FileVersion32_4) {
  485         fprintf(stderr, "! %s : File version '%x' is currently not supported!\n", encryptedDatabase, uVersion);
  486         goto bailout;
  487     }
  488 
  489     if (keyfile) {
  490         kfp = fopen(keyfile, "rb");
  491         if (!kfp) {
  492             fprintf(stderr, "! %s : %s\n", keyfile, strerror(errno));
  493             return;
  494         }
  495         filesize_keyfile = (int64_t)get_file_size(keyfile);
  496     }
  497 
  498     dbname = strip_suffixes(basename(encryptedDatabase),extension, 1);
  499     // printf("%s:$keepass$*2*%ld*%ld*", dbname, transformRounds, dataStartOffset);
  500     printf("%s:$keepass$*2*%ld*%ld*", dbname, transformRounds, algorithm);  // dataStartOffset field is now used to convey algorithm information
  501     print_hex(masterSeed, masterSeedLength);
  502     printf("*");
  503     print_hex(transformSeed, transformSeedLength);
  504     printf("*");
  505     print_hex(initializationVectors, initializationVectorsLength);
  506     printf("*");
  507     print_hex(expectedStartBytes, expectedStartBytesLength);
  508     if (fread(out, 32, 1, fp) != 1) {
  509         fprintf(stderr, "error reading encrypted data!\n");
  510         goto bailout;
  511     }
  512     printf("*");
  513     print_hex(out, 32);
  514 
  515     if (keyfile) {
  516         buffer = (unsigned char*)malloc(filesize_keyfile * sizeof(char));
  517         printf("*1*64*"); /* inline keyfile content */
  518         if (fread(buffer, filesize_keyfile, 1, kfp) != 1) {
  519             warn("%s: Error: read failed: %s.",
  520                 encryptedDatabase, strerror(errno));
  521             return;
  522         }
  523 
  524         /* as in Keepass 2.x implementation:
  525          *  if keyfile is an xml, get <Data> content
  526          *  if filesize_keyfile == 32 then assume byte_array
  527          *  if filesize_keyfile == 64 then assume hex(byte_array)
  528          *  else byte_array = sha256(keyfile_content)
  529          */
  530 
  531         if (!memcmp((char *) buffer, "<?xml", 5)
  532             && ((p = strstr((char *) buffer, "<Key>")) != NULL)
  533             && ((p = strstr(p, "<Data>")) != NULL)
  534             )
  535         {
  536             p += strlen("<Data>");
  537             data = p;
  538             p = strstr(p, "</Data>");
  539             printf ("%s", base64_convert_cp(data, e_b64_mime, p - data, b64_decoded, e_b64_hex, sizeof(b64_decoded), flg_Base64_NO_FLAGS, 0));
  540         }
  541         else if (filesize_keyfile == 32)
  542             print_hex(buffer, filesize_keyfile);
  543         else if (filesize_keyfile == 64)
  544         {
  545             for (counter = 0; counter <64; counter++)
  546                 printf("%c", buffer[counter]);
  547         }
  548         else
  549         {
  550           /* precompute sha256 to speed-up cracking */
  551 
  552           SHA256_Init(&ctx);
  553           SHA256_Update(&ctx, buffer, filesize_keyfile);
  554           SHA256_Final(hash, &ctx);
  555           print_hex(hash, 32);
  556         }
  557         MEM_FREE(buffer);
  558     }
  559     printf("\n");
  560 
  561 bailout:
  562     MEM_FREE(masterSeed);
  563     MEM_FREE(transformSeed);
  564     MEM_FREE(initializationVectors);
  565     MEM_FREE(expectedStartBytes);
  566     fclose(fp);
  567 }
  568 
  569 #ifndef HAVE_LIBFUZZER
  570 static int usage(char *name)
  571 {
  572     fprintf(stderr, "Usage: %s [-k <keyfile>] <.kdbx database(s)>\n", name);
  573 
  574     return EXIT_FAILURE;
  575 }
  576 
  577 int main(int argc, char **argv)
  578 {
  579     int c;
  580 
  581     errno = 0;
  582     /* Parse command line */
  583     while ((c = getopt(argc, argv, "k:")) != -1) {
  584         switch (c) {
  585         case 'k':
  586             keyfile = (char *)malloc(strlen(optarg) + 1);
  587             strcpy(keyfile, optarg);
  588             break;
  589         case '?':
  590         default:
  591             return usage(argv[0]);
  592         }
  593     }
  594     argc -= optind;
  595     if (argc == 0)
  596         return usage(argv[0]);
  597     argv += optind;
  598 
  599     while(argc--)
  600         process_database(*argv++);
  601 
  602     return 0;
  603 }
  604 #endif
  605 
  606 #ifdef HAVE_LIBFUZZER
  607 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
  608 {
  609     int fd;
  610     char name[] = "/tmp/libFuzzer-XXXXXX";
  611 
  612     fd = mkstemp(name);  // this approach is somehow faster than the fmemopen way
  613     if (fd < 0) {
  614         fprintf(stderr, "Problem detected while creating the input file, %s, aborting!\n", strerror(errno));
  615         exit(-1);
  616     }
  617     write(fd, data, size);
  618     close(fd);
  619     process_database(name);
  620     remove(name);
  621 
  622     return 0;
  623 }
  624 #endif