1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* escape/unescape functions. 18 * 19 * These functions perform various escaping operations, and are provided in 20 * pairs, a function to query the length of and escape existing buffers, as 21 * well as companion functions to perform the same process to memory 22 * allocated from a pool. 23 * 24 * The API is designed to have the smallest possible RAM footprint, and so 25 * will only allocate the exact amount of RAM needed for each conversion. 26 */ 27 28#include "apr_escape.h" 29#include "apr_escape_test_char.h" 30#include "apr_lib.h" 31#include "apr_strings.h" 32 33#if APR_CHARSET_EBCDIC 34static int convert_a2e[256] = { 35 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 36 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, 37 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, 38 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, 39 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 40 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, 41 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 42 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, 43 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, 44 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, 45 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, 46 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, 47 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, 48 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, 49 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, 50 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF }; 51 52static int convert_e2a[256] = { 53 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 54 0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, 55 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, 56 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, 57 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, 58 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, 59 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, 60 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, 61 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, 62 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, 63 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, 64 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, 65 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, 66 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, 67 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, 68 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F }; 69#define RAW_ASCII_CHAR(ch) convert_e2a[(unsigned char)ch] 70#else /* APR_CHARSET_EBCDIC */ 71#define RAW_ASCII_CHAR(ch) (ch) 72#endif /* !APR_CHARSET_EBCDIC */ 73 74/* we assume the folks using this ensure 0 <= c < 256... which means 75 * you need a cast to (unsigned char) first, you can't just plug a 76 * char in here and get it to work, because if char is signed then it 77 * will first be sign extended. 78 */ 79#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) 80 81APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str, 82 apr_ssize_t slen, apr_size_t *len) 83{ 84 unsigned char *d; 85 const unsigned char *s; 86 apr_size_t size = 1; 87 int found = 0; 88 89 d = (unsigned char *) escaped; 90 s = (const unsigned char *) str; 91 92 if (s) { 93 if (d) { 94 for (; *s && slen; ++s, slen--) { 95#if defined(OS2) || defined(WIN32) 96 /* 97 * Newlines to Win32/OS2 CreateProcess() are ill advised. 98 * Convert them to spaces since they are effectively white 99 * space to most applications 100 */ 101 if (*s == '\r' || *s == '\n') { 102 if (d) { 103 *d++ = ' '; 104 found = 1; 105 } 106 continue; 107 } 108#endif 109 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { 110 *d++ = '\\'; 111 size++; 112 found = 1; 113 } 114 *d++ = *s; 115 size++; 116 } 117 *d = '\0'; 118 } 119 else { 120 for (; *s && slen; ++s, slen--) { 121 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { 122 size++; 123 found = 1; 124 } 125 size++; 126 } 127 } 128 } 129 130 if (len) { 131 *len = size; 132 } 133 if (!found) { 134 return APR_NOTFOUND; 135 } 136 137 return APR_SUCCESS; 138} 139 140APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str) 141{ 142 apr_size_t len; 143 144 switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) { 145 case APR_SUCCESS: { 146 char *cmd = apr_palloc(p, len); 147 apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL); 148 return cmd; 149 } 150 case APR_NOTFOUND: { 151 break; 152 } 153 } 154 155 return str; 156} 157 158static char x2c(const char *what) 159{ 160 register char digit; 161 162#if !APR_CHARSET_EBCDIC 163 digit = 164 ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); 165 digit *= 16; 166 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); 167#else /*APR_CHARSET_EBCDIC*/ 168 char xstr[5]; 169 xstr[0]='0'; 170 xstr[1]='x'; 171 xstr[2]=what[0]; 172 xstr[3]=what[1]; 173 xstr[4]='\0'; 174 digit = convert_a2e[0xFF & strtol(xstr, NULL, 16)]; 175#endif /*APR_CHARSET_EBCDIC*/ 176 return (digit); 177} 178 179APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url, 180 apr_ssize_t slen, const char *forbid, const char *reserved, int plus, 181 apr_size_t *len) 182{ 183 apr_size_t size = 1; 184 int found = 0; 185 const char *s = (const char *) url; 186 char *d = (char *) escaped; 187 register int badesc, badpath; 188 189 if (!url) { 190 return APR_NOTFOUND; 191 } 192 193 badesc = 0; 194 badpath = 0; 195 if (s) { 196 if (d) { 197 for (; *s && slen; ++s, d++, slen--) { 198 if (plus && *s == '+') { 199 *d = ' '; 200 found = 1; 201 } 202 else if (*s != '%') { 203 *d = *s; 204 } 205 else { 206 if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) { 207 badesc = 1; 208 *d = '%'; 209 } 210 else { 211 char decoded; 212 decoded = x2c(s + 1); 213 if ((decoded == '\0') 214 || (forbid && strchr(forbid, decoded))) { 215 badpath = 1; 216 *d = decoded; 217 s += 2; 218 slen -= 2; 219 } 220 else if (reserved && strchr(reserved, decoded)) { 221 *d++ = *s++; 222 *d++ = *s++; 223 *d = *s; 224 size += 2; 225 } 226 else { 227 *d = decoded; 228 s += 2; 229 slen -= 2; 230 found = 1; 231 } 232 } 233 } 234 size++; 235 } 236 *d = '\0'; 237 } 238 else { 239 for (; *s && slen; ++s, slen--) { 240 if (plus && *s == '+') { 241 found = 1; 242 } 243 else if (*s != '%') { 244 /* character unchanged */ 245 } 246 else { 247 if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) { 248 badesc = 1; 249 } 250 else { 251 char decoded; 252 decoded = x2c(s + 1); 253 if ((decoded == '\0') 254 || (forbid && strchr(forbid, decoded))) { 255 badpath = 1; 256 s += 2; 257 slen -= 2; 258 } 259 else if (reserved && strchr(reserved, decoded)) { 260 s += 2; 261 slen -= 2; 262 size += 2; 263 } 264 else { 265 s += 2; 266 slen -= 2; 267 found = 1; 268 } 269 } 270 } 271 size++; 272 } 273 } 274 } 275 276 if (len) { 277 *len = size; 278 } 279 if (badesc) { 280 return APR_EINVAL; 281 } 282 else if (badpath) { 283 return APR_BADCH; 284 } 285 else if (!found) { 286 return APR_NOTFOUND; 287 } 288 289 return APR_SUCCESS; 290} 291 292APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url, 293 const char *forbid, const char *reserved, int plus) 294{ 295 apr_size_t len; 296 297 switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved, 298 plus, &len)) { 299 case APR_SUCCESS: { 300 char *buf = apr_palloc(p, len); 301 apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus, 302 NULL); 303 return buf; 304 } 305 case APR_EINVAL: 306 case APR_BADCH: { 307 return NULL; 308 } 309 case APR_NOTFOUND: { 310 break; 311 } 312 } 313 314 return url; 315} 316 317/* c2x takes an unsigned, and expects the caller has guaranteed that 318 * 0 <= what < 256... which usually means that you have to cast to 319 * unsigned char first, because (unsigned)(char)(x) first goes through 320 * signed extension to an int before the unsigned cast. 321 * 322 * The reason for this assumption is to assist gcc code generation -- 323 * the unsigned char -> unsigned extension is already done earlier in 324 * both uses of this code, so there's no need to waste time doing it 325 * again. 326 */ 327static const char c2x_table[] = "0123456789abcdef"; 328 329static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, 330 unsigned char *where) 331{ 332#if APR_CHARSET_EBCDIC 333 what = convert_e2a[(unsigned char)what]; 334#endif /*APR_CHARSET_EBCDIC*/ 335 *where++ = prefix; 336 *where++ = c2x_table[what >> 4]; 337 *where++ = c2x_table[what & 0xf]; 338 return where; 339} 340 341APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped, 342 const char *str, apr_ssize_t slen, apr_size_t *len) 343{ 344 apr_size_t size = 1; 345 int found = 0; 346 const unsigned char *s = (const unsigned char *) str; 347 unsigned char *d = (unsigned char *) escaped; 348 unsigned c; 349 350 if (s) { 351 if (d) { 352 while ((c = *s) && slen) { 353 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { 354 d = c2x(c, '%', d); 355 size += 2; 356 found = 1; 357 } 358 else { 359 *d++ = c; 360 } 361 ++s; 362 size++; 363 slen--; 364 } 365 *d = '\0'; 366 } 367 else { 368 while ((c = *s) && slen) { 369 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { 370 size += 2; 371 found = 1; 372 } 373 ++s; 374 size++; 375 slen--; 376 } 377 } 378 } 379 380 if (len) { 381 *len = size; 382 } 383 if (!found) { 384 return APR_NOTFOUND; 385 } 386 387 return APR_SUCCESS; 388} 389 390APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p, 391 const char *str) 392{ 393 apr_size_t len; 394 395 switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) { 396 case APR_SUCCESS: { 397 char *cmd = apr_palloc(p, len); 398 apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL); 399 return cmd; 400 } 401 case APR_NOTFOUND: { 402 break; 403 } 404 } 405 406 return str; 407} 408 409APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path, 410 apr_ssize_t slen, int partial, apr_size_t *len) 411{ 412 apr_size_t size = 1; 413 int found = 0; 414 const unsigned char *s = (const unsigned char *) path; 415 unsigned char *d = (unsigned char *) escaped; 416 unsigned c; 417 418 if (!path) { 419 return APR_NOTFOUND; 420 } 421 422 if (!partial) { 423 const char *colon = strchr(path, ':'); 424 const char *slash = strchr(path, '/'); 425 426 if (colon && (!slash || colon < slash)) { 427 if (d) { 428 *d++ = '.'; 429 *d++ = '/'; 430 } 431 size += 2; 432 found = 1; 433 } 434 } 435 if (d) { 436 while ((c = *s) && slen) { 437 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { 438 d = c2x(c, '%', d); 439 size += 2; 440 found = 1; 441 } 442 else { 443 *d++ = c; 444 } 445 ++s; 446 size++; 447 slen--; 448 } 449 *d = '\0'; 450 } 451 else { 452 while ((c = *s) && slen) { 453 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { 454 size += 2; 455 found = 1; 456 } 457 ++s; 458 size++; 459 slen--; 460 } 461 } 462 463 if (len) { 464 *len = size; 465 } 466 if (!found) { 467 return APR_NOTFOUND; 468 } 469 470 return APR_SUCCESS; 471} 472 473APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str, 474 int partial) 475{ 476 apr_size_t len; 477 478 switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) { 479 case APR_SUCCESS: { 480 char *path = apr_palloc(p, len); 481 apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL); 482 return path; 483 } 484 case APR_NOTFOUND: { 485 break; 486 } 487 } 488 489 return str; 490} 491 492APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str, 493 apr_ssize_t slen, apr_size_t *len) 494{ 495 apr_size_t size = 1; 496 int found = 0; 497 const unsigned char *s = (const unsigned char *) str; 498 unsigned char *d = (unsigned char *) escaped; 499 unsigned c; 500 501 if (s) { 502 if (d) { 503 while ((c = *s) && slen) { 504 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) { 505 d = c2x(c, '%', d); 506 size += 2; 507 found = 1; 508 } 509 else if (c == ' ') { 510 *d++ = '+'; 511 found = 1; 512 } 513 else { 514 *d++ = c; 515 } 516 ++s; 517 size++; 518 slen--; 519 } 520 *d = '\0'; 521 } 522 else { 523 while ((c = *s) && slen) { 524 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) { 525 size += 2; 526 found = 1; 527 } 528 else if (c == ' ') { 529 found = 1; 530 } 531 ++s; 532 size++; 533 slen--; 534 } 535 } 536 } 537 538 if (len) { 539 *len = size; 540 } 541 if (!found) { 542 return APR_NOTFOUND; 543 } 544 545 return APR_SUCCESS; 546} 547 548APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str) 549{ 550 apr_size_t len; 551 552 switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) { 553 case APR_SUCCESS: { 554 char *encoded = apr_palloc(p, len); 555 apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL); 556 return encoded; 557 } 558 case APR_NOTFOUND: { 559 break; 560 } 561 } 562 563 return str; 564} 565 566APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str, 567 apr_ssize_t slen, int toasc, apr_size_t *len) 568{ 569 apr_size_t size = 1; 570 int found = 0; 571 const unsigned char *s = (const unsigned char *) str; 572 unsigned char *d = (unsigned char *) escaped; 573 unsigned c; 574 575 if (s) { 576 if (d) { 577 while ((c = *s) && slen) { 578 if (TEST_CHAR(c, T_ESCAPE_XML)) { 579 switch (c) { 580 case '>': { 581 memcpy(d, ">", 4); 582 size += 4; 583 d += 4; 584 break; 585 } 586 case '<': { 587 memcpy(d, "<", 4); 588 size += 4; 589 d += 4; 590 break; 591 } 592 case '&': { 593 memcpy(d, "&", 5); 594 size += 5; 595 d += 5; 596 break; 597 } 598 case '\"': { 599 memcpy(d, """, 6); 600 size += 6; 601 d += 6; 602 break; 603 } 604 case '\'': { 605 memcpy(d, "'", 6); 606 size += 6; 607 d += 6; 608 break; 609 } 610 } 611 found = 1; 612 } 613 else if (toasc && !apr_isascii(c)) { 614 int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c); 615 size += offset; 616 d += offset; 617 found = 1; 618 } 619 else { 620 *d++ = c; 621 size++; 622 } 623 ++s; 624 slen--; 625 } 626 *d = '\0'; 627 } 628 else { 629 while ((c = *s) && slen) { 630 if (TEST_CHAR(c, T_ESCAPE_XML)) { 631 switch (c) { 632 case '>': { 633 size += 4; 634 break; 635 } 636 case '<': { 637 size += 4; 638 break; 639 } 640 case '&': { 641 size += 5; 642 break; 643 } 644 case '\"': { 645 size += 6; 646 break; 647 } 648 case '\'': { 649 size += 6; 650 break; 651 } 652 } 653 found = 1; 654 } 655 else if (toasc && !apr_isascii(c)) { 656 char buf[8]; 657 size += apr_snprintf(buf, 6, "&#%3.3d;", c); 658 found = 1; 659 } 660 else { 661 size++; 662 } 663 ++s; 664 slen--; 665 } 666 } 667 } 668 669 if (len) { 670 *len = size; 671 } 672 if (!found) { 673 return APR_NOTFOUND; 674 } 675 676 return APR_SUCCESS; 677} 678 679APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str, 680 int toasc) 681{ 682 apr_size_t len; 683 684 switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) { 685 case APR_SUCCESS: { 686 char *cmd = apr_palloc(p, len); 687 apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL); 688 return cmd; 689 } 690 case APR_NOTFOUND: { 691 break; 692 } 693 } 694 695 return str; 696} 697 698/* maximum length of any ISO-LATIN-1 HTML entity name. */ 699#define MAXENTLEN (6) 700 701APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str, 702 apr_ssize_t slen, apr_size_t *len) 703{ 704 int found = 0; 705 apr_size_t size = 1; 706 int val, i, j; 707 char *d = unescaped; 708 const char *s = str; 709 const char *ents; 710 static const char * const entlist[MAXENTLEN + 1] = 711 { 712 NULL, /* 0 */ 713 NULL, /* 1 */ 714 "lt\074gt\076", /* 2 */ 715 "amp\046ETH\320eth\360", /* 3 */ 716 "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml" 717 "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */ 718 "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc" 719 "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352" 720 "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */ 721 "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311" 722 "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde" 723 "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340" 724 "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave" 725 "\354iacute\355ntilde\361ograve\362oacute\363otilde\365" 726 "oslash\370ugrave\371uacute\372yacute\375" /* 6 */ 727 }; 728 729 if (s) { 730 if (d) { 731 for (; *s != '\0' && slen; s++, d++, size++, slen--) { 732 if (*s != '&') { 733 *d = *s; 734 continue; 735 } 736 /* find end of entity */ 737 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0; 738 i++) { 739 continue; 740 } 741 742 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */ 743 *d = *s; 744 continue; 745 } 746 747 /* is it numeric ? */ 748 if (s[1] == '#') { 749 for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { 750 val = val * 10 + s[j] - '0'; 751 } 752 s += i; 753 if (j < i || val <= 8 || (val >= 11 && val <= 31) 754 || (val >= 127 && val <= 160) || val >= 256) { 755 d--; /* no data to output */ 756 size--; 757 } 758 else { 759 *d = RAW_ASCII_CHAR(val); 760 found = 1; 761 } 762 } 763 else { 764 j = i - 1; 765 if (j > MAXENTLEN || entlist[j] == NULL) { 766 /* wrong length */ 767 *d = '&'; 768 continue; /* skip it */ 769 } 770 for (ents = entlist[j]; *ents != '\0'; ents += i) { 771 if (strncmp(s + 1, ents, j) == 0) { 772 break; 773 } 774 } 775 776 if (*ents == '\0') { 777 *d = '&'; /* unknown */ 778 } 779 else { 780 *d = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]); 781 s += i; 782 slen -= i; 783 found = 1; 784 } 785 } 786 } 787 *d = '\0'; 788 } 789 else { 790 for (; *s != '\0' && slen; s++, size++, slen--) { 791 if (*s != '&') { 792 continue; 793 } 794 /* find end of entity */ 795 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0; 796 i++) { 797 continue; 798 } 799 800 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */ 801 continue; 802 } 803 804 /* is it numeric ? */ 805 if (s[1] == '#') { 806 for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { 807 val = val * 10 + s[j] - '0'; 808 } 809 s += i; 810 if (j < i || val <= 8 || (val >= 11 && val <= 31) 811 || (val >= 127 && val <= 160) || val >= 256) { 812 /* no data to output */ 813 size--; 814 } 815 else { 816 found = 1; 817 } 818 } 819 else { 820 j = i - 1; 821 if (j > MAXENTLEN || entlist[j] == NULL) { 822 /* wrong length */ 823 continue; /* skip it */ 824 } 825 for (ents = entlist[j]; *ents != '\0'; ents += i) { 826 if (strncmp(s + 1, ents, j) == 0) { 827 break; 828 } 829 } 830 831 if (*ents == '\0') { 832 /* unknown */ 833 } 834 else { 835 s += i; 836 slen -= i; 837 found = 1; 838 } 839 } 840 } 841 } 842 } 843 844 if (len) { 845 *len = size; 846 } 847 if (!found) { 848 return APR_NOTFOUND; 849 } 850 851 return APR_SUCCESS; 852} 853 854APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str) 855{ 856 apr_size_t len; 857 858 switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) { 859 case APR_SUCCESS: { 860 char *cmd = apr_palloc(p, len); 861 apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL); 862 return cmd; 863 } 864 case APR_NOTFOUND: { 865 break; 866 } 867 } 868 869 return str; 870} 871 872APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str, 873 apr_ssize_t slen, int quote, apr_size_t *len) 874{ 875 apr_size_t size = 1; 876 int found = 0; 877 const unsigned char *s = (const unsigned char *) str; 878 unsigned char *d = (unsigned char *) escaped; 879 unsigned c; 880 881 if (s) { 882 if (d) { 883 while ((c = *s) && slen) { 884 if (TEST_CHAR(c, T_ESCAPE_ECHO)) { 885 *d++ = '\\'; 886 size++; 887 switch (c) { 888 case '\a': 889 *d++ = 'a'; 890 size++; 891 found = 1; 892 break; 893 case '\b': 894 *d++ = 'b'; 895 size++; 896 found = 1; 897 break; 898 case '\f': 899 *d++ = 'f'; 900 size++; 901 found = 1; 902 break; 903 case '\n': 904 *d++ = 'n'; 905 size++; 906 found = 1; 907 break; 908 case '\r': 909 *d++ = 'r'; 910 size++; 911 found = 1; 912 break; 913 case '\t': 914 *d++ = 't'; 915 size++; 916 found = 1; 917 break; 918 case '\v': 919 *d++ = 'v'; 920 size++; 921 found = 1; 922 break; 923 case '\\': 924 *d++ = '\\'; 925 size++; 926 found = 1; 927 break; 928 case '"': 929 if (quote) { 930 *d++ = c; 931 size++; 932 found = 1; 933 } 934 else { 935 d[-1] = c; 936 } 937 break; 938 default: 939 c2x(c, 'x', d); 940 d += 3; 941 size += 3; 942 found = 1; 943 break; 944 } 945 } 946 else { 947 *d++ = c; 948 size++; 949 } 950 ++s; 951 slen--; 952 } 953 *d = '\0'; 954 } 955 else { 956 while ((c = *s) && slen) { 957 if (TEST_CHAR(c, T_ESCAPE_ECHO)) { 958 size++; 959 switch (c) { 960 case '\a': 961 case '\b': 962 case '\f': 963 case '\n': 964 case '\r': 965 case '\t': 966 case '\v': 967 case '\\': 968 size++; 969 found = 1; 970 break; 971 case '"': 972 if (quote) { 973 size++; 974 found = 1; 975 } 976 break; 977 default: 978 size += 3; 979 found = 1; 980 break; 981 } 982 } 983 else { 984 size++; 985 } 986 ++s; 987 slen--; 988 } 989 } 990 } 991 992 if (len) { 993 *len = size; 994 } 995 if (!found) { 996 return APR_NOTFOUND; 997 } 998 999 return APR_SUCCESS; 1000} 1001 1002APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str, 1003 int quote) 1004{ 1005 apr_size_t len; 1006 1007 switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) { 1008 case APR_SUCCESS: { 1009 char *cmd = apr_palloc(p, len); 1010 apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL); 1011 return cmd; 1012 } 1013 case APR_NOTFOUND: { 1014 break; 1015 } 1016 } 1017 1018 return str; 1019} 1020 1021APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src, 1022 apr_size_t srclen, int colon, apr_size_t *len) 1023{ 1024 const unsigned char *in = src; 1025 apr_size_t size; 1026 1027 if (!src) { 1028 return APR_NOTFOUND; 1029 } 1030 1031 if (dest) { 1032 for (size = 0; size < srclen; size++) { 1033 if (colon && size) { 1034 *dest++ = ':'; 1035 } 1036 *dest++ = c2x_table[in[size] >> 4]; 1037 *dest++ = c2x_table[in[size] & 0xf]; 1038 } 1039 *dest = '\0'; 1040 } 1041 1042 if (len) { 1043 if (colon && srclen) { 1044 *len = srclen * 3; 1045 } 1046 else { 1047 *len = srclen * 2 + 1; 1048 } 1049 } 1050 1051 return APR_SUCCESS; 1052} 1053 1054APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src, 1055 apr_size_t srclen, int colon) 1056{ 1057 apr_size_t len; 1058 1059 switch (apr_escape_hex(NULL, src, srclen, colon, &len)) { 1060 case APR_SUCCESS: { 1061 char *cmd = apr_palloc(p, len); 1062 apr_escape_hex(cmd, src, srclen, colon, NULL); 1063 return cmd; 1064 } 1065 case APR_NOTFOUND: { 1066 break; 1067 } 1068 } 1069 1070 return src; 1071} 1072 1073APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str, 1074 apr_ssize_t slen, int colon, apr_size_t *len) 1075{ 1076 apr_size_t size = 0; 1077 int flip = 0; 1078 const unsigned char *s = (const unsigned char *) str; 1079 unsigned char *d = (unsigned char *) dest; 1080 unsigned c; 1081 unsigned char u = 0; 1082 1083 if (s) { 1084 if (d) { 1085 while ((c = *s) && slen) { 1086 1087 if (!flip) { 1088 u = 0; 1089 } 1090 1091 if (colon && c == ':' && !flip) { 1092 ++s; 1093 slen--; 1094 continue; 1095 } 1096 else if (apr_isdigit(c)) { 1097 u |= c - '0'; 1098 } 1099 else if (apr_isupper(c) && c <= 'F') { 1100 u |= c - ('A' - 10); 1101 } 1102 else if (apr_islower(c) && c <= 'f') { 1103 u |= c - ('a' - 10); 1104 } 1105 else { 1106 return APR_BADCH; 1107 } 1108 1109 if (flip) { 1110 *d++ = u; 1111 size++; 1112 } 1113 else { 1114 u <<= 4; 1115 *d = u; 1116 } 1117 flip = !flip; 1118 1119 ++s; 1120 slen--; 1121 } 1122 } 1123 else { 1124 while ((c = *s) && slen) { 1125 1126 if (colon && c == ':' && !flip) { 1127 ++s; 1128 slen--; 1129 continue; 1130 } 1131 else if (apr_isdigit(c)) { 1132 /* valid */ 1133 } 1134 else if (apr_isupper(c) && c <= 'F') { 1135 /* valid */ 1136 } 1137 else if (apr_islower(c) && c <= 'f') { 1138 /* valid */ 1139 } 1140 else { 1141 return APR_BADCH; 1142 } 1143 1144 if (flip) { 1145 size++; 1146 } 1147 flip = !flip; 1148 1149 ++s; 1150 slen--; 1151 } 1152 } 1153 } 1154 1155 if (len) { 1156 *len = size; 1157 } 1158 if (!s) { 1159 return APR_NOTFOUND; 1160 } 1161 1162 return APR_SUCCESS; 1163} 1164 1165APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str, 1166 int colon, apr_size_t *len) 1167{ 1168 apr_size_t size; 1169 1170 switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) { 1171 case APR_SUCCESS: { 1172 void *cmd = apr_palloc(p, size); 1173 apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len); 1174 return cmd; 1175 } 1176 case APR_BADCH: 1177 case APR_NOTFOUND: { 1178 break; 1179 } 1180 } 1181 1182 return NULL; 1183} 1184