1 /* <!-- copyright */
2 /*
3 * libmetalink
4 *
5 * Copyright (c) 2012 Tatsuhiro Tsujikawa
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 /* copyright --> */
26 #include "metalink_helper.h"
27
28 #include <string.h>
29 #include <stdlib.h>
30
ends_with(const char * a,const char * b)31 static int ends_with(const char* a, const char *b)
32 {
33 size_t alen = strlen(a);
34 size_t blen = strlen(b);
35 if(alen < blen) {
36 return 0;
37 }
38 a += alen-blen;
39 return strcmp(a, b) == 0;
40 }
41
metalink_check_safe_path(const char * path)42 int metalink_check_safe_path(const char* path)
43 {
44 /* See discussions of treating filename from the remote server in
45 http://tools.ietf.org/html/rfc6266#section-4.3,
46 http://tools.ietf.org/html/rfc2183#section-5 and
47 http://tools.ietf.org/html/rfc5854.html#section-4.1.2.1
48 */
49 size_t len, i;
50 ssize_t filename_idx = 0;
51 /* If path or filename (string following the final '/' in path)
52 start with one of the characters in bad_prefix, we consider it as
53 invalid. */
54 const char bad_prefix[] = " .~/";
55 /* If path ends with one of the characters in bad_suffix, we
56 consider it as invalid. */
57 const char bad_suffix[] = " /";
58 if(!path || !path[0]) {
59 return 0;
60 }
61 for(i = 0; path[i]; ++i) {
62 unsigned char c = path[i];
63 if(c <= 0x1f || c == 0x7f || c == '\\' || c == '<' || c == '>' ||
64 c == '|') {
65 return 0;
66 }
67 if(path[i] == '/') {
68 filename_idx = i + 1;
69 }
70 }
71 len = i;
72 if(filename_idx == len) {
73 return 0;
74 }
75 if(strchr(bad_prefix, path[0]) != NULL) {
76 return 0;
77 }
78 if(filename_idx != 0) {
79 if(strchr(bad_prefix, path[filename_idx]) != NULL) {
80 return 0;
81 }
82 }
83 if(strchr(bad_suffix, path[len-1]) != NULL) {
84 return 0;
85 }
86 /* Don't allow DOS drive letter (e.g., C:) */
87 if(len >= 2 &&
88 (('A' <= path[0] && path[0] <= 'Z') ||
89 ('a' <= path[0] && path[0] <= 'z')) && path[1] == ':') {
90 return 0;
91 }
92 /* "." and ".." and prefix "./" and "../" are considered in
93 bad_prefix */
94 if(strstr(path, "/./") != NULL ||
95 strstr(path, "/../") != NULL ||
96 ends_with(path, "/.") ||
97 ends_with(path, "/..")) {
98 return 0;
99 }
100 return 1;
101 }
102
metalink_get_version(int * major,int * minor,int * patch)103 void metalink_get_version(int* major, int* minor, int* patch)
104 {
105 *major = LIBMETALINK_VERSION_MAJOR;
106 *minor = LIBMETALINK_VERSION_MINOR;
107 *patch = LIBMETALINK_VERSION_PATCH;
108 }
109
metalink_strerror(int error_code)110 const char* metalink_strerror(int error_code)
111 {
112 switch(error_code) {
113 case 0:
114 return "success";
115 case METALINK_ERR_BAD_ALLOC:
116 return "out of memory";
117 case METALINK_ERR_CANNOT_OPEN_FILE:
118 return "could not open file";
119 case METALINK_ERR_MISSING_REQUIRED_ATTR:
120 return "required attribute not found";
121 case METALINK_ERR_NAMESPACE_ERROR:
122 return "unexpected namespace";
123 case METALINK_ERR_PARSER_ERROR:
124 return "xml parser failure";
125 /* METALINK_ERR_NO_*_TRANSACTION error code should not be returned
126 to the application code. If they are, it is a bug of
127 libmetalink. In the future release, they will be removed and
128 assert() will be used instead. */
129 case METALINK_ERR_NO_FILE_TRANSACTION:
130 return "no file transaction";
131 case METALINK_ERR_NO_RESOURCE_TRANSACTION:
132 return "no resource transaction";
133 case METALINK_ERR_NO_CHECKSUM_TRANSACTION:
134 return "no checksum transaction";
135 case METALINK_ERR_NO_CHUNK_CHECKSUM_TRANSACTION:
136 return "no chunk checksum transaction";
137 case METALINK_ERR_NO_PIECE_HASH_TRANSACTION:
138 return "no piece hash transaction";
139 default:
140 return "unknown error code";
141 }
142 }
143