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_encode_private.h" 31#include "apr_lib.h" 32#include "apr_strings.h" 33 34/* we assume the folks using this ensure 0 <= c < 256... which means 35 * you need a cast to (unsigned char) first, you can't just plug a 36 * char in here and get it to work, because if char is signed then it 37 * will first be sign extended. 38 */ 39#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) 40 41APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str, 42 apr_ssize_t slen, apr_size_t *len) 43{ 44 unsigned char *d; 45 const unsigned char *s; 46 apr_size_t size = 1; 47 int found = 0; 48 49 d = (unsigned char *) escaped; 50 s = (const unsigned char *) str; 51 52 if (s) { 53 if (d) { 54 for (; *s && slen; ++s, slen--) { 55#if defined(OS2) || defined(WIN32) 56 /* 57 * Newlines to Win32/OS2 CreateProcess() are ill advised. 58 * Convert them to spaces since they are effectively white 59 * space to most applications 60 */ 61 if (*s == '\r' || *s == '\n') { 62 if (d) { 63 *d++ = ' '; 64 found = 1; 65 } 66 continue; 67 } 68#endif 69 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { 70 *d++ = '\\'; 71 size++; 72 found = 1; 73 } 74 *d++ = *s; 75 size++; 76 } 77 *d = '\0'; 78 } 79 else { 80 for (; *s && slen; ++s, slen--) { 81 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) { 82 size++; 83 found = 1; 84 } 85 size++; 86 } 87 } 88 } 89 90 if (len) { 91 *len = size; 92 } 93 if (!found) { 94 return APR_NOTFOUND; 95 } 96 97 return APR_SUCCESS; 98} 99 100APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str) 101{ 102 apr_size_t len; 103 104 switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) { 105 case APR_SUCCESS: { 106 char *cmd = apr_palloc(p, len); 107 apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL); 108 return cmd; 109 } 110 case APR_NOTFOUND: { 111 break; 112 } 113 } 114 115 return str; 116} 117 118static char x2c(const char *what) 119{ 120 register char digit; 121 122#if !APR_CHARSET_EBCDIC 123 digit = 124 ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); 125 digit *= 16; 126 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); 127#else /*APR_CHARSET_EBCDIC*/ 128 char xstr[5]; 129 xstr[0]='0'; 130 xstr[1]='x'; 131 xstr[2]=what[0]; 132 xstr[3]=what[1]; 133 xstr[4]='\0'; 134 digit = ENCODE_TO_NATIVE[0xFF & strtol(xstr, NULL, 16)]; 135#endif /*APR_CHARSET_EBCDIC*/ 136 return (digit); 137} 138 139APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url, 140 apr_ssize_t slen, const char *forbid, const char *reserved, int plus, 141 apr_size_t *len) 142{ 143 apr_size_t size = 1; 144 int found = 0; 145 const char *s = (const char *) url; 146 char *d = (char *) escaped; 147 register int badesc, badpath; 148 149 if (!url) { 150 return APR_NOTFOUND; 151 } 152 153 badesc = 0; 154 badpath = 0; 155 if (s) { 156 if (d) { 157 for (; *s && slen; ++s, d++, slen--) { 158 if (plus && *s == '+') { 159 *d = ' '; 160 found = 1; 161 } 162 else if (*s != '%') { 163 *d = *s; 164 } 165 else { 166 if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) { 167 badesc = 1; 168 *d = '%'; 169 } 170 else { 171 char decoded; 172 decoded = x2c(s + 1); 173 if ((decoded == '\0') 174 || (forbid && strchr(forbid, decoded))) { 175 badpath = 1; 176 *d = decoded; 177 s += 2; 178 slen -= 2; 179 } 180 else if (reserved && strchr(reserved, decoded)) { 181 *d++ = *s++; 182 *d++ = *s++; 183 *d = *s; 184 size += 2; 185 } 186 else { 187 *d = decoded; 188 s += 2; 189 slen -= 2; 190 found = 1; 191 } 192 } 193 } 194 size++; 195 } 196 *d = '\0'; 197 } 198 else { 199 for (; *s && slen; ++s, slen--) { 200 if (plus && *s == '+') { 201 found = 1; 202 } 203 else if (*s != '%') { 204 /* character unchanged */ 205 } 206 else { 207 if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) { 208 badesc = 1; 209 } 210 else { 211 char decoded; 212 decoded = x2c(s + 1); 213 if ((decoded == '\0') 214 || (forbid && strchr(forbid, decoded))) { 215 badpath = 1; 216 s += 2; 217 slen -= 2; 218 } 219 else if (reserved && strchr(reserved, decoded)) { 220 s += 2; 221 slen -= 2; 222 size += 2; 223 } 224 else { 225 s += 2; 226 slen -= 2; 227 found = 1; 228 } 229 } 230 } 231 size++; 232 } 233 } 234 } 235 236 if (len) { 237 *len = size; 238 } 239 if (badesc) { 240 return APR_EINVAL; 241 } 242 else if (badpath) { 243 return APR_BADCH; 244 } 245 else if (!found) { 246 return APR_NOTFOUND; 247 } 248 249 return APR_SUCCESS; 250} 251 252APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url, 253 const char *forbid, const char *reserved, int plus) 254{ 255 apr_size_t len; 256 257 switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved, 258 plus, &len)) { 259 case APR_SUCCESS: { 260 char *buf = apr_palloc(p, len); 261 apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus, 262 NULL); 263 return buf; 264 } 265 case APR_EINVAL: 266 case APR_BADCH: { 267 return NULL; 268 } 269 case APR_NOTFOUND: { 270 break; 271 } 272 } 273 274 return url; 275} 276 277/* c2x takes an unsigned, and expects the caller has guaranteed that 278 * 0 <= what < 256... which usually means that you have to cast to 279 * unsigned char first, because (unsigned)(char)(x) first goes through 280 * signed extension to an int before the unsigned cast. 281 * 282 * The reason for this assumption is to assist gcc code generation -- 283 * the unsigned char -> unsigned extension is already done earlier in 284 * both uses of this code, so there's no need to waste time doing it 285 * again. 286 */ 287static const char c2x_table[] = "0123456789abcdef"; 288 289static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, 290 unsigned char *where) 291{ 292#if APR_CHARSET_EBCDIC 293 what = convert_e2a[(unsigned char)what]; 294#endif /*APR_CHARSET_EBCDIC*/ 295 *where++ = prefix; 296 *where++ = c2x_table[what >> 4]; 297 *where++ = c2x_table[what & 0xf]; 298 return where; 299} 300 301APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped, 302 const char *str, apr_ssize_t slen, apr_size_t *len) 303{ 304 apr_size_t size = 1; 305 int found = 0; 306 const unsigned char *s = (const unsigned char *) str; 307 unsigned char *d = (unsigned char *) escaped; 308 unsigned c; 309 310 if (s) { 311 if (d) { 312 while ((c = *s) && slen) { 313 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { 314 d = c2x(c, '%', d); 315 size += 2; 316 found = 1; 317 } 318 else { 319 *d++ = c; 320 } 321 ++s; 322 size++; 323 slen--; 324 } 325 *d = '\0'; 326 } 327 else { 328 while ((c = *s) && slen) { 329 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) { 330 size += 2; 331 found = 1; 332 } 333 ++s; 334 size++; 335 slen--; 336 } 337 } 338 } 339 340 if (len) { 341 *len = size; 342 } 343 if (!found) { 344 return APR_NOTFOUND; 345 } 346 347 return APR_SUCCESS; 348} 349 350APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p, 351 const char *str) 352{ 353 apr_size_t len; 354 355 switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) { 356 case APR_SUCCESS: { 357 char *cmd = apr_palloc(p, len); 358 apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL); 359 return cmd; 360 } 361 case APR_NOTFOUND: { 362 break; 363 } 364 } 365 366 return str; 367} 368 369APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path, 370 apr_ssize_t slen, int partial, apr_size_t *len) 371{ 372 apr_size_t size = 1; 373 int found = 0; 374 const unsigned char *s = (const unsigned char *) path; 375 unsigned char *d = (unsigned char *) escaped; 376 unsigned c; 377 378 if (!path) { 379 return APR_NOTFOUND; 380 } 381 382 if (!partial) { 383 const char *colon = strchr(path, ':'); 384 const char *slash = strchr(path, '/'); 385 386 if (colon && (!slash || colon < slash)) { 387 if (d) { 388 *d++ = '.'; 389 *d++ = '/'; 390 } 391 size += 2; 392 found = 1; 393 } 394 } 395 if (d) { 396 while ((c = *s) && slen) { 397 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { 398 d = c2x(c, '%', d); 399 size += 2; 400 found = 1; 401 } 402 else { 403 *d++ = c; 404 } 405 ++s; 406 size++; 407 slen--; 408 } 409 *d = '\0'; 410 } 411 else { 412 while ((c = *s) && slen) { 413 if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) { 414 size += 2; 415 found = 1; 416 } 417 ++s; 418 size++; 419 slen--; 420 } 421 } 422 423 if (len) { 424 *len = size; 425 } 426 if (!found) { 427 return APR_NOTFOUND; 428 } 429 430 return APR_SUCCESS; 431} 432 433APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str, 434 int partial) 435{ 436 apr_size_t len; 437 438 switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) { 439 case APR_SUCCESS: { 440 char *path = apr_palloc(p, len); 441 apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL); 442 return path; 443 } 444 case APR_NOTFOUND: { 445 break; 446 } 447 } 448 449 return str; 450} 451 452APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str, 453 apr_ssize_t slen, apr_size_t *len) 454{ 455 apr_size_t size = 1; 456 int found = 0; 457 const unsigned char *s = (const unsigned char *) str; 458 unsigned char *d = (unsigned char *) escaped; 459 unsigned c; 460 461 if (s) { 462 if (d) { 463 while ((c = *s) && slen) { 464 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) { 465 d = c2x(c, '%', d); 466 size += 2; 467 found = 1; 468 } 469 else if (c == ' ') { 470 *d++ = '+'; 471 found = 1; 472 } 473 else { 474 *d++ = c; 475 } 476 ++s; 477 size++; 478 slen--; 479 } 480 *d = '\0'; 481 } 482 else { 483 while ((c = *s) && slen) { 484 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) { 485 size += 2; 486 found = 1; 487 } 488 else if (c == ' ') { 489 found = 1; 490 } 491 ++s; 492 size++; 493 slen--; 494 } 495 } 496 } 497 498 if (len) { 499 *len = size; 500 } 501 if (!found) { 502 return APR_NOTFOUND; 503 } 504 505 return APR_SUCCESS; 506} 507 508APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str) 509{ 510 apr_size_t len; 511 512 switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) { 513 case APR_SUCCESS: { 514 char *encoded = apr_palloc(p, len); 515 apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL); 516 return encoded; 517 } 518 case APR_NOTFOUND: { 519 break; 520 } 521 } 522 523 return str; 524} 525 526APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str, 527 apr_ssize_t slen, int toasc, apr_size_t *len) 528{ 529 apr_size_t size = 1; 530 int found = 0; 531 const unsigned char *s = (const unsigned char *) str; 532 unsigned char *d = (unsigned char *) escaped; 533 unsigned c; 534 535 if (s) { 536 if (d) { 537 while ((c = *s) && slen) { 538 if (TEST_CHAR(c, T_ESCAPE_XML)) { 539 switch (c) { 540 case '>': { 541 memcpy(d, ">", 4); 542 size += 4; 543 d += 4; 544 break; 545 } 546 case '<': { 547 memcpy(d, "<", 4); 548 size += 4; 549 d += 4; 550 break; 551 } 552 case '&': { 553 memcpy(d, "&", 5); 554 size += 5; 555 d += 5; 556 break; 557 } 558 case '\"': { 559 memcpy(d, """, 6); 560 size += 6; 561 d += 6; 562 break; 563 } 564 case '\'': { 565 memcpy(d, "'", 6); 566 size += 6; 567 d += 6; 568 break; 569 } 570 } 571 found = 1; 572 } 573 else if (toasc && !apr_isascii(c)) { 574 int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c); 575 size += offset; 576 d += offset; 577 found = 1; 578 } 579 else { 580 *d++ = c; 581 size++; 582 } 583 ++s; 584 slen--; 585 } 586 *d = '\0'; 587 } 588 else { 589 while ((c = *s) && slen) { 590 if (TEST_CHAR(c, T_ESCAPE_XML)) { 591 switch (c) { 592 case '>': { 593 size += 4; 594 break; 595 } 596 case '<': { 597 size += 4; 598 break; 599 } 600 case '&': { 601 size += 5; 602 break; 603 } 604 case '\"': { 605 size += 6; 606 break; 607 } 608 case '\'': { 609 size += 6; 610 break; 611 } 612 } 613 found = 1; 614 } 615 else if (toasc && !apr_isascii(c)) { 616 char buf[8]; 617 size += apr_snprintf(buf, 6, "&#%3.3d;", c); 618 found = 1; 619 } 620 else { 621 size++; 622 } 623 ++s; 624 slen--; 625 } 626 } 627 } 628 629 if (len) { 630 *len = size; 631 } 632 if (!found) { 633 return APR_NOTFOUND; 634 } 635 636 return APR_SUCCESS; 637} 638 639APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str, 640 int toasc) 641{ 642 apr_size_t len; 643 644 switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) { 645 case APR_SUCCESS: { 646 char *cmd = apr_palloc(p, len); 647 apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL); 648 return cmd; 649 } 650 case APR_NOTFOUND: { 651 break; 652 } 653 } 654 655 return str; 656} 657 658/* maximum length of any ISO-LATIN-1 HTML entity name. */ 659#define MAXENTLEN (6) 660 661APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str, 662 apr_ssize_t slen, apr_size_t *len) 663{ 664 int found = 0; 665 apr_size_t size = 1; 666 int val, i, j; 667 char *d = unescaped; 668 const char *s = str; 669 const char *ents; 670 static const char * const entlist[MAXENTLEN + 1] = 671 { 672 NULL, /* 0 */ 673 NULL, /* 1 */ 674 "lt\074gt\076", /* 2 */ 675 "amp\046ETH\320eth\360", /* 3 */ 676 "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml" 677 "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */ 678 "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc" 679 "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352" 680 "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */ 681 "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311" 682 "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde" 683 "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340" 684 "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave" 685 "\354iacute\355ntilde\361ograve\362oacute\363otilde\365" 686 "oslash\370ugrave\371uacute\372yacute\375" /* 6 */ 687 }; 688 689 if (s) { 690 if (d) { 691 for (; *s != '\0' && slen; s++, d++, size++, slen--) { 692 if (*s != '&') { 693 *d = *s; 694 continue; 695 } 696 /* find end of entity */ 697 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0; 698 i++) { 699 continue; 700 } 701 702 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */ 703 *d = *s; 704 continue; 705 } 706 707 /* is it numeric ? */ 708 if (s[1] == '#') { 709 for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { 710 val = val * 10 + s[j] - '0'; 711 } 712 s += i; 713 if (j < i || val <= 8 || (val >= 11 && val <= 31) 714 || (val >= 127 && val <= 160) || val >= 256) { 715 d--; /* no data to output */ 716 size--; 717 } 718 else { 719 *d = ENCODE_TO_ASCII(val); 720 found = 1; 721 } 722 } 723 else { 724 j = i - 1; 725 if (j > MAXENTLEN || entlist[j] == NULL) { 726 /* wrong length */ 727 *d = '&'; 728 continue; /* skip it */ 729 } 730 for (ents = entlist[j]; *ents != '\0'; ents += i) { 731 if (strncmp(s + 1, ents, j) == 0) { 732 break; 733 } 734 } 735 736 if (*ents == '\0') { 737 *d = '&'; /* unknown */ 738 } 739 else { 740 *d = ENCODE_TO_ASCII(((const unsigned char *) ents)[j]); 741 s += i; 742 slen -= i; 743 found = 1; 744 } 745 } 746 } 747 *d = '\0'; 748 } 749 else { 750 for (; *s != '\0' && slen; s++, size++, slen--) { 751 if (*s != '&') { 752 continue; 753 } 754 /* find end of entity */ 755 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0; 756 i++) { 757 continue; 758 } 759 760 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */ 761 continue; 762 } 763 764 /* is it numeric ? */ 765 if (s[1] == '#') { 766 for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) { 767 val = val * 10 + s[j] - '0'; 768 } 769 s += i; 770 if (j < i || val <= 8 || (val >= 11 && val <= 31) 771 || (val >= 127 && val <= 160) || val >= 256) { 772 /* no data to output */ 773 size--; 774 } 775 else { 776 found = 1; 777 } 778 } 779 else { 780 j = i - 1; 781 if (j > MAXENTLEN || entlist[j] == NULL) { 782 /* wrong length */ 783 continue; /* skip it */ 784 } 785 for (ents = entlist[j]; *ents != '\0'; ents += i) { 786 if (strncmp(s + 1, ents, j) == 0) { 787 break; 788 } 789 } 790 791 if (*ents == '\0') { 792 /* unknown */ 793 } 794 else { 795 s += i; 796 slen -= i; 797 found = 1; 798 } 799 } 800 } 801 } 802 } 803 804 if (len) { 805 *len = size; 806 } 807 if (!found) { 808 return APR_NOTFOUND; 809 } 810 811 return APR_SUCCESS; 812} 813 814APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str) 815{ 816 apr_size_t len; 817 818 switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) { 819 case APR_SUCCESS: { 820 char *cmd = apr_palloc(p, len); 821 apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL); 822 return cmd; 823 } 824 case APR_NOTFOUND: { 825 break; 826 } 827 } 828 829 return str; 830} 831 832APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str, 833 apr_ssize_t slen, int quote, apr_size_t *len) 834{ 835 apr_size_t size = 1; 836 int found = 0; 837 const unsigned char *s = (const unsigned char *) str; 838 unsigned char *d = (unsigned char *) escaped; 839 unsigned c; 840 841 if (s) { 842 if (d) { 843 while ((c = *s) && slen) { 844 if (TEST_CHAR(c, T_ESCAPE_ECHO)) { 845 *d++ = '\\'; 846 size++; 847 switch (c) { 848 case '\a': 849 *d++ = 'a'; 850 size++; 851 found = 1; 852 break; 853 case '\b': 854 *d++ = 'b'; 855 size++; 856 found = 1; 857 break; 858 case '\f': 859 *d++ = 'f'; 860 size++; 861 found = 1; 862 break; 863 case '\n': 864 *d++ = 'n'; 865 size++; 866 found = 1; 867 break; 868 case '\r': 869 *d++ = 'r'; 870 size++; 871 found = 1; 872 break; 873 case '\t': 874 *d++ = 't'; 875 size++; 876 found = 1; 877 break; 878 case '\v': 879 *d++ = 'v'; 880 size++; 881 found = 1; 882 break; 883 case '\\': 884 *d++ = '\\'; 885 size++; 886 found = 1; 887 break; 888 case '"': 889 if (quote) { 890 *d++ = c; 891 size++; 892 found = 1; 893 } 894 else { 895 d[-1] = c; 896 } 897 break; 898 default: 899 c2x(c, 'x', d); 900 d += 3; 901 size += 3; 902 found = 1; 903 break; 904 } 905 } 906 else { 907 *d++ = c; 908 size++; 909 } 910 ++s; 911 slen--; 912 } 913 *d = '\0'; 914 } 915 else { 916 while ((c = *s) && slen) { 917 if (TEST_CHAR(c, T_ESCAPE_ECHO)) { 918 size++; 919 switch (c) { 920 case '\a': 921 case '\b': 922 case '\f': 923 case '\n': 924 case '\r': 925 case '\t': 926 case '\v': 927 case '\\': 928 size++; 929 found = 1; 930 break; 931 case '"': 932 if (quote) { 933 size++; 934 found = 1; 935 } 936 break; 937 default: 938 size += 3; 939 found = 1; 940 break; 941 } 942 } 943 else { 944 size++; 945 } 946 ++s; 947 slen--; 948 } 949 } 950 } 951 952 if (len) { 953 *len = size; 954 } 955 if (!found) { 956 return APR_NOTFOUND; 957 } 958 959 return APR_SUCCESS; 960} 961 962APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str, 963 int quote) 964{ 965 apr_size_t len; 966 967 switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) { 968 case APR_SUCCESS: { 969 char *cmd = apr_palloc(p, len); 970 apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL); 971 return cmd; 972 } 973 case APR_NOTFOUND: { 974 break; 975 } 976 } 977 978 return str; 979} 980 981APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src, 982 apr_size_t srclen, int colon, apr_size_t *len) 983{ 984 const unsigned char *in = src; 985 apr_size_t size; 986 987 if (!src) { 988 return APR_NOTFOUND; 989 } 990 991 if (dest) { 992 for (size = 0; size < srclen; size++) { 993 if (colon && size) { 994 *dest++ = ':'; 995 } 996 *dest++ = c2x_table[in[size] >> 4]; 997 *dest++ = c2x_table[in[size] & 0xf]; 998 } 999 *dest = '\0'; 1000 } 1001 1002 if (len) { 1003 if (colon && srclen) { 1004 *len = srclen * 3; 1005 } 1006 else { 1007 *len = srclen * 2 + 1; 1008 } 1009 } 1010 1011 return APR_SUCCESS; 1012} 1013 1014APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src, 1015 apr_size_t srclen, int colon) 1016{ 1017 apr_size_t len; 1018 1019 switch (apr_escape_hex(NULL, src, srclen, colon, &len)) { 1020 case APR_SUCCESS: { 1021 char *cmd = apr_palloc(p, len); 1022 apr_escape_hex(cmd, src, srclen, colon, NULL); 1023 return cmd; 1024 } 1025 case APR_NOTFOUND: { 1026 break; 1027 } 1028 } 1029 1030 return src; 1031} 1032 1033APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str, 1034 apr_ssize_t slen, int colon, apr_size_t *len) 1035{ 1036 apr_size_t size = 0; 1037 int flip = 0; 1038 const unsigned char *s = (const unsigned char *) str; 1039 unsigned char *d = (unsigned char *) dest; 1040 unsigned c; 1041 unsigned char u = 0; 1042 1043 if (s) { 1044 if (d) { 1045 while ((c = *s) && slen) { 1046 1047 if (!flip) { 1048 u = 0; 1049 } 1050 1051 if (colon && c == ':' && !flip) { 1052 ++s; 1053 slen--; 1054 continue; 1055 } 1056 else if (apr_isdigit(c)) { 1057 u |= c - '0'; 1058 } 1059 else if (apr_isupper(c) && c <= 'F') { 1060 u |= c - ('A' - 10); 1061 } 1062 else if (apr_islower(c) && c <= 'f') { 1063 u |= c - ('a' - 10); 1064 } 1065 else { 1066 return APR_BADCH; 1067 } 1068 1069 if (flip) { 1070 *d++ = u; 1071 size++; 1072 } 1073 else { 1074 u <<= 4; 1075 *d = u; 1076 } 1077 flip = !flip; 1078 1079 ++s; 1080 slen--; 1081 } 1082 } 1083 else { 1084 while ((c = *s) && slen) { 1085 1086 if (colon && c == ':' && !flip) { 1087 ++s; 1088 slen--; 1089 continue; 1090 } 1091 else if (apr_isdigit(c)) { 1092 /* valid */ 1093 } 1094 else if (apr_isupper(c) && c <= 'F') { 1095 /* valid */ 1096 } 1097 else if (apr_islower(c) && c <= 'f') { 1098 /* valid */ 1099 } 1100 else { 1101 return APR_BADCH; 1102 } 1103 1104 if (flip) { 1105 size++; 1106 } 1107 flip = !flip; 1108 1109 ++s; 1110 slen--; 1111 } 1112 } 1113 } 1114 1115 if (len) { 1116 *len = size; 1117 } 1118 if (!s) { 1119 return APR_NOTFOUND; 1120 } 1121 1122 return APR_SUCCESS; 1123} 1124 1125APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str, 1126 int colon, apr_size_t *len) 1127{ 1128 apr_size_t size; 1129 1130 switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) { 1131 case APR_SUCCESS: { 1132 void *cmd = apr_palloc(p, size); 1133 apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len); 1134 return cmd; 1135 } 1136 case APR_BADCH: 1137 case APR_NOTFOUND: { 1138 break; 1139 } 1140 } 1141 1142 return NULL; 1143} 1144 1145APR_DECLARE(apr_status_t) apr_escape_ldap(char *escaped, const void *str, 1146 apr_ssize_t slen, int flags, apr_size_t *len) 1147{ 1148 apr_size_t size = 1; 1149 int found = 0; 1150 const unsigned char *s = (const unsigned char *) str; 1151 unsigned char *d = (unsigned char *) escaped; 1152 unsigned c; 1153 1154 if (s) { 1155 if (d) { 1156 while (((c = *s) && slen) || (slen > 0)) { 1157 if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN)) 1158 || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) { 1159 d = c2x(c, '\\', d); 1160 size += 2; 1161 found = 1; 1162 } 1163 else { 1164 *d++ = c; 1165 } 1166 ++s; 1167 size++; 1168 slen--; 1169 } 1170 *d = '\0'; 1171 } 1172 else { 1173 while (((c = *s) && slen) || (slen > 0)) { 1174 if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN)) 1175 || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) { 1176 size += 2; 1177 found = 1; 1178 } 1179 ++s; 1180 size++; 1181 slen--; 1182 } 1183 } 1184 } 1185 1186 if (len) { 1187 *len = size; 1188 } 1189 if (!found) { 1190 return APR_NOTFOUND; 1191 } 1192 1193 return APR_SUCCESS; 1194} 1195 1196APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src, 1197 apr_ssize_t srclen, int flags) 1198{ 1199 apr_size_t len; 1200 1201 switch (apr_escape_ldap(NULL, src, srclen, flags, &len)) { 1202 case APR_SUCCESS: { 1203 char *encoded = apr_palloc(p, len); 1204 apr_escape_ldap(encoded, src, srclen, flags, NULL); 1205 return encoded; 1206 } 1207 case APR_NOTFOUND: { 1208 break; 1209 } 1210 } 1211 1212 return src; 1213} 1214 1215