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