]>
Commit | Line | Data |
---|---|---|
5b13ecb8 | 1 | /* |
5b13ecb8 KS |
2 | * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org> |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation version 2 of the License. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
11 | * General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along | |
14 | * with this program; if not, write to the Free Software Foundation, Inc., | |
27b77df4 | 15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
5b13ecb8 KS |
16 | * |
17 | */ | |
18 | ||
19 | ||
20 | #include <stdlib.h> | |
21 | #include <stdio.h> | |
22 | #include <stddef.h> | |
23 | #include <unistd.h> | |
24 | #include <fcntl.h> | |
25 | #include <errno.h> | |
26 | #include <ctype.h> | |
27 | #include <dirent.h> | |
28 | #include <syslog.h> | |
29 | #include <sys/utsname.h> | |
30 | ||
5b13ecb8 | 31 | #include "udev.h" |
5b13ecb8 | 32 | |
5b13ecb8 KS |
33 | int string_is_true(const char *str) |
34 | { | |
35 | if (strcasecmp(str, "true") == 0) | |
36 | return 1; | |
37 | if (strcasecmp(str, "yes") == 0) | |
38 | return 1; | |
39 | if (strcasecmp(str, "1") == 0) | |
40 | return 1; | |
41 | return 0; | |
42 | } | |
43 | ||
b2c6818d | 44 | void remove_trailing_chars(char *path, char c) |
5b13ecb8 KS |
45 | { |
46 | size_t len; | |
47 | ||
48 | len = strlen(path); | |
49 | while (len > 0 && path[len-1] == c) | |
50 | path[--len] = '\0'; | |
51 | } | |
52 | ||
9c6ad9fb KS |
53 | size_t path_encode(char *s, size_t len) |
54 | { | |
55 | char t[(len * 3)+1]; | |
56 | size_t i, j; | |
57 | ||
58 | t[0] = '\0'; | |
59 | for (i = 0, j = 0; s[i] != '\0'; i++) { | |
60 | if (s[i] == '/') { | |
61 | memcpy(&t[j], "%2f", 3); | |
62 | j += 3; | |
63 | } else if (s[i] == '%') { | |
64 | memcpy(&t[j], "%25", 3); | |
65 | j += 3; | |
66 | } else { | |
67 | t[j] = s[i]; | |
68 | j++; | |
69 | } | |
70 | } | |
71 | t[j] = '\0'; | |
72 | strncpy(s, t, len); | |
73 | return j; | |
74 | } | |
75 | ||
76 | size_t path_decode(char *s) | |
77 | { | |
78 | size_t i, j; | |
79 | ||
80 | for (i = 0, j = 0; s[i] != '\0'; j++) { | |
81 | if (memcmp(&s[i], "%2f", 3) == 0) { | |
82 | s[j] = '/'; | |
83 | i += 3; | |
84 | }else if (memcmp(&s[i], "%25", 3) == 0) { | |
85 | s[j] = '%'; | |
86 | i += 3; | |
87 | } else { | |
88 | s[j] = s[i]; | |
89 | i++; | |
90 | } | |
91 | } | |
92 | s[j] = '\0'; | |
93 | return j; | |
94 | } | |
95 | ||
5b13ecb8 KS |
96 | /* count of characters used to encode one unicode char */ |
97 | static int utf8_encoded_expected_len(const char *str) | |
98 | { | |
99 | unsigned char c = (unsigned char)str[0]; | |
100 | ||
101 | if (c < 0x80) | |
102 | return 1; | |
103 | if ((c & 0xe0) == 0xc0) | |
104 | return 2; | |
105 | if ((c & 0xf0) == 0xe0) | |
106 | return 3; | |
107 | if ((c & 0xf8) == 0xf0) | |
108 | return 4; | |
109 | if ((c & 0xfc) == 0xf8) | |
110 | return 5; | |
111 | if ((c & 0xfe) == 0xfc) | |
112 | return 6; | |
113 | return 0; | |
114 | } | |
115 | ||
116 | /* decode one unicode char */ | |
117 | static int utf8_encoded_to_unichar(const char *str) | |
118 | { | |
119 | int unichar; | |
120 | int len; | |
121 | int i; | |
122 | ||
123 | len = utf8_encoded_expected_len(str); | |
124 | switch (len) { | |
125 | case 1: | |
126 | return (int)str[0]; | |
127 | case 2: | |
128 | unichar = str[0] & 0x1f; | |
129 | break; | |
130 | case 3: | |
131 | unichar = (int)str[0] & 0x0f; | |
132 | break; | |
133 | case 4: | |
134 | unichar = (int)str[0] & 0x07; | |
135 | break; | |
136 | case 5: | |
137 | unichar = (int)str[0] & 0x03; | |
138 | break; | |
139 | case 6: | |
140 | unichar = (int)str[0] & 0x01; | |
141 | break; | |
142 | default: | |
143 | return -1; | |
144 | } | |
145 | ||
146 | for (i = 1; i < len; i++) { | |
147 | if (((int)str[i] & 0xc0) != 0x80) | |
148 | return -1; | |
149 | unichar <<= 6; | |
150 | unichar |= (int)str[i] & 0x3f; | |
151 | } | |
152 | ||
153 | return unichar; | |
154 | } | |
155 | ||
156 | /* expected size used to encode one unicode char */ | |
157 | static int utf8_unichar_to_encoded_len(int unichar) | |
158 | { | |
159 | if (unichar < 0x80) | |
160 | return 1; | |
161 | if (unichar < 0x800) | |
162 | return 2; | |
163 | if (unichar < 0x10000) | |
164 | return 3; | |
165 | if (unichar < 0x200000) | |
166 | return 4; | |
167 | if (unichar < 0x4000000) | |
168 | return 5; | |
169 | return 6; | |
170 | } | |
171 | ||
172 | /* check if unicode char has a valid numeric range */ | |
173 | static int utf8_unichar_valid_range(int unichar) | |
174 | { | |
175 | if (unichar > 0x10ffff) | |
176 | return 0; | |
177 | if ((unichar & 0xfffff800) == 0xd800) | |
178 | return 0; | |
179 | if ((unichar > 0xfdcf) && (unichar < 0xfdf0)) | |
180 | return 0; | |
181 | if ((unichar & 0xffff) == 0xffff) | |
182 | return 0; | |
183 | return 1; | |
184 | } | |
185 | ||
186 | /* validate one encoded unicode char and return its length */ | |
187 | int utf8_encoded_valid_unichar(const char *str) | |
188 | { | |
189 | int len; | |
190 | int unichar; | |
191 | int i; | |
192 | ||
193 | len = utf8_encoded_expected_len(str); | |
194 | if (len == 0) | |
195 | return -1; | |
196 | ||
197 | /* ascii is valid */ | |
198 | if (len == 1) | |
199 | return 1; | |
200 | ||
201 | /* check if expected encoded chars are available */ | |
202 | for (i = 0; i < len; i++) | |
203 | if ((str[i] & 0x80) != 0x80) | |
204 | return -1; | |
205 | ||
206 | unichar = utf8_encoded_to_unichar(str); | |
207 | ||
208 | /* check if encoded length matches encoded value */ | |
209 | if (utf8_unichar_to_encoded_len(unichar) != len) | |
210 | return -1; | |
211 | ||
212 | /* check if value has valid range */ | |
213 | if (!utf8_unichar_valid_range(unichar)) | |
214 | return -1; | |
215 | ||
216 | return len; | |
217 | } | |
218 | ||
764ce7f2 KS |
219 | /* replace everything but whitelisted plain ascii and valid utf8 */ |
220 | int replace_untrusted_chars(char *str) | |
5b13ecb8 | 221 | { |
764ce7f2 KS |
222 | size_t i = 0; |
223 | int replaced = 0; | |
224 | ||
225 | while (str[i] != '\0') { | |
226 | int len; | |
227 | ||
228 | /* valid printable ascii char */ | |
229 | if ((str[i] >= '0' && str[i] <= '9') || | |
230 | (str[i] >= 'A' && str[i] <= 'Z') || | |
231 | (str[i] >= 'a' && str[i] <= 'z') || | |
8a37a391 | 232 | strchr(" #$%+-./:=?@_,", str[i])) { |
764ce7f2 KS |
233 | i++; |
234 | continue; | |
235 | } | |
236 | /* valid utf8 is accepted */ | |
237 | len = utf8_encoded_valid_unichar(&str[i]); | |
238 | if (len > 1) { | |
239 | i += len; | |
240 | continue; | |
241 | } | |
5b13ecb8 | 242 | |
764ce7f2 KS |
243 | /* everything else is garbage */ |
244 | str[i] = '_'; | |
245 | i++; | |
246 | replaced++; | |
5b13ecb8 | 247 | } |
764ce7f2 KS |
248 | |
249 | return replaced; | |
5b13ecb8 | 250 | } |