1/* 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., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 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 31#include "udev.h" 32 33int 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 44void remove_trailing_chars(char *path, char c) 45{ 46 size_t len; 47 48 len = strlen(path); 49 while (len > 0 && path[len-1] == c) 50 path[--len] = '\0'; 51} 52 53size_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], "\\x2f", 4); 62 j += 4; 63 } else if (s[i] == '\\') { 64 memcpy(&t[j], "\\x5c", 4); 65 j += 4; 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 76size_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], "\\x2f", 4) == 0) { 82 s[j] = '/'; 83 i += 4; 84 }else if (memcmp(&s[i], "\\x5c", 4) == 0) { 85 s[j] = '\\'; 86 i += 4; 87 } else { 88 s[j] = s[i]; 89 i++; 90 } 91 } 92 s[j] = '\0'; 93 return j; 94} 95 96/* count of characters used to encode one unicode char */ 97static 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 */ 117static 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 */ 157static 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 */ 173static 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 */ 187int 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 219/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ 220int replace_chars(char *str, const char *white) 221{ 222 size_t i = 0; 223 int replaced = 0; 224 225 while (str[i] != '\0') { 226 int len; 227 228 /* accept whitelist */ 229 if (white != NULL && strchr(white, str[i]) != NULL) { 230 i++; 231 continue; 232 } 233 234 /* accept plain ascii char */ 235 if ((str[i] >= '0' && str[i] <= '9') || 236 (str[i] >= 'A' && str[i] <= 'Z') || 237 (str[i] >= 'a' && str[i] <= 'z')) { 238 i++; 239 continue; 240 } 241 242 /* accept hex encoding */ 243 if (str[i] == '\\' && str[i+1] == 'x') { 244 i += 2; 245 continue; 246 } 247 248 /* accept valid utf8 */ 249 len = utf8_encoded_valid_unichar(&str[i]); 250 if (len > 1) { 251 i += len; 252 continue; 253 } 254 255 /* if space is allowed, replace whitespace with ordinary space */ 256 if (isspace(str[i]) && strchr(white, ' ') != NULL) { 257 str[i] = ' '; 258 i++; 259 replaced++; 260 continue; 261 } 262 263 /* everything else is replaced with '_' */ 264 str[i] = '_'; 265 i++; 266 replaced++; 267 } 268 269 return replaced; 270} 271