tool_metalink.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "tool_setup.h"
00023 
00024 #ifdef USE_METALINK
00025 
00026 #include <sys/stat.h>
00027 #include <stdlib.h>
00028 
00029 #ifdef HAVE_FCNTL_H
00030 #  include <fcntl.h>
00031 #endif
00032 
00033 #ifdef USE_OPENSSL
00034 #  include <openssl/md5.h>
00035 #  include <openssl/sha.h>
00036 #elif defined(USE_GNUTLS_NETTLE)
00037 #  include <nettle/md5.h>
00038 #  include <nettle/sha.h>
00039 #  define MD5_CTX    struct md5_ctx
00040 #  define SHA_CTX    struct sha1_ctx
00041 #  define SHA256_CTX struct sha256_ctx
00042 #elif defined(USE_GNUTLS)
00043 #  include <gcrypt.h>
00044 #  define MD5_CTX    gcry_md_hd_t
00045 #  define SHA_CTX    gcry_md_hd_t
00046 #  define SHA256_CTX gcry_md_hd_t
00047 #elif defined(USE_NSS)
00048 #  include <nss.h>
00049 #  include <pk11pub.h>
00050 #  define MD5_CTX    void *
00051 #  define SHA_CTX    void *
00052 #  define SHA256_CTX void *
00053    static NSSInitContext *nss_context;
00054 #elif defined(USE_POLARSSL)
00055 #  include <polarssl/md5.h>
00056 #  include <polarssl/sha1.h>
00057 #  include <polarssl/sha256.h>
00058 #  define MD5_CTX    md5_context
00059 #  define SHA_CTX    sha1_context
00060 #  define SHA256_CTX sha256_context
00061 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
00062               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
00063       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
00064               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
00065 /* For Apple operating systems: CommonCrypto has the functions we need.
00066    The library's headers are even backward-compatible with OpenSSL's
00067    headers as long as we define COMMON_DIGEST_FOR_OPENSSL first.
00068 
00069    These functions are available on Tiger and later, as well as iOS 2.0
00070    and later. If you're building for an older cat, well, sorry. */
00071 #  define COMMON_DIGEST_FOR_OPENSSL
00072 #  include <CommonCrypto/CommonDigest.h>
00073 #elif defined(_WIN32)
00074 /* For Windows: If no other crypto library is provided, we fallback
00075    to the hash functions provided within the Microsoft Windows CryptoAPI */
00076 #  include <wincrypt.h>
00077 /* Custom structure in order to store the required provider and hash handle */
00078 struct win32_crypto_hash {
00079   HCRYPTPROV hCryptProv;
00080   HCRYPTHASH hHash;
00081 };
00082 /* Custom Microsoft AES Cryptographic Provider defines required for MinGW */
00083 #  ifndef ALG_SID_SHA_256
00084 #    define ALG_SID_SHA_256  12
00085 #  endif
00086 #  ifndef CALG_SHA_256
00087 #    define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
00088 #  endif
00089 #  define MD5_CTX    struct win32_crypto_hash
00090 #  define SHA_CTX    struct win32_crypto_hash
00091 #  define SHA256_CTX struct win32_crypto_hash
00092 #else
00093 #  error "Can't compile METALINK support without a crypto library."
00094 #endif
00095 
00096 #define ENABLE_CURLX_PRINTF
00097 /* use our own printf() functions */
00098 #include "curlx.h"
00099 
00100 #include "tool_getparam.h"
00101 #include "tool_paramhlp.h"
00102 #include "tool_cfgable.h"
00103 #include "tool_metalink.h"
00104 #include "tool_msgs.h"
00105 
00106 #include "memdebug.h" /* keep this as LAST include */
00107 
00108 /* Copied from tool_getparam.c */
00109 #define GetStr(str,val) do { \
00110   if(*(str)) { \
00111     free(*(str)); \
00112     *(str) = NULL; \
00113   } \
00114   if((val)) \
00115     *(str) = strdup((val)); \
00116   if(!(val)) \
00117     return PARAM_NO_MEM; \
00118 } WHILE_FALSE
00119 
00120 #ifdef USE_GNUTLS_NETTLE
00121 
00122 static int MD5_Init(MD5_CTX *ctx)
00123 {
00124   md5_init(ctx);
00125   return 1;
00126 }
00127 
00128 static void MD5_Update(MD5_CTX *ctx,
00129                        const unsigned char *input,
00130                        unsigned int inputLen)
00131 {
00132   md5_update(ctx, inputLen, input);
00133 }
00134 
00135 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00136 {
00137   md5_digest(ctx, 16, digest);
00138 }
00139 
00140 static int SHA1_Init(SHA_CTX *ctx)
00141 {
00142   sha1_init(ctx);
00143   return 1;
00144 }
00145 
00146 static void SHA1_Update(SHA_CTX *ctx,
00147                         const unsigned char *input,
00148                         unsigned int inputLen)
00149 {
00150   sha1_update(ctx, inputLen, input);
00151 }
00152 
00153 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00154 {
00155   sha1_digest(ctx, 20, digest);
00156 }
00157 
00158 static int SHA256_Init(SHA256_CTX *ctx)
00159 {
00160   sha256_init(ctx);
00161   return 1;
00162 }
00163 
00164 static void SHA256_Update(SHA256_CTX *ctx,
00165                           const unsigned char *input,
00166                           unsigned int inputLen)
00167 {
00168   sha256_update(ctx, inputLen, input);
00169 }
00170 
00171 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00172 {
00173   sha256_digest(ctx, 32, digest);
00174 }
00175 
00176 #elif defined(USE_GNUTLS)
00177 
00178 static int MD5_Init(MD5_CTX *ctx)
00179 {
00180   gcry_md_open(ctx, GCRY_MD_MD5, 0);
00181   return 1;
00182 }
00183 
00184 static void MD5_Update(MD5_CTX *ctx,
00185                        const unsigned char *input,
00186                        unsigned int inputLen)
00187 {
00188   gcry_md_write(*ctx, input, inputLen);
00189 }
00190 
00191 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00192 {
00193   memcpy(digest, gcry_md_read(*ctx, 0), 16);
00194   gcry_md_close(*ctx);
00195 }
00196 
00197 static int SHA1_Init(SHA_CTX *ctx)
00198 {
00199   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
00200   return 1;
00201 }
00202 
00203 static void SHA1_Update(SHA_CTX *ctx,
00204                         const unsigned char *input,
00205                         unsigned int inputLen)
00206 {
00207   gcry_md_write(*ctx, input, inputLen);
00208 }
00209 
00210 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00211 {
00212   memcpy(digest, gcry_md_read(*ctx, 0), 20);
00213   gcry_md_close(*ctx);
00214 }
00215 
00216 static int SHA256_Init(SHA256_CTX *ctx)
00217 {
00218   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
00219   return 1;
00220 }
00221 
00222 static void SHA256_Update(SHA256_CTX *ctx,
00223                           const unsigned char *input,
00224                           unsigned int inputLen)
00225 {
00226   gcry_md_write(*ctx, input, inputLen);
00227 }
00228 
00229 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00230 {
00231   memcpy(digest, gcry_md_read(*ctx, 0), 32);
00232   gcry_md_close(*ctx);
00233 }
00234 
00235 #elif defined(USE_NSS)
00236 
00237 static int nss_hash_init(void **pctx, SECOidTag hash_alg)
00238 {
00239   PK11Context *ctx;
00240 
00241   /* we have to initialize NSS if not initialized alraedy */
00242   if(!NSS_IsInitialized() && !nss_context) {
00243     static NSSInitParameters params;
00244     params.length = sizeof params;
00245     nss_context = NSS_InitContext("", "", "", "", &params, NSS_INIT_READONLY
00246         | NSS_INIT_NOCERTDB   | NSS_INIT_NOMODDB       | NSS_INIT_FORCEOPEN
00247         | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
00248   }
00249 
00250   ctx = PK11_CreateDigestContext(hash_alg);
00251   if(!ctx)
00252     return /* failure */ 0;
00253 
00254   if(PK11_DigestBegin(ctx) != SECSuccess) {
00255     PK11_DestroyContext(ctx, PR_TRUE);
00256     return /* failure */ 0;
00257   }
00258 
00259   *pctx = ctx;
00260   return /* success */ 1;
00261 }
00262 
00263 static void nss_hash_final(void **pctx, unsigned char *out, unsigned int len)
00264 {
00265   PK11Context *ctx = *pctx;
00266   unsigned int outlen;
00267   PK11_DigestFinal(ctx, out, &outlen, len);
00268   PK11_DestroyContext(ctx, PR_TRUE);
00269 }
00270 
00271 static int MD5_Init(MD5_CTX *pctx)
00272 {
00273   return nss_hash_init(pctx, SEC_OID_MD5);
00274 }
00275 
00276 static void MD5_Update(MD5_CTX *pctx,
00277                        const unsigned char *input,
00278                        unsigned int input_len)
00279 {
00280   PK11_DigestOp(*pctx, input, input_len);
00281 }
00282 
00283 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
00284 {
00285   nss_hash_final(pctx, digest, 16);
00286 }
00287 
00288 static int SHA1_Init(SHA_CTX *pctx)
00289 {
00290   return nss_hash_init(pctx, SEC_OID_SHA1);
00291 }
00292 
00293 static void SHA1_Update(SHA_CTX *pctx,
00294                         const unsigned char *input,
00295                         unsigned int input_len)
00296 {
00297   PK11_DigestOp(*pctx, input, input_len);
00298 }
00299 
00300 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
00301 {
00302   nss_hash_final(pctx, digest, 20);
00303 }
00304 
00305 static int SHA256_Init(SHA256_CTX *pctx)
00306 {
00307   return nss_hash_init(pctx, SEC_OID_SHA256);
00308 }
00309 
00310 static void SHA256_Update(SHA256_CTX *pctx,
00311                           const unsigned char *input,
00312                           unsigned int input_len)
00313 {
00314   PK11_DigestOp(*pctx, input, input_len);
00315 }
00316 
00317 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *pctx)
00318 {
00319   nss_hash_final(pctx, digest, 32);
00320 }
00321 
00322 #elif defined(USE_POLARSSL)
00323 
00324 static int MD5_Init(MD5_CTX *ctx)
00325 {
00326   md5_starts(ctx);
00327   return 1;
00328 }
00329 
00330 static void MD5_Update(MD5_CTX *ctx,
00331                        const unsigned char *input,
00332                        unsigned int inputLen)
00333 {
00334   md5_update(ctx, input, inputLen);
00335 }
00336 
00337 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00338 {
00339   md5_finish(ctx, digest);
00340 }
00341 
00342 static int SHA1_Init(SHA_CTX *ctx)
00343 {
00344   sha1_starts(ctx);
00345   return 1;
00346 }
00347 
00348 static void SHA1_Update(SHA_CTX *ctx,
00349                         const unsigned char *input,
00350                         unsigned int inputLen)
00351 {
00352   sha1_update(ctx, input, inputLen);
00353 }
00354 
00355 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00356 {
00357   sha1_finish(ctx, digest);
00358 }
00359 
00360 static int SHA256_Init(SHA256_CTX *ctx)
00361 {
00362   sha256_starts(ctx, 0); /* 0 = sha256 */
00363   return 1;
00364 }
00365 
00366 static void SHA256_Update(SHA256_CTX *ctx,
00367                           const unsigned char *input,
00368                           unsigned int inputLen)
00369 {
00370   sha256_update(ctx, input, inputLen);
00371 }
00372 
00373 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00374 {
00375   sha256_finish(ctx, digest);
00376 }
00377 
00378 #elif defined(_WIN32) && !defined(USE_OPENSSL)
00379 
00380 static void win32_crypto_final(struct win32_crypto_hash *ctx,
00381                                unsigned char *digest,
00382                                unsigned int digestLen)
00383 {
00384   unsigned long length;
00385   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
00386   if(length == digestLen)
00387     CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
00388   if(ctx->hHash)
00389     CryptDestroyHash(ctx->hHash);
00390   if(ctx->hCryptProv)
00391     CryptReleaseContext(ctx->hCryptProv, 0);
00392 }
00393 
00394 static int MD5_Init(MD5_CTX *ctx)
00395 {
00396   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00397                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
00398     CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
00399   }
00400   return 1;
00401 }
00402 
00403 static void MD5_Update(MD5_CTX *ctx,
00404                        const unsigned char *input,
00405                        unsigned int inputLen)
00406 {
00407   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00408 }
00409 
00410 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
00411 {
00412   win32_crypto_final(ctx, digest, 16);
00413 }
00414 
00415 static int SHA1_Init(SHA_CTX *ctx)
00416 {
00417   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00418                          PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
00419     CryptCreateHash(ctx->hCryptProv, CALG_SHA1, 0, 0, &ctx->hHash);
00420   }
00421   return 1;
00422 }
00423 
00424 static void SHA1_Update(SHA_CTX *ctx,
00425                         const unsigned char *input,
00426                         unsigned int inputLen)
00427 {
00428   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00429 }
00430 
00431 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
00432 {
00433   win32_crypto_final(ctx, digest, 20);
00434 }
00435 
00436 static int SHA256_Init(SHA256_CTX *ctx)
00437 {
00438   if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
00439                          PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
00440     CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
00441   }
00442   return 1;
00443 }
00444 
00445 static void SHA256_Update(SHA256_CTX *ctx,
00446                           const unsigned char *input,
00447                           unsigned int inputLen)
00448 {
00449   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
00450 }
00451 
00452 static void SHA256_Final(unsigned char digest[32], SHA256_CTX *ctx)
00453 {
00454   win32_crypto_final(ctx, digest, 32);
00455 }
00456 
00457 #endif /* CRYPTO LIBS */
00458 
00459 const digest_params MD5_DIGEST_PARAMS[] = {
00460   {
00461     (Curl_digest_init_func) MD5_Init,
00462     (Curl_digest_update_func) MD5_Update,
00463     (Curl_digest_final_func) MD5_Final,
00464     sizeof(MD5_CTX),
00465     16
00466   }
00467 };
00468 
00469 const digest_params SHA1_DIGEST_PARAMS[] = {
00470   {
00471     (Curl_digest_init_func) SHA1_Init,
00472     (Curl_digest_update_func) SHA1_Update,
00473     (Curl_digest_final_func) SHA1_Final,
00474     sizeof(SHA_CTX),
00475     20
00476   }
00477 };
00478 
00479 const digest_params SHA256_DIGEST_PARAMS[] = {
00480   {
00481     (Curl_digest_init_func) SHA256_Init,
00482     (Curl_digest_update_func) SHA256_Update,
00483     (Curl_digest_final_func) SHA256_Final,
00484     sizeof(SHA256_CTX),
00485     32
00486   }
00487 };
00488 
00489 static const metalink_digest_def SHA256_DIGEST_DEF[] = {
00490   {"sha-256", SHA256_DIGEST_PARAMS}
00491 };
00492 
00493 static const metalink_digest_def SHA1_DIGEST_DEF[] = {
00494   {"sha-1", SHA1_DIGEST_PARAMS}
00495 };
00496 
00497 static const metalink_digest_def MD5_DIGEST_DEF[] = {
00498   {"md5", MD5_DIGEST_PARAMS}
00499 };
00500 
00501 /*
00502  * The alias of supported hash functions in the order by preference
00503  * (basically stronger hash comes first). We included "sha-256" and
00504  * "sha256". The former is the name defined in the IANA registry named
00505  * "Hash Function Textual Names". The latter is widely (and
00506  * historically) used in Metalink version 3.
00507  */
00508 static const metalink_digest_alias digest_aliases[] = {
00509   {"sha-256", SHA256_DIGEST_DEF},
00510   {"sha256", SHA256_DIGEST_DEF},
00511   {"sha-1", SHA1_DIGEST_DEF},
00512   {"sha1", SHA1_DIGEST_DEF},
00513   {"md5", MD5_DIGEST_DEF},
00514   {NULL, NULL}
00515 };
00516 
00517 digest_context *Curl_digest_init(const digest_params *dparams)
00518 {
00519   digest_context *ctxt;
00520 
00521   /* Create digest context */
00522   ctxt = malloc(sizeof *ctxt);
00523 
00524   if(!ctxt)
00525     return ctxt;
00526 
00527   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
00528 
00529   if(!ctxt->digest_hashctx) {
00530     free(ctxt);
00531     return NULL;
00532   }
00533 
00534   ctxt->digest_hash = dparams;
00535 
00536   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
00537     free(ctxt);
00538     return NULL;
00539   }
00540 
00541   return ctxt;
00542 }
00543 
00544 int Curl_digest_update(digest_context *context,
00545                        const unsigned char *data,
00546                        unsigned int len)
00547 {
00548   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
00549 
00550   return 0;
00551 }
00552 
00553 int Curl_digest_final(digest_context *context, unsigned char *result)
00554 {
00555   (*context->digest_hash->digest_final)(result, context->digest_hashctx);
00556 
00557   free(context->digest_hashctx);
00558   free(context);
00559 
00560   return 0;
00561 }
00562 
00563 static unsigned char hex_to_uint(const char *s)
00564 {
00565   char buf[3];
00566   unsigned long val;
00567   buf[0] = s[0];
00568   buf[1] = s[1];
00569   buf[2] = 0;
00570   val = strtoul(buf, NULL, 16);
00571   return (unsigned char)(val&0xff);
00572 }
00573 
00574 /*
00575  * Check checksum of file denoted by filename. The expected hash value
00576  * is given in hex_hash which is hex-encoded string.
00577  *
00578  * This function returns 1 if it succeeds or one of the following
00579  * integers:
00580  *
00581  * 0:
00582  *   Checksum didn't match.
00583  * -1:
00584  *   Could not open file; or could not read data from file.
00585  * -2:
00586  *   Hash algorithm not available.
00587  */
00588 static int check_hash(const char *filename,
00589                       const metalink_digest_def *digest_def,
00590                       const unsigned char *digest, FILE *error)
00591 {
00592   unsigned char *result;
00593   digest_context *dctx;
00594   int check_ok, flags, fd;
00595 
00596   flags = O_RDONLY;
00597 #ifdef O_BINARY
00598   /* O_BINARY is required in order to avoid binary EOF in text mode */
00599   flags |= O_BINARY;
00600 #endif
00601 
00602   fd = open(filename, flags);
00603   if(fd == -1) {
00604     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
00605             digest_def->hash_name, strerror(errno));
00606     return -1;
00607   }
00608 
00609   dctx = Curl_digest_init(digest_def->dparams);
00610   if(!dctx) {
00611     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
00612             digest_def->hash_name, "failed to initialize hash algorithm");
00613     close(fd);
00614     return -2;
00615   }
00616 
00617   result = malloc(digest_def->dparams->digest_resultlen);
00618   if(!result) {
00619     close(fd);
00620     return -1;
00621   }
00622   while(1) {
00623     unsigned char buf[4096];
00624     ssize_t len = read(fd, buf, sizeof(buf));
00625     if(len == 0) {
00626       break;
00627     }
00628     else if(len == -1) {
00629       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
00630               digest_def->hash_name, strerror(errno));
00631       Curl_digest_final(dctx, result);
00632       close(fd);
00633       return -1;
00634     }
00635     Curl_digest_update(dctx, buf, (unsigned int)len);
00636   }
00637   Curl_digest_final(dctx, result);
00638   check_ok = memcmp(result, digest,
00639                     digest_def->dparams->digest_resultlen) == 0;
00640   /* sha*sum style verdict output */
00641   if(check_ok)
00642     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
00643             digest_def->hash_name);
00644   else
00645     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
00646             filename, digest_def->hash_name);
00647 
00648   free(result);
00649   close(fd);
00650   return check_ok;
00651 }
00652 
00653 int metalink_check_hash(struct GlobalConfig *config,
00654                         metalinkfile *mlfile,
00655                         const char *filename)
00656 {
00657   int rv;
00658   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
00659   if(mlfile->checksum == NULL) {
00660     fprintf(config->errors,
00661             "Metalink: validating (%s) FAILED (digest missing)\n", filename);
00662     return -2;
00663   }
00664   rv = check_hash(filename, mlfile->checksum->digest_def,
00665                   mlfile->checksum->digest, config->errors);
00666   return rv;
00667 }
00668 
00669 static metalink_checksum *new_metalink_checksum_from_hex_digest
00670 (const metalink_digest_def *digest_def, const char *hex_digest)
00671 {
00672   metalink_checksum *chksum;
00673   unsigned char *digest;
00674   size_t i;
00675   size_t len = strlen(hex_digest);
00676   digest = malloc(len/2);
00677   if(!digest)
00678     return 0;
00679 
00680   for(i = 0; i < len; i += 2) {
00681     digest[i/2] = hex_to_uint(hex_digest+i);
00682   }
00683   chksum = malloc(sizeof(metalink_checksum));
00684   if(chksum) {
00685     chksum->digest_def = digest_def;
00686     chksum->digest = digest;
00687   }
00688   return chksum;
00689 }
00690 
00691 static metalink_resource *new_metalink_resource(const char *url)
00692 {
00693   metalink_resource *res;
00694   res = malloc(sizeof(metalink_resource));
00695   if(res) {
00696     res->next = NULL;
00697     res->url = strdup(url);
00698     if(!res->url) {
00699       free(res);
00700       return NULL;
00701     }
00702   }
00703   return res;
00704 }
00705 
00706 /* Returns nonzero if hex_digest is properly formatted; that is each
00707    letter is in [0-9A-Za-z] and the length of the string equals to the
00708    result length of digest * 2. */
00709 static int check_hex_digest(const char *hex_digest,
00710                             const metalink_digest_def *digest_def)
00711 {
00712   size_t i;
00713   for(i = 0; hex_digest[i]; ++i) {
00714     char c = hex_digest[i];
00715     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
00716          ('A' <= c && c <= 'Z'))) {
00717       return 0;
00718     }
00719   }
00720   return digest_def->dparams->digest_resultlen * 2 == i;
00721 }
00722 
00723 static metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
00724 {
00725   metalinkfile *f;
00726   f = (metalinkfile*)malloc(sizeof(metalinkfile));
00727   if(!f)
00728     return NULL;
00729 
00730   f->next = NULL;
00731   f->filename = strdup(fileinfo->name);
00732   if(!f->filename) {
00733     free(f);
00734     return NULL;
00735   }
00736   f->checksum = NULL;
00737   f->resource = NULL;
00738   if(fileinfo->checksums) {
00739     const metalink_digest_alias *digest_alias;
00740     for(digest_alias = digest_aliases; digest_alias->alias_name;
00741         ++digest_alias) {
00742       metalink_checksum_t **p;
00743       for(p = fileinfo->checksums; *p; ++p) {
00744         if(curl_strequal(digest_alias->alias_name, (*p)->type) &&
00745            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
00746           f->checksum =
00747             new_metalink_checksum_from_hex_digest(digest_alias->digest_def,
00748                                                   (*p)->hash);
00749           break;
00750         }
00751       }
00752       if(f->checksum) {
00753         break;
00754       }
00755     }
00756   }
00757   if(fileinfo->resources) {
00758     metalink_resource_t **p;
00759     metalink_resource root, *tail;
00760     root.next = NULL;
00761     tail = &root;
00762     for(p = fileinfo->resources; *p; ++p) {
00763       metalink_resource *res;
00764       /* Filter by type if it is non-NULL. In Metalink v3, type
00765          includes the type of the resource. In curl, we are only
00766          interested in HTTP, HTTPS and FTP. In addition to them,
00767          Metalink v3 file may contain bittorrent type URL, which
00768          points to the BitTorrent metainfo file. We ignore it here.
00769          In Metalink v4, type was deprecated and all
00770          fileinfo->resources point to the target file. BitTorrent
00771          metainfo file URL may be appeared in fileinfo->metaurls.
00772       */
00773       if((*p)->type == NULL ||
00774          curl_strequal((*p)->type, "http") ||
00775          curl_strequal((*p)->type, "https") ||
00776          curl_strequal((*p)->type, "ftp") ||
00777          curl_strequal((*p)->type, "ftps")) {
00778         res = new_metalink_resource((*p)->url);
00779         tail->next = res;
00780         tail = res;
00781       }
00782     }
00783     f->resource = root.next;
00784   }
00785   return f;
00786 }
00787 
00788 int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
00789                    const char *metalink_url)
00790 {
00791   metalink_error_t r;
00792   metalink_t* metalink;
00793   metalink_file_t **files;
00794   bool warnings = FALSE;
00795 
00796   /* metlaink_parse_final deletes outs->metalink_parser */
00797   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
00798   outs->metalink_parser = NULL;
00799   if(r != 0) {
00800     return -1;
00801   }
00802   if(metalink->files == NULL) {
00803     fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
00804             "(missing or invalid file name)\n",
00805             metalink_url);
00806     metalink_delete(metalink);
00807     return -1;
00808   }
00809   for(files = metalink->files; *files; ++files) {
00810     struct getout *url;
00811     /* Skip an entry which has no resource. */
00812     if(!(*files)->resources) {
00813       fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
00814               "(missing or invalid resource)\n",
00815               metalink_url, (*files)->name);
00816       continue;
00817     }
00818     if(config->url_get ||
00819        ((config->url_get = config->url_list) != NULL)) {
00820       /* there's a node here, if it already is filled-in continue to
00821          find an "empty" node */
00822       while(config->url_get && (config->url_get->flags & GETOUT_URL))
00823         config->url_get = config->url_get->next;
00824     }
00825 
00826     /* now there might or might not be an available node to fill in! */
00827 
00828     if(config->url_get)
00829       /* existing node */
00830       url = config->url_get;
00831     else
00832       /* there was no free node, create one! */
00833       url = new_getout(config);
00834 
00835     if(url) {
00836       metalinkfile *mlfile = new_metalinkfile(*files);
00837       if(!mlfile)
00838         break;
00839 
00840       if(!mlfile->checksum) {
00841         warnings = TRUE;
00842         fprintf(config->global->errors,
00843                 "Metalink: parsing (%s) WARNING (digest missing)\n",
00844                 metalink_url);
00845       }
00846       /* Set name as url */
00847       GetStr(&url->url, mlfile->filename);
00848 
00849       /* set flag metalink here */
00850       url->flags |= GETOUT_URL | GETOUT_METALINK;
00851 
00852       if(config->metalinkfile_list) {
00853         config->metalinkfile_last->next = mlfile;
00854         config->metalinkfile_last = mlfile;
00855       }
00856       else {
00857         config->metalinkfile_list = config->metalinkfile_last = mlfile;
00858       }
00859     }
00860   }
00861   metalink_delete(metalink);
00862   return (warnings) ? -2 : 0;
00863 }
00864 
00865 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
00866                          void *userdata)
00867 {
00868   struct OutStruct *outs = userdata;
00869   struct OperationConfig *config = outs->config;
00870   int rv;
00871 
00872   /*
00873    * Once that libcurl has called back tool_write_cb() the returned value
00874    * is checked against the amount that was intended to be written, if
00875    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
00876    * point returning a value different from sz*nmemb indicates failure.
00877    */
00878   const size_t failure = (sz * nmemb) ? 0 : 1;
00879 
00880   if(!config)
00881     return failure;
00882 
00883   rv = metalink_parse_update(outs->metalink_parser, buffer, sz *nmemb);
00884   if(rv == 0)
00885     return sz * nmemb;
00886   else {
00887     fprintf(config->global->errors, "Metalink: parsing FAILED\n");
00888     return failure;
00889   }
00890 }
00891 
00892 /*
00893  * Returns nonzero if content_type includes mediatype.
00894  */
00895 static int check_content_type(const char *content_type, const char *media_type)
00896 {
00897   const char *ptr = content_type;
00898   size_t media_type_len = strlen(media_type);
00899   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
00900   if(!*ptr) {
00901     return 0;
00902   }
00903   return curl_strnequal(ptr, media_type, media_type_len) &&
00904     (*(ptr+media_type_len) == '\0' || *(ptr+media_type_len) == ' ' ||
00905      *(ptr+media_type_len) == '\t' || *(ptr+media_type_len) == ';');
00906 }
00907 
00908 int check_metalink_content_type(const char *content_type)
00909 {
00910   return check_content_type(content_type, "application/metalink+xml");
00911 }
00912 
00913 int count_next_metalink_resource(metalinkfile *mlfile)
00914 {
00915   int count = 0;
00916   metalink_resource *res;
00917   for(res = mlfile->resource; res; res = res->next, ++count);
00918   return count;
00919 }
00920 
00921 static void delete_metalink_checksum(metalink_checksum *chksum)
00922 {
00923   if(chksum == NULL) {
00924     return;
00925   }
00926   Curl_safefree(chksum->digest);
00927   Curl_safefree(chksum);
00928 }
00929 
00930 static void delete_metalink_resource(metalink_resource *res)
00931 {
00932   if(res == NULL) {
00933     return;
00934   }
00935   Curl_safefree(res->url);
00936   Curl_safefree(res);
00937 }
00938 
00939 static void delete_metalinkfile(metalinkfile *mlfile)
00940 {
00941   metalink_resource *res;
00942   if(mlfile == NULL) {
00943     return;
00944   }
00945   Curl_safefree(mlfile->filename);
00946   delete_metalink_checksum(mlfile->checksum);
00947   for(res = mlfile->resource; res;) {
00948     metalink_resource *next;
00949     next = res->next;
00950     delete_metalink_resource(res);
00951     res = next;
00952   }
00953   Curl_safefree(mlfile);
00954 }
00955 
00956 void clean_metalink(struct OperationConfig *config)
00957 {
00958   while(config->metalinkfile_list) {
00959     metalinkfile *mlfile = config->metalinkfile_list;
00960     config->metalinkfile_list = config->metalinkfile_list->next;
00961     delete_metalinkfile(mlfile);
00962   }
00963   config->metalinkfile_last = 0;
00964 }
00965 
00966 void metalink_cleanup(void)
00967 {
00968 #ifdef USE_NSS
00969   if(nss_context) {
00970     NSS_ShutdownContext(nss_context);
00971     nss_context = NULL;
00972   }
00973 #endif
00974 }
00975 
00976 #endif /* USE_METALINK */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:07