1 /*****************************************************************************
2 * Copyright 2005 Alt-N Technologies, Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * This code incorporates intellectual property owned by Yahoo! and licensed
11 * pursuant to the Yahoo! DomainKeys Patent License Agreement.
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *****************************************************************************/
20
21 #ifdef WIN32
22 #include <windows.h>
23 #pragma warning( disable: 4786 )
24 #else
25 #endif
26
27 #include <string.h>
28
29 #include "dkim.h"
30 #include "dkimbase.h"
31
32 #include <algorithm>
33
34
CDKIMBase()35 CDKIMBase::CDKIMBase()
36 {
37 m_From = NULL;
38 m_Sender = NULL;
39 m_hTag = NULL;
40 m_hTagSize = 0;
41 m_hTagPos = 0;
42 m_Line = NULL;
43 m_LineSize = 0;
44 m_LinePos = 0;
45 m_InHeaders = true;
46 }
47
~CDKIMBase()48 CDKIMBase::~CDKIMBase()
49 {
50 Free( m_Line );
51 Free( m_From );
52 Free( m_Sender );
53 Free( m_hTag );
54 }
55
Init(void)56 int CDKIMBase::Init(void)
57 {
58 return DKIM_SUCCESS;
59 }
60
61 ////////////////////////////////////////////////////////////////////////////////
62 //
63 // Alloc - allocate buffer
64 //
65 ////////////////////////////////////////////////////////////////////////////////
Alloc(char * & szBuffer,int nRequiredSize)66 int CDKIMBase::Alloc( char*& szBuffer, int nRequiredSize )
67 {
68 szBuffer = new char[nRequiredSize];
69
70 return (szBuffer == NULL) ? DKIM_OUT_OF_MEMORY : DKIM_SUCCESS;
71 }
72
73
74 ////////////////////////////////////////////////////////////////////////////////
75 //
76 // ReAlloc - extend buffer if necessary, leaving room for future expansion
77 //
78 ////////////////////////////////////////////////////////////////////////////////
ReAlloc(char * & szBuffer,int & nBufferSize,int nRequiredSize)79 int CDKIMBase::ReAlloc( char*& szBuffer, int& nBufferSize, int nRequiredSize )
80 {
81 if( nRequiredSize > nBufferSize )
82 {
83 char* newp;
84 int nNewSize = nRequiredSize + BUFFER_ALLOC_INCREMENT;
85
86 if( Alloc( newp, nNewSize ) == DKIM_SUCCESS )
87 {
88 if( szBuffer != NULL && nBufferSize > 0 )
89 {
90 memcpy( newp, szBuffer, nBufferSize );
91 delete[] szBuffer;
92 }
93 szBuffer = newp;
94 nBufferSize = nNewSize;
95 }
96 else
97 {
98 return DKIM_OUT_OF_MEMORY; // memory alloc error!
99 }
100 }
101
102 return DKIM_SUCCESS;
103 }
104
105 ////////////////////////////////////////////////////////////////////////////////
106 //
107 // Process - split buffers into lines without any CRs or LFs at the end.
108 //
109 ////////////////////////////////////////////////////////////////////////////////
Free(char * szBuffer)110 void CDKIMBase::Free( char* szBuffer )
111 {
112 if( szBuffer )
113 delete[] szBuffer;
114 }
115
116 ////////////////////////////////////////////////////////////////////////////////
117 //
118 // Process - split buffers into lines without any CRs or LFs at the end.
119 //
120 ////////////////////////////////////////////////////////////////////////////////
Process(char * szBuffer,int nBufLength,bool bEOF)121 int CDKIMBase::Process( char* szBuffer, int nBufLength, bool bEOF )
122 {
123 char* p = szBuffer;
124 char* e = szBuffer + nBufLength;
125
126 while( p < e )
127 {
128 if( *p != '\n' || m_LinePos == 0 || m_Line[m_LinePos-1] != '\r' )
129 {
130 // add char to line
131 if (m_LinePos >= m_LineSize)
132 {
133 int nRet = ReAlloc( m_Line, m_LineSize, m_LinePos+1 );
134 if (nRet != DKIM_SUCCESS)
135 return nRet;
136 }
137 m_Line[m_LinePos++] = *p;
138 }
139 else
140 {
141 // back up past the CR
142 m_LinePos--;
143
144 if (m_InHeaders)
145 {
146 // process header line
147 if (m_LinePos == 0)
148 {
149 m_InHeaders = false;
150 int Result = ProcessHeaders();
151 if (Result != DKIM_SUCCESS)
152 return Result;
153 }
154 else
155 {
156 // append the header to the headers list
157 if ( m_Line[0] != ' ' && m_Line[0] != '\t' )
158 {
159 HeaderList.push_back( string( m_Line, m_LinePos ) );
160 }
161 else
162 {
163 if ( !HeaderList.empty() )
164 {
165 HeaderList.back().append( "\r\n", 2 ).append( m_Line, m_LinePos );
166 }
167 else
168 {
169 // no header to append to...
170 }
171 }
172 }
173 }
174 else
175 {
176 // process body line
177 int Result = ProcessBody(m_Line, m_LinePos, bEOF);
178 if (Result != DKIM_SUCCESS)
179 {
180 m_LinePos = 0;
181 return Result;
182 }
183 }
184
185 m_LinePos = 0;
186 }
187
188 p++;
189 }
190
191 return DKIM_SUCCESS;
192 }
193
194
195 ////////////////////////////////////////////////////////////////////////////////
196 //
197 // ProcessFinal - process leftovers if stopping before the body or mid-line
198 //
199 ////////////////////////////////////////////////////////////////////////////////
ProcessFinal(void)200 int CDKIMBase::ProcessFinal(void)
201 {
202 if ( m_LinePos > 0 )
203 {
204 Process( "\r\n", 2, true );
205 }
206
207 if( m_InHeaders )
208 {
209 m_InHeaders = false;
210 ProcessHeaders();
211 ProcessBody("", 0, true);
212 }
213
214 return DKIM_SUCCESS;
215 }
216
217
218 ////////////////////////////////////////////////////////////////////////////////
219 //
220 // ProcessHeaders - process the headers (to be implemented by derived class)
221 //
222 ////////////////////////////////////////////////////////////////////////////////
ProcessHeaders()223 int CDKIMBase::ProcessHeaders()
224 {
225 return DKIM_SUCCESS;
226 }
227
228
229 ////////////////////////////////////////////////////////////////////////////////
230 //
231 // ProcessBody - process body line (to be implemented by derived class)
232 //
233 ////////////////////////////////////////////////////////////////////////////////
ProcessBody(char * szBuffer,int nBufLength,bool bEOF)234 int CDKIMBase::ProcessBody( char* szBuffer, int nBufLength, bool bEOF )
235 {
236 return DKIM_SUCCESS;
237 }
238
239
240 ////////////////////////////////////////////////////////////////////////////////
241 //
242 // RemoveSWSP - remove streaming white space from buffer/string inline
243 //
244 ////////////////////////////////////////////////////////////////////////////////
245
246 struct isswsp
247 {
operator ()isswsp248 bool operator()( char ch ) { return( ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' ); }
249 };
250
RemoveSWSP(char * szBuffer)251 void CDKIMBase::RemoveSWSP( char* szBuffer )
252 {
253 *remove_if( szBuffer, szBuffer+strlen(szBuffer), isswsp() ) = '\0';
254 }
255
RemoveSWSP(char * pBuffer,int & nBufLength)256 void CDKIMBase::RemoveSWSP( char* pBuffer, int& nBufLength )
257 {
258 nBufLength = remove_if( pBuffer, pBuffer+nBufLength, isswsp() ) - pBuffer;
259 }
260
RemoveSWSP(string & sBuffer)261 void CDKIMBase::RemoveSWSP( string& sBuffer )
262 {
263 sBuffer.erase( remove_if( sBuffer.begin(), sBuffer.end(), isswsp() ), sBuffer.end() );
264 }
265
266
267 //////////////////////////////////////////////////////////////////////////////////////////
268 //
269 // CompressSWSP - compress streaming white space into single spaces from buffer/string inline
270 //
271 //////////////////////////////////////////////////////////////////////////////////////////
272
CompressSWSP(char * pBuffer,int & nBufLength)273 void CDKIMBase::CompressSWSP( char* pBuffer, int& nBufLength )
274 {
275 char* pSrc = pBuffer;
276 char* pDst = pBuffer;
277 char* pEnd = pBuffer+nBufLength;
278
279 while (pSrc != pEnd)
280 {
281 if (isswsp()(*pSrc))
282 {
283
284 do {
285 ++pSrc;
286 } while (pSrc != pEnd && isswsp()(*pSrc));
287
288 if (pSrc == pEnd)
289 break;
290
291 *pDst++ = ' ';
292 }
293
294 *pDst++ = *pSrc++;
295 }
296
297 nBufLength = pDst - pBuffer;
298 }
299
CompressSWSP(string & sBuffer)300 void CDKIMBase::CompressSWSP( string& sBuffer )
301 {
302 string::iterator iSrc = sBuffer.begin();
303 string::iterator iDst = sBuffer.begin();
304 string::iterator iEnd = sBuffer.end();
305
306 while (iSrc != iEnd)
307 {
308 if (isswsp()(*iSrc))
309 {
310
311 do {
312 ++iSrc;
313 } while (iSrc != iEnd && isswsp()(*iSrc));
314
315 if (iSrc == iEnd)
316 break;
317
318 *iDst++ = ' ';
319 }
320
321 *iDst++ = *iSrc++;
322 }
323
324 sBuffer.erase(iDst, iEnd);
325 }
326
327 //////////////////////////////////////////////////////////////////////////////////////////
328 //
329 // RelaxHeader - relax a header field (lower case the name, remove swsp before and after :)
330 //
331 // modified 4/21/06 STB to remove white space before colon
332 //
333 //////////////////////////////////////////////////////////////////////////////////////////
334
RelaxHeader(const string & sHeader)335 string CDKIMBase::RelaxHeader( const string& sHeader )
336 {
337 string sTemp = sHeader;
338
339 CompressSWSP(sTemp);
340
341 unsigned cpos = sTemp.find(':');
342
343 if (cpos == -1)
344 {
345 // no colon?!
346 }
347 else
348 {
349 // lower case the header field name
350 for (unsigned i=0; i<cpos; i++)
351 {
352 if (sTemp[i] >= 'A' && sTemp[i] <= 'Z')
353 sTemp[i] += 'a'-'A';
354 }
355
356 // remove the space after the :
357 if (cpos+1 < sTemp.length() && sTemp[cpos+1] == ' ')
358 sTemp.erase(cpos+1, 1);
359
360 // remove the space before the :
361 if (cpos > 0 && sTemp[cpos-1] == ' ')
362 sTemp.erase(cpos-1, 1);
363 }
364
365 return sTemp;
366 }
367
368