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.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 
MD5_Init(MD5_CTX * ctx)121 static int MD5_Init(MD5_CTX *ctx)
122 {
123   md5_init(ctx);
124   return 1;
125 }
126 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)134 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
135 {
136   md5_digest(ctx, 16, digest);
137 }
138 
SHA1_Init(SHA_CTX * ctx)139 static int SHA1_Init(SHA_CTX *ctx)
140 {
141   sha1_init(ctx);
142   return 1;
143 }
144 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)152 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
153 {
154   sha1_digest(ctx, 20, digest);
155 }
156 
SHA256_Init(SHA256_CTX * ctx)157 static int SHA256_Init(SHA256_CTX *ctx)
158 {
159   sha256_init(ctx);
160   return 1;
161 }
162 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)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 
MD5_Init(MD5_CTX * ctx)177 static int MD5_Init(MD5_CTX *ctx)
178 {
179   gcry_md_open(ctx, GCRY_MD_MD5, 0);
180   return 1;
181 }
182 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)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 
SHA1_Init(SHA_CTX * ctx)196 static int SHA1_Init(SHA_CTX *ctx)
197 {
198   gcry_md_open(ctx, GCRY_MD_SHA1, 0);
199   return 1;
200 }
201 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)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 
SHA256_Init(SHA256_CTX * ctx)215 static int SHA256_Init(SHA256_CTX *ctx)
216 {
217   gcry_md_open(ctx, GCRY_MD_SHA256, 0);
218   return 1;
219 }
220 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)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 
nss_hash_init(void ** pctx,SECOidTag hash_alg)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 
nss_hash_final(void ** pctx,unsigned char * out,unsigned int len)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 
MD5_Init(MD5_CTX * pctx)270 static int MD5_Init(MD5_CTX *pctx)
271 {
272   return nss_hash_init(pctx, SEC_OID_MD5);
273 }
274 
MD5_Update(MD5_CTX * pctx,const unsigned char * input,unsigned int input_len)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 
MD5_Final(unsigned char digest[16],MD5_CTX * pctx)282 static void MD5_Final(unsigned char digest[16], MD5_CTX *pctx)
283 {
284   nss_hash_final(pctx, digest, 16);
285 }
286 
SHA1_Init(SHA_CTX * pctx)287 static int SHA1_Init(SHA_CTX *pctx)
288 {
289   return nss_hash_init(pctx, SEC_OID_SHA1);
290 }
291 
SHA1_Update(SHA_CTX * pctx,const unsigned char * input,unsigned int input_len)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 
SHA1_Final(unsigned char digest[20],SHA_CTX * pctx)299 static void SHA1_Final(unsigned char digest[20], SHA_CTX *pctx)
300 {
301   nss_hash_final(pctx, digest, 20);
302 }
303 
SHA256_Init(SHA256_CTX * pctx)304 static int SHA256_Init(SHA256_CTX *pctx)
305 {
306   return nss_hash_init(pctx, SEC_OID_SHA256);
307 }
308 
SHA256_Update(SHA256_CTX * pctx,const unsigned char * input,unsigned int input_len)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 
SHA256_Final(unsigned char digest[32],SHA256_CTX * pctx)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 
win32_crypto_final(struct win32_crypto_hash * ctx,unsigned char * digest,unsigned int digestLen)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 
MD5_Init(MD5_CTX * ctx)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 
MD5_Update(MD5_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
MD5_Final(unsigned char digest[16],MD5_CTX * ctx)353 static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
354 {
355   win32_crypto_final(ctx, digest, 16);
356 }
357 
SHA1_Init(SHA_CTX * ctx)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 
SHA1_Update(SHA_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
SHA1_Final(unsigned char digest[20],SHA_CTX * ctx)374 static void SHA1_Final(unsigned char digest[20], SHA_CTX *ctx)
375 {
376   win32_crypto_final(ctx, digest, 20);
377 }
378 
SHA256_Init(SHA256_CTX * ctx)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 
SHA256_Update(SHA256_CTX * ctx,const unsigned char * input,unsigned int inputLen)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 
SHA256_Final(unsigned char digest[32],SHA256_CTX * ctx)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 struct 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 struct 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 struct 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 struct metalink_digest_def SHA256_DIGEST_DEF[] = {
433   {"sha-256", SHA256_DIGEST_PARAMS}
434 };
435 
436 static const struct metalink_digest_def SHA1_DIGEST_DEF[] = {
437   {"sha-1", SHA1_DIGEST_PARAMS}
438 };
439 
440 static const struct 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 struct 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 
digest_init(const struct digest_params * dparams)460 static struct digest_context *digest_init(const struct digest_params *dparams)
461 {
462   struct digest_context *ctxt = malloc(sizeof(*ctxt));
463   if(!ctxt)
464     return ctxt;
465 
466   ctxt->digest_hashctx = malloc(dparams->digest_ctxtsize);
467 
468   if(!ctxt->digest_hashctx) {
469     free(ctxt);
470     return NULL;
471   }
472 
473   ctxt->digest_hash = dparams;
474 
475   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
476     free(ctxt->digest_hashctx);
477     free(ctxt);
478     return NULL;
479   }
480 
481   return ctxt;
482 }
483 
digest_update(struct digest_context * context,const unsigned char * data,unsigned int len)484 static int digest_update(struct digest_context *context,
485                          const unsigned char *data,
486                          unsigned int len)
487 {
488   (*context->digest_hash->digest_update)(context->digest_hashctx, data, len);
489 
490   return 0;
491 }
492 
digest_final(struct digest_context * context,unsigned char * result)493 static int digest_final(struct digest_context *context, unsigned char *result)
494 {
495   if(result)
496     (*context->digest_hash->digest_final)(result, context->digest_hashctx);
497 
498   free(context->digest_hashctx);
499   free(context);
500 
501   return 0;
502 }
503 
hex_to_uint(const char * s)504 static unsigned char hex_to_uint(const char *s)
505 {
506   char buf[3];
507   unsigned long val;
508   buf[0] = s[0];
509   buf[1] = s[1];
510   buf[2] = 0;
511   val = strtoul(buf, NULL, 16);
512   return (unsigned char)(val&0xff);
513 }
514 
515 /*
516  * Check checksum of file denoted by filename. The expected hash value
517  * is given in hex_hash which is hex-encoded string.
518  *
519  * This function returns 1 if it succeeds or one of the following
520  * integers:
521  *
522  * 0:
523  *   Checksum didn't match.
524  * -1:
525  *   Could not open file; or could not read data from file.
526  * -2:
527  *   Hash algorithm not available.
528  */
check_hash(const char * filename,const struct metalink_digest_def * digest_def,const unsigned char * digest,FILE * error)529 static int check_hash(const char *filename,
530                       const struct metalink_digest_def *digest_def,
531                       const unsigned char *digest, FILE *error)
532 {
533   unsigned char *result;
534   struct digest_context *dctx;
535   int check_ok, flags, fd;
536 
537   flags = O_RDONLY;
538 #ifdef O_BINARY
539   /* O_BINARY is required in order to avoid binary EOF in text mode */
540   flags |= O_BINARY;
541 #endif
542 
543   fd = open(filename, flags);
544   if(fd == -1) {
545     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
546             digest_def->hash_name, strerror(errno));
547     return -1;
548   }
549 
550   dctx = digest_init(digest_def->dparams);
551   if(!dctx) {
552     fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
553             digest_def->hash_name, "failed to initialize hash algorithm");
554     close(fd);
555     return -2;
556   }
557 
558   result = malloc(digest_def->dparams->digest_resultlen);
559   if(!result) {
560     close(fd);
561     digest_final(dctx, NULL);
562     return -1;
563   }
564   while(1) {
565     unsigned char buf[4096];
566     ssize_t len = read(fd, buf, sizeof(buf));
567     if(len == 0) {
568       break;
569     }
570     else if(len == -1) {
571       fprintf(error, "Metalink: validating (%s) [%s] FAILED (%s)\n", filename,
572               digest_def->hash_name, strerror(errno));
573       digest_final(dctx, result);
574       close(fd);
575       return -1;
576     }
577     digest_update(dctx, buf, (unsigned int)len);
578   }
579   digest_final(dctx, result);
580   check_ok = memcmp(result, digest,
581                     digest_def->dparams->digest_resultlen) == 0;
582   /* sha*sum style verdict output */
583   if(check_ok)
584     fprintf(error, "Metalink: validating (%s) [%s] OK\n", filename,
585             digest_def->hash_name);
586   else
587     fprintf(error, "Metalink: validating (%s) [%s] FAILED (digest mismatch)\n",
588             filename, digest_def->hash_name);
589 
590   free(result);
591   close(fd);
592   return check_ok;
593 }
594 
metalink_check_hash(struct GlobalConfig * config,struct metalinkfile * mlfile,const char * filename)595 int metalink_check_hash(struct GlobalConfig *config,
596                         struct metalinkfile *mlfile,
597                         const char *filename)
598 {
599   int rv;
600   fprintf(config->errors, "Metalink: validating (%s)...\n", filename);
601   if(mlfile->checksum == NULL) {
602     fprintf(config->errors,
603             "Metalink: validating (%s) FAILED (digest missing)\n", filename);
604     return -2;
605   }
606   rv = check_hash(filename, mlfile->checksum->digest_def,
607                   mlfile->checksum->digest, config->errors);
608   return rv;
609 }
610 
611 static struct metalink_checksum *
checksum_from_hex_digest(const struct metalink_digest_def * digest_def,const char * hex_digest)612 checksum_from_hex_digest(const struct metalink_digest_def *digest_def,
613                          const char *hex_digest)
614 {
615   struct metalink_checksum *chksum;
616   unsigned char *digest;
617   size_t i;
618   size_t len = strlen(hex_digest);
619   digest = malloc(len/2);
620   if(!digest)
621     return 0;
622 
623   for(i = 0; i < len; i += 2) {
624     digest[i/2] = hex_to_uint(hex_digest + i);
625   }
626   chksum = malloc(sizeof(struct metalink_checksum));
627   if(chksum) {
628     chksum->digest_def = digest_def;
629     chksum->digest = digest;
630   }
631   else
632     free(digest);
633   return chksum;
634 }
635 
new_metalink_resource(const char * url)636 static struct metalink_resource *new_metalink_resource(const char *url)
637 {
638   struct metalink_resource *res = malloc(sizeof(struct metalink_resource));
639   if(res) {
640     res->next = NULL;
641     res->url = strdup(url);
642     if(!res->url) {
643       free(res);
644       return NULL;
645     }
646   }
647   return res;
648 }
649 
650 /* Returns nonzero if hex_digest is properly formatted; that is each
651    letter is in [0-9A-Za-z] and the length of the string equals to the
652    result length of digest * 2. */
check_hex_digest(const char * hex_digest,const struct metalink_digest_def * digest_def)653 static int check_hex_digest(const char *hex_digest,
654                             const struct metalink_digest_def *digest_def)
655 {
656   size_t i;
657   for(i = 0; hex_digest[i]; ++i) {
658     char c = hex_digest[i];
659     if(!(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
660          ('A' <= c && c <= 'Z'))) {
661       return 0;
662     }
663   }
664   return digest_def->dparams->digest_resultlen * 2 == i;
665 }
666 
new_metalinkfile(metalink_file_t * fileinfo)667 static struct metalinkfile *new_metalinkfile(metalink_file_t *fileinfo)
668 {
669   struct metalinkfile *f = malloc(sizeof(struct metalinkfile));
670   if(!f)
671     return NULL;
672 
673   f->next = NULL;
674   f->filename = strdup(fileinfo->name);
675   if(!f->filename) {
676     free(f);
677     return NULL;
678   }
679   f->checksum = NULL;
680   f->resource = NULL;
681   if(fileinfo->checksums) {
682     const struct metalink_digest_alias *digest_alias;
683     for(digest_alias = digest_aliases; digest_alias->alias_name;
684         ++digest_alias) {
685       metalink_checksum_t **p;
686       for(p = fileinfo->checksums; *p; ++p) {
687         if(curl_strequal(digest_alias->alias_name, (*p)->type) &&
688            check_hex_digest((*p)->hash, digest_alias->digest_def)) {
689           f->checksum =
690             checksum_from_hex_digest(digest_alias->digest_def,
691                                      (*p)->hash);
692           break;
693         }
694       }
695       if(f->checksum) {
696         break;
697       }
698     }
699   }
700   if(fileinfo->resources) {
701     metalink_resource_t **p;
702     struct metalink_resource root, *tail;
703     root.next = NULL;
704     tail = &root;
705     for(p = fileinfo->resources; *p; ++p) {
706       struct metalink_resource *res;
707       /* Filter by type if it is non-NULL. In Metalink v3, type
708          includes the type of the resource. In curl, we are only
709          interested in HTTP, HTTPS and FTP. In addition to them,
710          Metalink v3 file may contain bittorrent type URL, which
711          points to the BitTorrent metainfo file. We ignore it here.
712          In Metalink v4, type was deprecated and all
713          fileinfo->resources point to the target file. BitTorrent
714          metainfo file URL may be appeared in fileinfo->metaurls.
715       */
716       if((*p)->type == NULL ||
717          curl_strequal((*p)->type, "http") ||
718          curl_strequal((*p)->type, "https") ||
719          curl_strequal((*p)->type, "ftp") ||
720          curl_strequal((*p)->type, "ftps")) {
721         res = new_metalink_resource((*p)->url);
722         if(res) {
723           tail->next = res;
724           tail = res;
725         }
726         else {
727           tail = root.next;
728 
729           /* clean up the linked list */
730           while(tail) {
731             res = tail->next;
732             free(tail->url);
733             free(tail);
734             tail = res;
735           }
736           free(f->filename);
737           free(f);
738           return NULL;
739         }
740       }
741     }
742     f->resource = root.next;
743   }
744   return f;
745 }
746 
parse_metalink(struct OperationConfig * config,struct OutStruct * outs,const char * metalink_url)747 int parse_metalink(struct OperationConfig *config, struct OutStruct *outs,
748                    const char *metalink_url)
749 {
750   metalink_error_t r;
751   metalink_t* metalink;
752   metalink_file_t **files;
753   bool warnings = FALSE;
754 
755   /* metlaink_parse_final deletes outs->metalink_parser */
756   r = metalink_parse_final(outs->metalink_parser, NULL, 0, &metalink);
757   outs->metalink_parser = NULL;
758   if(r != 0) {
759     return -1;
760   }
761   if(metalink->files == NULL) {
762     fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
763             "(missing or invalid file name)\n",
764             metalink_url);
765     metalink_delete(metalink);
766     return -1;
767   }
768   for(files = metalink->files; *files; ++files) {
769     struct getout *url;
770     /* Skip an entry which has no resource. */
771     if(!(*files)->resources) {
772       fprintf(config->global->errors, "Metalink: parsing (%s) WARNING "
773               "(missing or invalid resource)\n",
774               metalink_url);
775       continue;
776     }
777     if(config->url_get ||
778        ((config->url_get = config->url_list) != NULL)) {
779       /* there's a node here, if it already is filled-in continue to
780          find an "empty" node */
781       while(config->url_get && (config->url_get->flags & GETOUT_URL))
782         config->url_get = config->url_get->next;
783     }
784 
785     /* now there might or might not be an available node to fill in! */
786 
787     if(config->url_get)
788       /* existing node */
789       url = config->url_get;
790     else
791       /* there was no free node, create one! */
792       url = new_getout(config);
793 
794     if(url) {
795       struct metalinkfile *mlfile = new_metalinkfile(*files);
796       if(!mlfile)
797         break;
798 
799       if(!mlfile->checksum) {
800         warnings = TRUE;
801         fprintf(config->global->errors,
802                 "Metalink: parsing (%s) WARNING (digest missing)\n",
803                 metalink_url);
804       }
805       /* Set name as url */
806       GetStr(&url->url, mlfile->filename);
807 
808       /* set flag metalink here */
809       url->flags |= GETOUT_URL | GETOUT_METALINK;
810 
811       if(config->metalinkfile_list) {
812         config->metalinkfile_last->next = mlfile;
813         config->metalinkfile_last = mlfile;
814       }
815       else {
816         config->metalinkfile_list = config->metalinkfile_last = mlfile;
817       }
818     }
819   }
820   metalink_delete(metalink);
821   return (warnings) ? -2 : 0;
822 }
823 
metalink_write_cb(void * buffer,size_t sz,size_t nmemb,void * userdata)824 size_t metalink_write_cb(void *buffer, size_t sz, size_t nmemb,
825                          void *userdata)
826 {
827   struct per_transfer *per = userdata;
828   struct OutStruct *outs = &per->outs;
829   struct OperationConfig *config = per->config;
830   int rv;
831 
832   /*
833    * Once that libcurl has called back tool_write_cb() the returned value
834    * is checked against the amount that was intended to be written, if
835    * it does not match then it fails with CURLE_WRITE_ERROR. So at this
836    * point returning a value different from sz*nmemb indicates failure.
837    */
838   const size_t failure = (sz && nmemb) ? 0 : 1;
839 
840   if(!config)
841     return failure;
842 
843   rv = metalink_parse_update(outs->metalink_parser, buffer, sz * nmemb);
844   if(rv == 0)
845     return sz * nmemb;
846   else {
847     fprintf(config->global->errors, "Metalink: parsing FAILED\n");
848     return failure;
849   }
850 }
851 
852 /*
853  * Returns nonzero if content_type includes mediatype.
854  */
check_content_type(const char * content_type,const char * media_type)855 static int check_content_type(const char *content_type, const char *media_type)
856 {
857   const char *ptr = content_type;
858   size_t media_type_len = strlen(media_type);
859   for(; *ptr && (*ptr == ' ' || *ptr == '\t'); ++ptr);
860   if(!*ptr) {
861     return 0;
862   }
863   return curl_strnequal(ptr, media_type, media_type_len) &&
864     (*(ptr + media_type_len) == '\0' || *(ptr + media_type_len) == ' ' ||
865      *(ptr + media_type_len) == '\t' || *(ptr + media_type_len) == ';');
866 }
867 
check_metalink_content_type(const char * content_type)868 int check_metalink_content_type(const char *content_type)
869 {
870   return check_content_type(content_type, "application/metalink+xml");
871 }
872 
count_next_metalink_resource(struct metalinkfile * mlfile)873 int count_next_metalink_resource(struct metalinkfile *mlfile)
874 {
875   int count = 0;
876   struct metalink_resource *res;
877   for(res = mlfile->resource; res; res = res->next, ++count);
878   return count;
879 }
880 
delete_metalink_checksum(struct metalink_checksum * chksum)881 static void delete_metalink_checksum(struct metalink_checksum *chksum)
882 {
883   if(!chksum)
884     return;
885   Curl_safefree(chksum->digest);
886   Curl_safefree(chksum);
887 }
888 
delete_metalink_resource(struct metalink_resource * res)889 static void delete_metalink_resource(struct metalink_resource *res)
890 {
891   if(res == NULL) {
892     return;
893   }
894   Curl_safefree(res->url);
895   Curl_safefree(res);
896 }
897 
delete_metalinkfile(struct metalinkfile * mlfile)898 void delete_metalinkfile(struct metalinkfile *mlfile)
899 {
900   struct metalink_resource *res;
901   if(mlfile == NULL) {
902     return;
903   }
904   Curl_safefree(mlfile->filename);
905   delete_metalink_checksum(mlfile->checksum);
906   for(res = mlfile->resource; res;) {
907     struct metalink_resource *next;
908     next = res->next;
909     delete_metalink_resource(res);
910     res = next;
911   }
912   Curl_safefree(mlfile);
913 }
914 
clean_metalink(struct OperationConfig * config)915 void clean_metalink(struct OperationConfig *config)
916 {
917   if(config) {
918     while(config->metalinkfile_list) {
919       struct metalinkfile *mlfile = config->metalinkfile_list;
920       config->metalinkfile_list = config->metalinkfile_list->next;
921       delete_metalinkfile(mlfile);
922     }
923     config->metalinkfile_last = 0;
924   }
925 }
926 
metalink_cleanup(void)927 void metalink_cleanup(void)
928 {
929 #ifdef HAVE_NSS_CONTEXT
930   if(nss_context) {
931     NSS_ShutdownContext(nss_context);
932     nss_context = NULL;
933   }
934 #endif
935 }
936 
937 #endif /* USE_METALINK */
938