]> code.citadel.org Git - citadel.git/blobdiff - libcitadel/lib/stringbuf.c
Fix possible endless loop conditions
[citadel.git] / libcitadel / lib / stringbuf.c
index d8ff554d708febafb8e13e6221f2384a8b8b5511..1408669b0bf90810e78a1ac819f95fa60526e7ba 100644 (file)
@@ -259,9 +259,12 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
                return -1;
                
        if (DestSize > 0)
-               while (NewSize <= DestSize)
+               while ((NewSize <= DestSize) && (NewSize != 0))
                        NewSize *= 2;
 
+       if (NewSize == 0)
+               return -1;
+
        NewBuf= (char*) malloc(NewSize);
        if (NewBuf == NULL)
                return -1;
@@ -286,14 +289,16 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
 
 /**
  * @ingroup StrBuf_DeConstructors
- * @brief shrink an _EMPTY_ buffer if its Buffer superseeds threshhold to NewSize. Buffercontent is thoroughly ignored and flushed.
+ * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed.
  * @param Buf Buffer to shrink (has to be empty)
  * @param ThreshHold if the buffer is bigger then this, its readjusted
  * @param NewSize if we Shrink it, how big are we going to be afterwards?
  */
 void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
 {
-       if ((Buf != NULL) && (Buf->BufUsed > ThreshHold)) {
+       if ((Buf != NULL) && 
+           (Buf->BufUsed == 0) &&
+           (Buf->BufSize < ThreshHold)) {
                free(Buf->buf);
                Buf->buf = (char*) malloc(NewSize);
                Buf->BufUsed = 0;
@@ -391,9 +396,14 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
        else
                CopySize = nChars;
 
-       while (Siz <= CopySize)
+       while ((Siz <= CopySize) && (Siz != 0))
                Siz *= 2;
 
+       if (Siz == 0)
+       {
+               return NULL;
+       }
+
        NewBuf->buf = (char*) malloc(Siz);
        NewBuf->BufSize = Siz;
        if (ptr != NULL) {
@@ -422,7 +432,7 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars)
  */
 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
 {
-       size_t Siz = Buf->BufSize;
+       size_t Siz;
        size_t CopySize;
 
        if (Buf == NULL)
@@ -431,14 +441,22 @@ int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
                FlushStrBuf(Buf);
                return -1;
        }
+
+       Siz = Buf->BufSize;
+
        if (nChars < 0)
                CopySize = strlen(ptr);
        else
                CopySize = nChars;
 
-       while (Siz <= CopySize)
+       while ((Siz <= CopySize) && (Siz != 0))
                Siz *= 2;
 
+       if (Siz == 0) {
+               FlushStrBuf(Buf);
+               return -1;
+       }
+
        if (Siz != Buf->BufSize)
                IncreaseBuf(Buf, 0, Siz);
        memcpy(Buf->buf, ptr, CopySize);
@@ -762,7 +780,8 @@ void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
                va_end(apl);
                newused = Offset + nWritten;
                if (newused >= Buf->BufSize) {
-                       IncreaseBuf(Buf, 1, newused);
+                       if (IncreaseBuf(Buf, 1, newused) == -1)
+                               return; /* TODO: error handling? */
                        newused = Buf->BufSize + 1;
                }
                else {
@@ -803,7 +822,8 @@ void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
                va_end(arg_ptr);
                newused = Buf->BufUsed + nWritten;
                if (newused >= Buf->BufSize) {
-                       IncreaseBuf(Buf, 1, newused);
+                       if (IncreaseBuf(Buf, 1, newused) == -1)
+                               return; /* TODO: error handling? */
                        newused = Buf->BufSize + 1;
                }
                else {
@@ -834,7 +854,8 @@ void StrBufPrintf(StrBuf *Buf, const char *format, ...)
                nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
                va_end(arg_ptr);
                if (nWritten >= Buf->BufSize) {
-                       IncreaseBuf(Buf, 0, 0);
+                       if (IncreaseBuf(Buf, 0, 0) == -1)
+                               return; /* TODO: error handling? */
                        nWritten = Buf->BufSize + 1;
                        continue;
                }
@@ -1217,7 +1238,7 @@ int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char se
        //cit_backtrace();
        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
 
-       while ((s<e) && !IsEmptyStr(s)) {
+       while ((s < e) && !IsEmptyStr(s)) {
                if (*s == separator) {
                        ++current_token;
                }
@@ -1502,7 +1523,7 @@ int StrBufSkip_NTokenS(const StrBuf *Source, const char **pStart, char separator
        //cit_backtrace();
        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
 
-       while ((s<EndBuffer) && !IsEmptyStr(s)) {
+       while ((s < EndBuffer) && !IsEmptyStr(s)) {
                if (*s == separator) {
                        ++current_token;
                }
@@ -2254,6 +2275,7 @@ int StrBufDecodeBase64(StrBuf *Buf)
        if (Buf == NULL) return -1;
 
        xferbuf = (char*) malloc(Buf->BufSize);
+       *xferbuf = '\0';
        siz = CtdlDecodeBase64(xferbuf,
                               Buf->buf,
                               Buf->BufUsed);
@@ -2431,6 +2453,184 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
        return (*target)->BufUsed;;
 }
 
+
+
+static void AddRecipient(StrBuf *Target, 
+                        StrBuf *UserName, 
+                        StrBuf *EmailAddress, 
+                        StrBuf *EncBuf)
+{
+       int QuoteMe = 0;
+
+       if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
+       if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
+
+       if (QuoteMe)  StrBufAppendBufPlain(Target, HKEY("\""), 0);
+       StrBufRFC2047encode(&EncBuf, UserName);
+       StrBufAppendBuf(Target, EncBuf, 0);
+       if (QuoteMe)  StrBufAppendBufPlain(Target, HKEY("\" "), 0);
+       else          StrBufAppendBufPlain(Target, HKEY(" "), 0);
+
+       if (StrLength(EmailAddress) > 0){
+               StrBufAppendBufPlain(Target, HKEY("<"), 0);
+               StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
+               StrBufAppendBufPlain(Target, HKEY(">"), 0);
+       }
+}
+
+
+/**
+ * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts
+ * \param Recp Source list of email recipients
+ * \param UserName Temporary buffer for internal use; Please provide valid buffer.
+ * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer.
+ * \param EncBuf Temporary buffer for internal use; Please provide valid buffer.
+ * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory.
+ */
+StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, 
+                                          StrBuf *UserName, 
+                                          StrBuf *EmailAddress,
+                                          StrBuf *EncBuf)
+{
+       StrBuf *Target;
+       int need_to_encode;
+
+       const char *pch, *pche;
+       const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
+
+       if ((Recp == NULL) || (StrLength(Recp) == 0))
+               return NULL;
+
+       need_to_encode = 0;
+       pch = ChrPtr(Recp);
+       pche = pch + StrLength(Recp);
+
+       if (!CheckEncode(pch, -1, pche))
+               return NewStrBufDup(Recp);
+
+       Target = NewStrBufPlain(NULL, StrLength(Recp));
+
+       while ((pch != NULL) && (pch < pche))
+       {
+               int ColonOk = 0;
+
+               while (isspace(*pch)) pch++;
+               UserStart = UserEnd = EmailStart = EmailEnd = NULL;
+               
+               if ((*pch == '"') || (*pch == '\'')) {
+                       UserStart = pch + 1;
+                       
+                       UserEnd = strchr(UserStart, *pch);
+                       if (UserEnd == NULL) 
+                               break; ///TODO: Userfeedback??
+                       EmailStart = UserEnd + 1;
+                       while (isspace(*EmailStart))
+                               EmailStart++;
+                       if (UserEnd == UserStart) {
+                               UserStart = UserEnd = NULL;
+                       }
+                       
+                       if (*EmailStart == '<') {
+                               EmailStart++;
+                               EmailEnd = strchr(EmailStart, '>');
+                               if (EmailEnd == NULL)
+                                       EmailEnd = strchr(EmailStart, ',');
+                               
+                       }
+                       else {
+                               EmailEnd = strchr(EmailStart, ',');
+                       }
+                       if (EmailEnd == NULL)
+                               EmailEnd = pche;
+                       pch = EmailEnd + 1;
+                       ColonOk = 1;
+               }
+               else {
+                       int gt = 0;
+                       UserStart = pch;
+                       EmailEnd = strchr(UserStart, ',');
+                       if (EmailEnd == NULL) {
+                               EmailEnd = strchr(pch, '>');
+                               pch = NULL;
+                               if (EmailEnd != NULL) {
+                                       gt = 1;
+                               }
+                               else {
+                                       EmailEnd = pche;
+                               }
+                       }
+                       else {
+
+                               pch = EmailEnd + 1;
+                               while ((EmailEnd > UserStart) && !gt &&
+                                      ((*EmailEnd == ',') ||
+                                       (*EmailEnd == '>') ||
+                                       (isspace(*EmailEnd))))
+                               {
+                                       if (*EmailEnd == '>')
+                                               gt = 1;
+                                       else 
+                                               EmailEnd--;
+                               }
+                               if (EmailEnd == UserStart)
+                                       break;
+                       }
+                       if (gt) {
+                               EmailStart = strchr(UserStart, '<');
+                               if ((EmailStart == NULL) || (EmailStart > EmailEnd))
+                                       break;
+                               UserEnd = EmailStart;
+
+                               while ((UserEnd > UserStart) && 
+                                      isspace (*(UserEnd - 1)))
+                                       UserEnd --;
+                               EmailStart ++;
+                               if (UserStart >= UserEnd)
+                                       UserStart = UserEnd = NULL;
+                               At = strchr(EmailStart, '@');
+                       }
+                       else { /* this is a local recipient... no domain, just a realname */
+                               EmailStart = UserStart;
+                               At = strchr(EmailStart, '@');
+                               if (At == NULL) {
+                                       UserEnd = EmailEnd;
+                                       EmailEnd = NULL;
+                               }
+                               else {
+                                       EmailStart = UserStart;
+                                       UserStart = NULL;
+                               }
+                       }
+               }
+
+               if ((UserStart != NULL) && (UserEnd != NULL))
+                       StrBufPlain(UserName, UserStart, UserEnd - UserStart);
+               else if ((UserStart != NULL) && (UserEnd == NULL))
+                       StrBufPlain(UserName, UserStart, UserEnd - UserStart);
+               else
+                       FlushStrBuf(UserName);
+
+               if ((EmailStart != NULL) && (EmailEnd != NULL))
+                       StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart);
+               else if ((EmailStart != NULL) && (EmailEnd == NULL))
+                       StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche);
+               else 
+                       FlushStrBuf(EmailAddress);
+
+               AddRecipient(Target, UserName, EmailAddress, EncBuf);
+
+               if (pch == NULL)
+                       break;
+               
+               if ((pch != NULL) && (*pch == ','))
+                       pch ++;
+               if (pch != NULL) while (isspace(*pch))
+                       pch ++;
+       }
+       return Target;
+}
+
+
 /**
  * @ingroup StrBuf
  * @brief replaces all occurances of 'search' by 'replace'
@@ -2666,6 +2866,8 @@ inline static void DecodeSegment(StrBuf *Target,
        
        *encoding = toupper(*encoding);
        if (*encoding == 'B') { /**< base64 */
+               if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
+                       IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
                ConvertBuf2->BufUsed = CtdlDecodeBase64(ConvertBuf2->buf, 
                                                        ConvertBuf->buf, 
                                                        ConvertBuf->BufUsed);
@@ -2681,6 +2883,9 @@ inline static void DecodeSegment(StrBuf *Target,
                        pos++;
                }
                
+               if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
+                       IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
+
                ConvertBuf2->BufUsed = CtdlDecodeQuotedPrintable(
                        ConvertBuf2->buf, 
                        ConvertBuf->buf,
@@ -3630,7 +3835,7 @@ int StrBufReadBLOBBuffered(StrBuf *Blob,
                }
                rlen = read(*fd, 
                            ptr,
-                           nBytes - nRead);
+                           IOBuf->BufSize - (ptr - IOBuf->buf));
                if (rlen == -1) {
                        close(*fd);
                        *fd = -1;