File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / src / tool_metalink.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:16 2020 UTC (4 years, 10 months ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    1: /***************************************************************************
    2:  *                                  _   _ ____  _
    3:  *  Project                     ___| | | |  _ \| |
    4:  *                             / __| | | | |_) | |
    5:  *                            | (__| |_| |  _ <| |___
    6:  *                             \___|\___/|_| \_\_____|
    7:  *
    8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
    9:  *
   10:  * This software is licensed as described in the file COPYING, which
   11:  * you should have received as part of this distribution. The terms
   12:  * are also available at https://curl.haxx.se/docs/copyright.html.
   13:  *
   14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
   15:  * copies of the Software, and permit persons to whom the Software is
   16:  * furnished to do so, under the terms of the COPYING file.
   17:  *
   18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
   19:  * KIND, either express or implied.
   20:  *
   21:  ***************************************************************************/
   22: #include "tool_setup.h"
   23: 
   24: #ifdef USE_METALINK
   25: 
   26: #include <sys/stat.h>
   27: #include <stdlib.h>
   28: 
   29: #ifdef HAVE_FCNTL_H
   30: #  include <fcntl.h>
   31: #endif
   32: 
   33: #undef HAVE_NSS_CONTEXT
   34: 
   35: #ifdef USE_OPENSSL
   36: #  include <openssl/md5.h>
   37: #  include <openssl/sha.h>
   38: #elif defined(USE_GNUTLS_NETTLE)
   39: #  include <nettle/md5.h>
   40: #  include <nettle/sha.h>
   41: #  define MD5_CTX    struct md5_ctx
   42: #  define SHA_CTX    struct sha1_ctx
   43: #  define SHA256_CTX struct sha256_ctx
   44: #elif defined(USE_GNUTLS)
   45: #  include <gcrypt.h>
   46: #  define MD5_CTX    gcry_md_hd_t
   47: #  define SHA_CTX    gcry_md_hd_t
   48: #  define SHA256_CTX gcry_md_hd_t
   49: #elif defined(USE_NSS)
   50: #  include <nss.h>
   51: #  include <pk11pub.h>
   52: #  define MD5_CTX    void *
   53: #  define SHA_CTX    void *
   54: #  define SHA256_CTX void *
   55: #  define HAVE_NSS_CONTEXT
   56:    static NSSInitContext *nss_context;
   57: #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
   58:               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
   59:       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
   60:               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
   61: /* For Apple operating systems: CommonCrypto has the functions we need.
   62:    The library's headers are even backward-compatible with OpenSSL's
   63:    headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
   64: 
   65:    These functions are available on Tiger and later, as well as iOS 2.0
   66:    and later. If you're building for an older cat, well, sorry. */
   67: #  define COMMON_DIGEST_FOR_OPENSSL
   68: #  include <CommonCrypto/CommonDigest.h>
   69: #elif defined(USE_WIN32_CRYPTO)
   70: /* For Windows: If no other crypto library is provided, we fallback
   71:    to the hash functions provided within the Microsoft Windows CryptoAPI */
   72: #  include <wincrypt.h>
   73: /* Custom structure in order to store the required provider and hash handle */
   74: struct win32_crypto_hash {
   75:   HCRYPTPROV hCryptProv;
   76:   HCRYPTHASH hHash;
   77: };
   78: /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
   79: #  ifndef ALG_SID_SHA_256
   80: #    define ALG_SID_SHA_256  12
   81: #  endif
   82: #  ifndef CALG_SHA_256
   83: #    define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
   84: #  endif
   85: #  define MD5_CTX    struct win32_crypto_hash
   86: #  define SHA_CTX    struct win32_crypto_hash
   87: #  define SHA256_CTX struct win32_crypto_hash
   88: #else
   89: #  error "Can't compile METALINK support without a crypto library."
   90: #endif
   91: 
   92: #define ENABLE_CURLX_PRINTF
   93: /* use our own printf() functions */
   94: #include "curlx.h"
   95: 
   96: #include "tool_getparam.h"
   97: #include "tool_paramhlp.h"
   98: #include "tool_cfgable.h"
   99: #include "tool_metalink.h"
  100: #include "tool_operate.h"
  101: #include "tool_msgs.h"
  102: 
  103: #include "memdebug.h" /* keep this as LAST include */
  104: 
  105: /* Copied from tool_getparam.c */
  106: #define GetStr(str,val) do { \
  107:   if(*(str)) { \
  108:     free(*(str)); \
  109:     *(str) = NULL; \
  110:   } \
  111:   if((val)) \
  112:     *(str) = strdup((val)); \
  113:   if(!(val)) \
  114:     return PARAM_NO_MEM; \
  115: } while(0)
  116: 
  117: #if defined(USE_OPENSSL)
  118: /* Functions are already defined */
  119: #elif defined(USE_GNUTLS_NETTLE)
  120: 
  121: static int MD5_Init(MD5_CTX *ctx)
  122: {
  123:   md5_init(ctx);
  124:   return 1;
  125: }
  126: 
  127: static void MD5_Update(MD5_CTX *ctx,
  128:                        const unsigned char *input,
  129:                        unsigned int inputLen)
  130: {
  131:   md5_update(ctx, inputLen, input);
  132: }
  133: 
  134: static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
  135: {
  136:   md5_digest(ctx, 16, digest);
  137: }
  138: 
  139: static int SHA1_Init(SHA_CTX *ctx)
  140: {
  141:   sha1_init(ctx);
  142:   return 1;
  143: }
  144: 
  145: static void SHA1_Update(SHA_CTX *ctx,
  146:                         const unsigned char *input,
  147:                         unsigned int inputLen)
  148: {
  149:   sha1_update(ctx, inputLen, input);
  150: }
  151: 
  152: static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
  153: {
  154:   sha1_digest(ctx, 20, digest);
  155: }
  156: 
  157: static int SHA256_Init(SHA256_CTX *ctx)
  158: {
  159:   sha256_init(ctx);
  160:   return 1;
  161: }
  162: 
  163: static void SHA256_Update(SHA256_CTX *ctx,
  164:                           const unsigned char *input,
  165:                           unsigned int inputLen)
  166: {
  167:   sha256_update(ctx, inputLen, input);
  168: }
  169: 
  170: static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
  171: {
  172:   sha256_digest(ctx, 32, digest);
  173: }
  174: 
  175: #elif defined(USE_GNUTLS)
  176: 
  177: static int MD5_Init(MD5_CTX *ctx)
  178: {
  179:   gcry_md_open(ctx, GCRY_MD_MD5, 0);
  180:   return 1;
  181: }
  182: 
  183: static void MD5_Update(MD5_CTX *ctx,
  184:                        const unsigned char *input,
  185:                        unsigned int inputLen)
  186: {
  187:   gcry_md_write(*ctx, input, inputLen);
  188: }
  189: 
  190: static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
  191: {
  192:   memcpy(digest, gcry_md_read(*ctx, 0), 16);
  193:   gcry_md_close(*ctx);
  194: }
  195: 
  196: static int SHA1_Init(SHA_CTX *ctx)
  197: {
  198:   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
  199:   return 1;
  200: }
  201: 
  202: static void SHA1_Update(SHA_CTX *ctx,
  203:                         const unsigned char *input,
  204:                         unsigned int inputLen)
  205: {
  206:   gcry_md_write(*ctx, input, inputLen);
  207: }
  208: 
  209: static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
  210: {
  211:   memcpy(digest, gcry_md_read(*ctx, 0), 20);
  212:   gcry_md_close(*ctx);
  213: }
  214: 
  215: static int SHA256_Init(SHA256_CTX *ctx)
  216: {
  217:   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
  218:   return 1;
  219: }
  220: 
  221: static void SHA256_Update(SHA256_CTX *ctx,
  222:                           const unsigned char *input,
  223:                           unsigned int inputLen)
  224: {
  225:   gcry_md_write(*ctx, input, inputLen);
  226: }
  227: 
  228: static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
  229: {
  230:   memcpy(digest, gcry_md_read(*ctx, 0), 32);
  231:   gcry_md_close(*ctx);
  232: }
  233: 
  234: #elif defined(USE_NSS)
  235: 
  236: static int nss_hash_init(void **pctx, SECOidTag hash_alg)
  237: {
  238:   PK11Context *ctx;
  239: 
  240:   /* we have to initialize NSS if not initialized already */
  241:   if(!NSS_IsInitialized() && !nss_context) {
  242:     static NSSInitParameters params;
  243:     params.length = sizeof(params);
  244:     nss_context = NSS_InitContext("", "", "", "", &params, NSS_INIT_READONLY
  245:         | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
  246:         | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
  247:   }
  248: 
  249:   ctx = PK11_CreateDigestContext(hash_alg);
  250:   if(!ctx)
  251:     return /* failure */ 0;
  252: 
  253:   if(PK11_DigestBegin(ctx) != SECSuccess) {
  254:     PK11_DestroyContext(ctx, PR_TRUE);
  255:     return /* failure */ 0;
  256:   }
  257: 
  258:   *pctx = ctx;
  259:   return /* success */ 1;
  260: }
  261: 
  262: static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
  263: {
  264:   PK11Context *ctx = *pctx;
  265:   unsigned int outlen;
  266:   PK11_DigestFinal(ctx, out, &outlen, len);
  267:   PK11_DestroyContext(ctx, PR_TRUE);
  268: }
  269: 
  270: static int MD5_Init(MD5_CTX *pctx)
  271: {
  272:   return nss_hash_init(pctx, SEC_OID_MD5);
  273: }
  274: 
  275: static void MD5_Update(MD5_CTX *pctx,
  276:                        const unsigned char *input,
  277:                        unsigned int input_len)
  278: {
  279:   PK11_DigestOp(*pctx, input, input_len);
  280: }
  281: 
  282: static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
  283: {
  284:   nss_hash_final(pctx, digest, 16);
  285: }
  286: 
  287: static int SHA1_Init(SHA_CTX *pctx)
  288: {
  289:   return nss_hash_init(pctx, SEC_OID_SHA1);
  290: }
  291: 
  292: static void SHA1_Update(SHA_CTX *pctx,
  293:                         const unsigned char *input,
  294:                         unsigned int input_len)
  295: {
  296:   PK11_DigestOp(*pctx, input, input_len);
  297: }
  298: 
  299: static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
  300: {
  301:   nss_hash_final(pctx, digest, 20);
  302: }
  303: 
  304: static int SHA256_Init(SHA256_CTX *pctx)
  305: {
  306:   return nss_hash_init(pctx, SEC_OID_SHA256);
  307: }
  308: 
  309: static void SHA256_Update(SHA256_CTX *pctx,
  310:                           const unsigned char *input,
  311:                           unsigned int input_len)
  312: {
  313:   PK11_DigestOp(*pctx, input, input_len);
  314: }
  315: 
  316: static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
  317: {
  318:   nss_hash_final(pctx, digest, 32);
  319: }
  320: 
  321: #elif defined(USE_WIN32_CRYPTO)
  322: 
  323: static void win32_crypto_final(struct win32_crypto_hash *ctx,
  324:                                unsigned char *digest,
  325:                                unsigned int digestLen)
  326: {
  327:   unsigned long length;
  328:   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
  329:   if(length == digestLen)
  330:     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
  331:   if(ctx->hHash)
  332:     CryptDestroyHash(ctx->hHash);
  333:   if(ctx->hCryptProv)
  334:     CryptReleaseContext(ctx->hCryptProv, 0);
  335: }
  336: 
  337: static int MD5_Init(MD5_CTX *ctx)
  338: {
  339:   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
  340:                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  341:     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
  342:   }
  343:   return 1;
  344: }
  345: 
  346: static void MD5_Update(MD5_CTX *ctx,
  347:                        const unsigned char *input,
  348:                        unsigned int inputLen)
  349: {
  350:   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
  351: }
  352: 
  353: static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
  354: {
  355:   win32_crypto_final(ctx, digest, 16);
  356: }
  357: 
  358: static int SHA1_Init(SHA_CTX *ctx)
  359: {
  360:   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
  361:                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  362:     CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
  363:   }
  364:   return 1;
  365: }
  366: 
  367: static void SHA1_Update(SHA_CTX *ctx,
  368:                         const unsigned char *input,
  369:                         unsigned int inputLen)
  370: {
  371:   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
  372: }
  373: 
  374: static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
  375: {
  376:   win32_crypto_final(ctx, digest, 20);
  377: }
  378: 
  379: static int SHA256_Init(SHA256_CTX *ctx)
  380: {
  381:   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
  382:                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  383:     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
  384:   }
  385:   return 1;
  386: }
  387: 
  388: static void SHA256_Update(SHA256_CTX *ctx,
  389:                           const unsigned char *input,
  390:                           unsigned int inputLen)
  391: {
  392:   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
  393: }
  394: 
  395: static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
  396: {
  397:   win32_crypto_final(ctx, digest, 32);
  398: }
  399: 
  400: #endif /* CRYPTO LIBS */
  401: 
  402: const digest_params MD5_DIGEST_PARAMS[] = {
  403:   {
  404:     CURLX_FUNCTION_CAST(digest_init_func, MD5_Init),
  405:     CURLX_FUNCTION_CAST(digest_update_func, MD5_Update),
  406:     CURLX_FUNCTION_CAST(digest_final_func, MD5_Final),
  407:     sizeof(MD5_CTX),
  408:     16
  409:   }
  410: };
  411: 
  412: const digest_params SHA1_DIGEST_PARAMS[] = {
  413:   {
  414:     CURLX_FUNCTION_CAST(digest_init_func, SHA1_Init),
  415:     CURLX_FUNCTION_CAST(digest_update_func, SHA1_Update),
  416:     CURLX_FUNCTION_CAST(digest_final_func, SHA1_Final),
  417:     sizeof(SHA_CTX),
  418:     20
  419:   }
  420: };
  421: 
  422: const digest_params SHA256_DIGEST_PARAMS[] = {
  423:   {
  424:     CURLX_FUNCTION_CAST(digest_init_func, SHA256_Init),
  425:     CURLX_FUNCTION_CAST(digest_update_func, SHA256_Update),
  426:     CURLX_FUNCTION_CAST(digest_final_func, SHA256_Final),
  427:     sizeof(SHA256_CTX),
  428:     32
  429:   }
  430: };
  431: 
  432: static const metalink_digest_def SHA256_DIGEST_DEF[] = {
  433:   {"sha-256", SHA256_DIGEST_PARAMS}
  434: };
  435: 
  436: static const metalink_digest_def SHA1_DIGEST_DEF[] = {
  437:   {"sha-1", SHA1_DIGEST_PARAMS}
  438: };
  439: 
  440: static const metalink_digest_def MD5_DIGEST_DEF[] = {
  441:   {"md5", MD5_DIGEST_PARAMS}
  442: };
  443: 
  444: /*
  445:  * The alias of supported hash functions in the order by preference
  446:  * (basically stronger hash comes first). We included "sha-256" and
  447:  * "sha256". The former is the name defined in the IANA registry named
  448:  * "Hash Function Textual Names". The latter is widely (and
  449:  * historically) used in Metalink version 3.
  450:  */
  451: static const metalink_digest_alias digest_aliases[] = {
  452:   {"sha-256", SHA256_DIGEST_DEF},
  453:   {"sha256", SHA256_DIGEST_DEF},
  454:   {"sha-1", SHA1_DIGEST_DEF},
  455:   {"sha1", SHA1_DIGEST_DEF},
  456:   {"md5", MD5_DIGEST_DEF},
  457:   {NULL, NULL}
  458: };
  459: 
  460: static digest_context *digest_init(const digest_params *dparams)
  461: {
  462:   digest_context *ctxt;
  463: 
  464:   /* Create digest context */
  465:   ctxt = malloc(sizeof(*ctxt));
  466: 
  467:   if(!ctxt)
  468:     return ctxt;
  469: 
  470:   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
  471: 
  472:   if(!ctxt->digest_hashctx) {
  473:     free(ctxt);
  474:     return NULL;
  475:   }
  476: 
  477:   ctxt->digest_hash = dparams;
  478: 
  479:   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
  480:     free(ctxt->digest_hashctx);
  481:     free(ctxt);
  482:     return NULL;
  483:   }
  484: 
  485:   return ctxt;
  486: }
  487: 
  488: static int digest_update(digest_context *context,
  489:                          const unsigned char *data,
  490:                          unsigned int len)
  491: {
  492:   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
  493: 
  494:   return 0;
  495: }
  496: 
  497: static int digest_final(digest_context *context, unsigned char *result)
  498: {
  499:   if(result)
  500:     (*context->digest_hash->digest_final)(result, context->digest_hashctx);
  501: 
  502:   free(context->digest_hashctx);
  503:   free(context);
  504: 
  505:   return 0;
  506: }
  507: 
  508: static unsigned char hex_to_uint(const char *s)
  509: {
  510:   char buf[3];
  511:   unsigned long val;
  512:   buf[0] = s[0];
  513:   buf[1] = s[1];
  514:   buf[2] = 0;
  515:   val = strtoul(buf, NULL, 16);
  516:   return (unsigned char)(val&0xff);
  517: }
  518: 
  519: /*
  520:  * Check checksum of file denoted by filename. The expected hash value
  521:  * is given in hex_hash which is hex-encoded string.
  522:  *
  523:  * This function returns 1 if it succeeds or one of the following
  524:  * integers:
  525:  *
  526:  * 0:
  527:  *   Checksum didn't match.
  528:  * -1:
  529:  *   Could not open file; or could not read data from file.
  530:  * -2:
  531:  *   Hash algorithm not available.
  532:  */
  533: static int check_hash(const char *filename,
  534:                       const metalink_digest_def *digest_def,
  535:                       const unsigned char *digest, FILE *error)
  536: {
  537:   unsigned char *result;
  538:   digest_context *dctx;
  539:   int check_ok, flags, fd;
  540: 
  541:   flags = O_RDONLY;
  542: #ifdef O_BINARY
  543:   /* O_BINARY is required in order to avoid binary EOF in text mode */
  544:   flags |= O_BINARY;
  545: #endif
  546: 
  547:   fd = open(filename, flags);
  548:   if(fd == -1) {
  549:     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
  550:             digest_def->hash_name, strerror(errno));
  551:     return -1;
  552:   }
  553: 
  554:   dctx = digest_init(digest_def->dparams);
  555:   if(!dctx) {
  556:     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
  557:             digest_def->hash_name, "failed to initialize hash algorithm");
  558:     close(fd);
  559:     return -2;
  560:   }
  561: 
  562:   result = malloc(digest_def->dparams->digest_resultlen);
  563:   if(!result) {
  564:     close(fd);
  565:     digest_final(dctx, NULL);
  566:     return -1;
  567:   }
  568:   while(1) {
  569:     unsigned char buf[4096];
  570:     ssize_t len = read(fd, buf, sizeof(buf));
  571:     if(len == 0) {
  572:       break;
  573:     }
  574:     else if(len == -1) {
  575:       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
  576:               digest_def->hash_name, strerror(errno));
  577:       digest_final(dctx, result);
  578:       close(fd);
  579:       return -1;
  580:     }
  581:     digest_update(dctx, buf, (unsigned int)len);
  582:   }
  583:   digest_final(dctx, result);
  584:   check_ok = memcmp(result, digest,
  585:                     digest_def->dparams->digest_resultlen) == 0;
  586:   /* sha*sum style verdict output */
  587:   if(check_ok)
  588:     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
  589:             digest_def->hash_name);
  590:   else
  591:     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
  592:             filename, digest_def->hash_name);
  593: 
  594:   free(result);
  595:   close(fd);
  596:   return check_ok;
  597: }
  598: 
  599: int metalink_check_hash(struct GlobalConfig *config,
  600:                         metalinkfile *mlfile,
  601:                         const char *filename)
  602: {
  603:   int rv;
  604:   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
  605:   if(mlfile->checksum == NULL) {
  606:     fprintf(config->errors,
  607:             "Metalink: validating (%s) FAILED (digest missing)\n", filename);
  608:     return -2;
  609:   }
  610:   rv = check_hash(filename, mlfile->checksum->digest_def,
  611:                   mlfile->checksum->digest, config->errors);
  612:   return rv;
  613: }
  614: 
  615: static metalink_checksum *
  616: checksum_from_hex_digest(const metalink_digest_def *digest_def,
  617:                          const char *hex_digest)
  618: {
  619:   metalink_checksum *chksum;
  620:   unsigned char *digest;
  621:   size_t i;
  622:   size_t len = strlen(hex_digest);
  623:   digest = malloc(len/2);
  624:   if(!digest)
  625:     return 0;
  626: 
  627:   for(i = 0; i < len; i += 2) {
  628:     digest[i/2] = hex_to_uint(hex_digest + i);
  629:   }
  630:   chksum = malloc(sizeof(metalink_checksum));
  631:   if(chksum) {
  632:     chksum->digest_def = digest_def;
  633:     chksum->digest = digest;
  634:   }
  635:   else
  636:     free(digest);
  637:   return chksum;
  638: }
  639: 
  640: static metalink_resource *new_metalink_resource(const char *url)
  641: {
  642:   metalink_resource *res;
  643:   res = malloc(sizeof(metalink_resource));
  644:   if(res) {
  645:     res->next = NULL;
  646:     res->url = strdup(url);
  647:     if(!res->url) {
  648:       free(res);
  649:       return NULL;
  650:     }
  651:   }
  652:   return res;
  653: }
  654: 
  655: /* Returns nonzero if hex_digest is properly formatted; that is each
  656:    letter is in [0-9A-Za-z] and the length of the string equals to the
  657:    result length of digest * 2. */
  658: static int check_hex_digest(const char *hex_digest,
  659:                             const metalink_digest_def *digest_def)
  660: {
  661:   size_t i;
  662:   for(i = 0; hex_digest[i]; ++i) {
  663:     char c = hex_digest[i];
  664:     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
  665:          ('A' <= c && c <= 'Z'))) {
  666:       return 0;
  667:     }
  668:   }
  669:   return digest_def->dparams->digest_resultlen * 2 == i;
  670: }
  671: 
  672: static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
  673: {
  674:   metalinkfile *f;
  675:   f = (metalinkfile*)malloc(sizeof(metalinkfile));
  676:   if(!f)
  677:     return NULL;
  678: 
  679:   f->next = NULL;
  680:   f->filename = strdup(fileinfo->name);
  681:   if(!f->filename) {
  682:     free(f);
  683:     return NULL;
  684:   }
  685:   f->checksum = NULL;
  686:   f->resource = NULL;
  687:   if(fileinfo->checksums) {
  688:     const metalink_digest_alias *digest_alias;
  689:     for(digest_alias = digest_aliases; digest_alias->alias_name;
  690:         ++digest_alias) {
  691:       metalink_checksum_t **p;
  692:       for(p = fileinfo->checksums; *p; ++p) {
  693:         if(curl_strequal(digest_alias->alias_name, (*p)->type) &&
  694:            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
  695:           f->checksum =
  696:             checksum_from_hex_digest(digest_alias->digest_def,
  697:                                      (*p)->hash);
  698:           break;
  699:         }
  700:       }
  701:       if(f->checksum) {
  702:         break;
  703:       }
  704:     }
  705:   }
  706:   if(fileinfo->resources) {
  707:     metalink_resource_t **p;
  708:     metalink_resource root, *tail;
  709:     root.next = NULL;
  710:     tail = &root;
  711:     for(p = fileinfo->resources; *p; ++p) {
  712:       metalink_resource *res;
  713:       /* Filter by type if it is non-NULL. In Metalink v3, type
  714:          includes the type of the resource. In curl, we are only
  715:          interested in HTTP, HTTPS and FTP. In addition to them,
  716:          Metalink v3 file may contain bittorrent type URL, which
  717:          points to the BitTorrent metainfo file. We ignore it here.
  718:          In Metalink v4, type was deprecated and all
  719:          fileinfo->resources point to the target file. BitTorrent
  720:          metainfo file URL may be appeared in fileinfo->metaurls.
  721:       */
  722:       if((*p)->type == NULL ||
  723:          curl_strequal((*p)->type, "http") ||
  724:          curl_strequal((*p)->type, "https") ||
  725:          curl_strequal((*p)->type, "ftp") ||
  726:          curl_strequal((*p)->type, "ftps")) {
  727:         res = new_metalink_resource((*p)->url);
  728:         if(res) {
  729:           tail->next = res;
  730:           tail = res;
  731:         }
  732:         else {
  733:           tail = root.next;
  734: 
  735:           /* clean up the linked list */
  736:           while(tail) {
  737:             res = tail->next;
  738:             free(tail->url);
  739:             free(tail);
  740:             tail = res;
  741:           }
  742:           free(f->filename);
  743:           free(f);
  744:           return NULL;
  745:         }
  746:       }
  747:     }
  748:     f->resource = root.next;
  749:   }
  750:   return f;
  751: }
  752: 
  753: int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
  754:                    const char *metalink_url)
  755: {
  756:   metalink_error_t r;
  757:   metalink_t* metalink;
  758:   metalink_file_t **files;
  759:   bool warnings = FALSE;
  760: 
  761:   /* metlaink_parse_final deletes outs->metalink_parser */
  762:   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
  763:   outs->metalink_parser = NULL;
  764:   if(r != 0) {
  765:     return -1;
  766:   }
  767:   if(metalink->files == NULL) {
  768:     fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
  769:             "(missing or invalid file name)\n",
  770:             metalink_url);
  771:     metalink_delete(metalink);
  772:     return -1;
  773:   }
  774:   for(files = metalink->files; *files; ++files) {
  775:     struct getout *url;
  776:     /* Skip an entry which has no resource. */
  777:     if(!(*files)->resources) {
  778:       fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
  779:               "(missing or invalid resource)\n",
  780:               metalink_url);
  781:       continue;
  782:     }
  783:     if(config->url_get ||
  784:        ((config->url_get = config->url_list) != NULL)) {
  785:       /* there's a node here, if it already is filled-in continue to
  786:          find an "empty" node */
  787:       while(config->url_get && (config->url_get->flags & GETOUT_URL))
  788:         config->url_get = config->url_get->next;
  789:     }
  790: 
  791:     /* now there might or might not be an available node to fill in! */
  792: 
  793:     if(config->url_get)
  794:       /* existing node */
  795:       url = config->url_get;
  796:     else
  797:       /* there was no free node, create one! */
  798:       url = new_getout(config);
  799: 
  800:     if(url) {
  801:       metalinkfile *mlfile = new_metalinkfile(*files);
  802:       if(!mlfile)
  803:         break;
  804: 
  805:       if(!mlfile->checksum) {
  806:         warnings = TRUE;
  807:         fprintf(config->global->errors,
  808:                 "Metalink: parsing (%s) WARNING (digest missing)\n",
  809:                 metalink_url);
  810:       }
  811:       /* Set name as url */
  812:       GetStr(&url->url, mlfile->filename);
  813: 
  814:       /* set flag metalink here */
  815:       url->flags |= GETOUT_URL | GETOUT_METALINK;
  816: 
  817:       if(config->metalinkfile_list) {
  818:         config->metalinkfile_last->next = mlfile;
  819:         config->metalinkfile_last = mlfile;
  820:       }
  821:       else {
  822:         config->metalinkfile_list = config->metalinkfile_last = mlfile;
  823:       }
  824:     }
  825:   }
  826:   metalink_delete(metalink);
  827:   return (warnings) ? -2 : 0;
  828: }
  829: 
  830: size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
  831:                          void *userdata)
  832: {
  833:   struct per_transfer *per = userdata;
  834:   struct OutStruct *outs = &per->outs;
  835:   struct OperationConfig *config = per->config;
  836:   int rv;
  837: 
  838:   /*
  839:    * Once that libcurl has called back tool_write_cb() the returned value
  840:    * is checked against the amount that was intended to be written, if
  841:    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
  842:    * point returning a value different from sz*nmemb indicates failure.
  843:    */
  844:   const size_t failure = (sz && nmemb) ? 0 : 1;
  845: 
  846:   if(!config)
  847:     return failure;
  848: 
  849:   rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb);
  850:   if(rv == 0)
  851:     return sz * nmemb;
  852:   else {
  853:     fprintf(config->global->errors, "Metalink: parsing FAILED\n");
  854:     return failure;
  855:   }
  856: }
  857: 
  858: /*
  859:  * Returns nonzero if content_type includes mediatype.
  860:  */
  861: static int check_content_type(const char *content_type, const char *media_type)
  862: {
  863:   const char *ptr = content_type;
  864:   size_t media_type_len = strlen(media_type);
  865:   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
  866:   if(!*ptr) {
  867:     return 0;
  868:   }
  869:   return curl_strnequal(ptr, media_type, media_type_len) &&
  870:     (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' ||
  871:      *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';');
  872: }
  873: 
  874: int check_metalink_content_type(const char *content_type)
  875: {
  876:   return check_content_type(content_type, "application/metalink+xml");
  877: }
  878: 
  879: int count_next_metalink_resource(metalinkfile *mlfile)
  880: {
  881:   int count = 0;
  882:   metalink_resource *res;
  883:   for(res = mlfile->resource; res; res = res->next, ++count);
  884:   return count;
  885: }
  886: 
  887: static void delete_metalink_checksum(metalink_checksum *chksum)
  888: {
  889:   if(chksum == NULL) {
  890:     return;
  891:   }
  892:   Curl_safefree(chksum->digest);
  893:   Curl_safefree(chksum);
  894: }
  895: 
  896: static void delete_metalink_resource(metalink_resource *res)
  897: {
  898:   if(res == NULL) {
  899:     return;
  900:   }
  901:   Curl_safefree(res->url);
  902:   Curl_safefree(res);
  903: }
  904: 
  905: void delete_metalinkfile(metalinkfile *mlfile)
  906: {
  907:   metalink_resource *res;
  908:   if(mlfile == NULL) {
  909:     return;
  910:   }
  911:   Curl_safefree(mlfile->filename);
  912:   delete_metalink_checksum(mlfile->checksum);
  913:   for(res = mlfile->resource; res;) {
  914:     metalink_resource *next;
  915:     next = res->next;
  916:     delete_metalink_resource(res);
  917:     res = next;
  918:   }
  919:   Curl_safefree(mlfile);
  920: }
  921: 
  922: void clean_metalink(struct OperationConfig *config)
  923: {
  924:   if(config) {
  925:     while(config->metalinkfile_list) {
  926:       metalinkfile *mlfile = config->metalinkfile_list;
  927:       config->metalinkfile_list = config->metalinkfile_list->next;
  928:       delete_metalinkfile(mlfile);
  929:     }
  930:     config->metalinkfile_last = 0;
  931:   }
  932: }
  933: 
  934: void metalink_cleanup(void)
  935: {
  936: #ifdef HAVE_NSS_CONTEXT
  937:   if(nss_context) {
  938:     NSS_ShutdownContext(nss_context);
  939:     nss_context = NULL;
  940:   }
  941: #endif
  942: }
  943: 
  944: #endif /* USE_METALINK */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>