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