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