--- parser3/src/main/untaint.C 2003/09/23 10:37:05 1.118.2.2 +++ parser3/src/main/untaint.C 2004/01/22 08:28:20 1.122.2.2 @@ -5,7 +5,7 @@ Author: Alexandr Petrosian (http://paf.design.ru) */ -static const char* IDENT_UNTAINT_C="$Date: 2003/09/23 10:37:05 $"; +static const char* IDENT_UNTAINT_C="$Date: 2004/01/22 08:28:20 $"; #include "pa_string.h" @@ -72,8 +72,8 @@ extern "C" { // author forgot to do that CORD_ec_append(info->result, hex[((unsigned char)c)%0x10]); \ } else \ CORD_ec_append(info->result, otherwise); -#define to_char(c) CORD_ec_append(info->result, c) -#define to_string(s) CORD_ec_append_cord(info->result, s) +#define to_char(c) { CORD_ec_append(info->result, c); whitespace=false; } +#define to_string(s) { CORD_ec_append_cord(info->result, s); whitespace=false; } inline bool need_file_encode(unsigned char c){ // russian letters and space ENABLED @@ -170,34 +170,36 @@ inline bool need_quote_http_header(const #ifndef DOXYGEN struct Append_fragment_info { String::Language lang; - const StringBody dest_body; String::Languages* dest_languages; + size_t dest_body_plan_length; }; #endif int append_fragment_optimizing(char alang, size_t asize, Append_fragment_info* info) { - const String::Language lang=(String::Language)alang; + const String::Language lang=(String::Language)(unsigned char)alang; // main idea here: // tainted piece would get OPTIMIZED bit from 'lang' // clean piece would be marked OPTIMIZED manually // pieces with determined languages [not tainted|clean] would retain theirs langs - info->dest_languages->append(info->dest_body, - lang==String::Language::L_TAINTED? + info->dest_languages->append(info->dest_body_plan_length, + lang==String::L_TAINTED? info->lang - :lang==String::Language::L_CLEAN? - (String::Language)(String::Language::L_CLEAN|String::Language::L_OPTIMIZE_BIT) // ORing with OPTIMIZED flag + :lang==String::L_CLEAN? + (String::Language)(String::L_CLEAN|String::L_OPTIMIZE_BIT) // ORing with OPTIMIZED flag :lang, asize); + info->dest_body_plan_length+=asize; return 0; // 0=continue } int append_fragment_nonoptimizing(char alang, size_t asize, Append_fragment_info* info) { - const String::Language lang=(String::Language)alang; + const String::Language lang=(String::Language)(unsigned char)alang; // The core idea: tainted pieces got marked with context's lang - info->dest_languages->append(info->dest_body, - lang==String::Language::L_TAINTED? + info->dest_languages->append(info->dest_body_plan_length, + lang==String::L_TAINTED? info->lang :lang, asize); + info->dest_body_plan_length+=asize; return 0; // 0=continue } @@ -215,11 +217,11 @@ String& String::append_to(String& dest, // first: fragment infos if(lang==L_PASS_APPENDED) // without language-change? - dest.langs.append(dest.body, body, langs); + dest.langs.append(dest.body, body.length(), langs); else if(forced) //forcing passed lang? dest.langs.append(dest.body, lang, length()); else { - Append_fragment_info info={lang, dest.body, &dest.langs}; + Append_fragment_info info={lang, &dest.langs, dest.body.length()}; langs.for_each(body, lang&L_OPTIMIZE_BIT? append_fragment_optimizing :append_fragment_nonoptimizing, &info); @@ -228,6 +230,7 @@ String& String::append_to(String& dest, // next: letters dest.body<whitespace; size_t fragment_end=info->fragment_begin+fragment_length; //fprintf(stderr, "%d, %d\n", fragment.lang, fragment.length); - String::Language to_lang=info->lang==String::Language::L_UNSPECIFIED?fragment_lang:info->lang; - bool optimize=(to_lang & String::Language::L_OPTIMIZE_BIT)!=0; + String::Language to_lang=info->lang==String::L_UNSPECIFIED?fragment_lang:info->lang; + bool optimize=(to_lang & String::L_OPTIMIZE_BIT)!=0; if(!optimize) whitespace=false; - switch(to_lang & ~String::Language::L_OPTIMIZE_BIT) { - case String::Language::L_CLEAN: - case String::Language::L_TAINTED: - case String::Language::L_AS_IS: + switch(to_lang & ~String::L_OPTIMIZE_BIT) { + case String::L_CLEAN: + case String::L_TAINTED: + case String::L_AS_IS: // clean piece // tainted piece, but undefined untaint language @@ -346,7 +349,7 @@ int cstr_to_string_body_block(char alang // tainted, untaint language: as-is ec_append(info->result, optimize, whitespace, info->pos, fragment_length); break; - case String::Language::L_FILE_SPEC: + case String::L_FILE_SPEC: // tainted, untaint language: file [name] escape( // Macintosh has problems with small Russian letter 'r' @@ -357,7 +360,7 @@ int cstr_to_string_body_block(char alang encode(need_file_encode, '_', c); ); break; - case String::Language::L_URI: + case String::L_URI: // tainted, untaint language: uri { const char *fragment_str=info->body->mid(info->fragment_begin, fragment_length).cstr(); @@ -374,13 +377,13 @@ int cstr_to_string_body_block(char alang encode(need_uri_encode, '%', c); } break; - case String::Language::L_HTTP_HEADER: + case String::L_HTTP_HEADER: // tainted, untaint language: http-field-content-text escape( encode(need_uri_encode, '%', c); ); break; - case String::Language::L_MAIL_HEADER: + case String::L_MAIL_HEADER: // tainted, untaint language: mail-header // http://www.ietf.org/rfc/rfc2047.txt if(info->charsets) { @@ -426,7 +429,7 @@ int cstr_to_string_body_block(char alang } else ec_append(info->result, optimize, whitespace, info->pos, fragment_length); break; - case String::Language::L_TABLE: + case String::L_TABLE: // tainted, untaint language: table escape(switch(c) { case '\t': to_char(' '); break; @@ -435,7 +438,7 @@ int cstr_to_string_body_block(char alang }); break; #ifdef PA_SQL - case String::Language::L_SQL: + case String::L_SQL: // tainted, untaint language: sql if(info->connection) { const char *fragment_str=info->body->mid(info->fragment_begin, fragment_length).cstr(); @@ -449,7 +452,7 @@ int cstr_to_string_body_block(char alang "untaint in SQL language failed - no connection specified"); break; #endif - case String::Language::L_JS: + case String::L_JS: escape(switch(c) { case '"': to_string("\\\""); break; case '\'': to_string("\\'"); break; @@ -459,7 +462,7 @@ int cstr_to_string_body_block(char alang _default; }); break; - case String::Language::L_XML: + case String::L_XML: escape(switch(c) { case '&': to_string("&"); break; case '>': to_string(">"); break; @@ -469,7 +472,7 @@ int cstr_to_string_body_block(char alang _default; }); break; - case String::Language::L_HTML: + case String::L_HTML: escape(switch(c) { case '&': to_string("&"); break; case '>': to_string(">"); break; @@ -479,6 +482,7 @@ int cstr_to_string_body_block(char alang }); break; default: + assert(!"should never"); SAPI::die("unknown untaint language #%d", static_cast(to_lang)); // should never break; // never @@ -490,7 +494,7 @@ int cstr_to_string_body_block(char alang } -StringBody String::cstr_to_string_body(Language lang, +String::Body String::cstr_to_string_body(Language lang, SQL_Connection* connection, const Request_charsets *charsets) const { @@ -506,8 +510,9 @@ StringBody String::cstr_to_string_body(L body.set_pos(info.pos, 0); info.fragment_begin=0; info.whitespace=true; - - langs.for_each(body, cstr_to_string_body_block, &info); - return StringBody(CORD_ec_to_cord(info.result)); + if(!is_empty()) + langs.for_each(body, cstr_to_string_body_block, &info); + + return String::Body(CORD_ec_to_cord(info.result)); }