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