|
|
1.1 paf 1: /*
2: Parser
3: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
4: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
5:
1.6 ! paf 6: $Id: untaint.C,v 1.5 2001/03/18 20:31:27 paf Exp $
1.1 paf 7: */
8:
9: #include <string.h>
10:
11: #include "pa_pool.h"
12: #include "pa_string.h"
13: #include "pa_hash.h"
14: #include "pa_exception.h"
15:
16: #define escape(cases) \
17: { \
18: const char *ptr=row->item.ptr; \
1.3 paf 19: for (int size=row->item.size; size--; ptr++) \
1.1 paf 20: switch(*ptr) { \
21: cases \
22: } \
23: }
1.4 paf 24: #define escape_value(a, c) case a: *copy_here++=c; break
25: #define escape_default default: *copy_here++=*ptr; break
1.1 paf 26: #define escape_subst(a, b, bsize) \
1.4 paf 27: case a: \
1.1 paf 28: strncpy(copy_here, b, bsize); \
29: copy_here+=bsize; \
1.4 paf 30: break
1.5 paf 31: #define escape_encode(need_encode_func) \
32: default: \
33: if(need_encode_func(*ptr)) { \
34: static const char *hex="0123456789ABCDEF"; \
35: char chunk[3]={'%'}; \
36: chunk[1]=hex[((unsigned char)*ptr)/0x10]; \
37: chunk[2]=hex[((unsigned char)*ptr)%0x10]; \
38: strncpy(copy_here, chunk, 3); copy_here+=3; \
39: } else \
40: *copy_here++=*ptr; \
41: break
1.4 paf 42:
1.5 paf 43: inline bool need_uri_encode(unsigned char c){
1.4 paf 44: if ((c>='0') && (c<='9') || (c>='A') && (c<='Z') || (c>='a') && (c<='z'))
45: return false;
46:
1.5 paf 47: return !strchr("_-./", c);
48: }
49: inline bool need_header_encode(unsigned char c){
50: if(strchr(" ,:", c))
51: return false;
52:
53: return need_uri_encode(c);
1.4 paf 54: }
1.1 paf 55:
56: // String
57:
1.6 ! paf 58: /// \todo optimize whitespaces for all but 'html'
1.1 paf 59: char *String::cstr() const {
1.2 paf 60: char *result=(char *)malloc(size()*UNTAINT_TIMES_BIGGER+1);
1.1 paf 61:
62: char *copy_here=result;
63: const Chunk *chunk=&head;
64: do {
65: const Chunk::Row *row=chunk->rows;
66: for(int i=0; i<chunk->count; i++) {
67: if(row==append_here)
68: goto break2;
69:
70: // WARNING:
71: // string can grow only UNTAINT_TIMES_BIGGER
72: switch(row->item.lang) {
73: case NO:
74: // clean piece
75: case YES:
76: // tainted piece, but undefined untaint language
77: // for VString.get_double of tainted values
78: // for ^process{body} evaluation
79: case AS_IS:
80: // tainted, untaint language: as-is
81: memcpy(copy_here, row->item.ptr, row->item.size);
82: copy_here+=row->item.size;
83: break;
1.4 paf 84: case URI:
85: // tainted, untaint language: uri
86: escape(
87: escape_value(' ', '+');
1.5 paf 88: escape_encode(need_uri_encode);
89: );
90: break;
91: case HEADER:
92: // tainted, untaint language: header
93: escape(
94: escape_encode(need_header_encode);
1.4 paf 95: );
96: break;
1.1 paf 97: case TABLE:
98: escape(
1.4 paf 99: escape_value('\t', ' ');
100: escape_value('\n', ' ');
101: escape_default;
1.1 paf 102: );
103: break;
104: case SQL:
105: // tainted, untaint language: sql
106: // TODO: зависимость от sql сервера
107: memset(copy_here, '?', row->item.size);
108: copy_here+=row->item.size;
109: break;
110: case JS:
111: escape(
1.4 paf 112: escape_subst('"', "\\\"", 2);
113: escape_subst('\'', "\\'", 2);
114: escape_subst('\n', "\\n", 2);
115: escape_subst('\r', "\\r", 2);
116: escape_subst('\\', "\\\\", 2);
117: escape_subst('я', "\\я", 2);
118: escape_default;
1.1 paf 119: );
120: break;
121: case HTML:
122: escape(
1.4 paf 123: escape_subst('&', "&", 5); // BEFORE consequent relpaces yelding '&'
124: escape_subst('>', ">", 4);
125: escape_subst('<', "<",4);
126: escape_subst('"', """,6);
127: escape_value('\t', ' ');
1.1 paf 128: //TODO: XSLT escape_subst('\'', "'", 6)
1.4 paf 129: escape_default;
1.1 paf 130: );
131: break;
132: case HTML_TYPO:
133: // tainted, untaint language: html-typo
134: escape(
1.4 paf 135: escape_subst('&', "&", 5); // BEFORE consequent relpaces yelding '&'
136: escape_subst('>', ">", 4);
137: escape_subst('<', "<",4);
138: escape_subst('"', """,6);
139: escape_value('\t', ' ');
1.1 paf 140: //TODO: $MAIN:html-type table replace, max length(b)==UNTAINT_TIMES_BIGGER*length(a)
1.4 paf 141: escape_default;
1.1 paf 142: );
143: break;
144: default:
145: THROW(0,0,
146: this,
147: "unknown untaint language #%d of %d piece",
148: static_cast<int>(row->item.lang),
149: i);
150: }
151: row++;
152: }
153: chunk=row->link;
154: } while(chunk);
155: break2:
156: *copy_here=0;
157: return result;
158: }