1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 // Copyright (C) 2002 Martin Roesch <roesch@sourcefire.com>
5 //
6 // This program is free software; you can redistribute it and/or modify it
7 // under the terms of the GNU General Public License Version 2 as published
8 // by the Free Software Foundation.  You may not use, modify or distribute
9 // this program under any other version of the GNU General Public License.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 //--------------------------------------------------------------------------
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "util_cstring.h"
26 
27 #include <cassert>
28 #include <cstdarg>
29 #include <cstdio>
30 #include <cstring>
31 
32 namespace snort
33 {
34 /* Guaranteed to be '\0' terminated even if truncation occurs.
35  *
36  * returns  SNORT_SNPRINTF_SUCCESS if successful
37  * returns  SNORT_SNPRINTF_TRUNCATION on truncation
38  * returns  SNORT_SNPRINTF_ERROR on error
39  */
SnortSnprintf(char * buf,size_t buf_size,const char * format,...)40 int SnortSnprintf(char* buf, size_t buf_size, const char* format, ...)
41 {
42     va_list ap;
43     int ret;
44 
45     if (buf == nullptr || buf_size == 0 || format == nullptr)
46         return SNORT_SNPRINTF_ERROR;
47 
48     /* zero first byte in case an error occurs with
49      * vsnprintf, so buffer is null terminated with
50      * zero length */
51     buf[0] = '\0';
52     buf[buf_size - 1] = '\0';
53 
54     va_start(ap, format);
55 
56     ret = vsnprintf(buf, buf_size, format, ap);
57 
58     va_end(ap);
59 
60     if (ret < 0)
61         return SNORT_SNPRINTF_ERROR;
62 
63     if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size)
64     {
65         /* result was truncated */
66         buf[buf_size - 1] = '\0';
67         return SNORT_SNPRINTF_TRUNCATION;
68     }
69 
70     return SNORT_SNPRINTF_SUCCESS;
71 }
72 
73 /* Appends to a given string
74  * Guaranteed to be '\0' terminated even if truncation occurs.
75  *
76  * returns SNORT_SNPRINTF_SUCCESS if successful
77  * returns SNORT_SNPRINTF_TRUNCATION on truncation
78  * returns SNORT_SNPRINTF_ERROR on error
79  */
SnortSnprintfAppend(char * buf,size_t buf_size,const char * format,...)80 int SnortSnprintfAppend(char* buf, size_t buf_size, const char* format, ...)
81 {
82     int str_len;
83     int ret;
84     va_list ap;
85 
86     if (buf == nullptr || buf_size == 0 || format == nullptr)
87         return SNORT_SNPRINTF_ERROR;
88 
89     str_len = SnortStrnlen(buf, buf_size);
90 
91     /* since we've already checked buf and buf_size an error
92      * indicates no null termination, so just start at
93      * beginning of buffer */
94     if (str_len == SNORT_STRNLEN_ERROR)
95     {
96         buf[0] = '\0';
97         str_len = 0;
98     }
99 
100     buf[buf_size - 1] = '\0';
101 
102     va_start(ap, format);
103 
104     ret = vsnprintf(buf + str_len, buf_size - (size_t)str_len, format, ap);
105 
106     va_end(ap);
107 
108     if (ret < 0)
109         return SNORT_SNPRINTF_ERROR;
110 
111     if (buf[buf_size - 1] != '\0' || (size_t)ret >= buf_size)
112     {
113         /* truncation occurred */
114         buf[buf_size - 1] = '\0';
115         return SNORT_SNPRINTF_TRUNCATION;
116     }
117 
118     return SNORT_SNPRINTF_SUCCESS;
119 }
120 
121 /* Guaranteed to be '\0' terminated even if truncation occurs.
122  *
123  * Arguments:  dst - the string to contain the copy
124  *             src - the string to copy from
125  *             dst_size - the size of the destination buffer
126  *                        including the null byte.
127  *
128  * returns SNORT_STRNCPY_SUCCESS if successful
129  * returns SNORT_STRNCPY_TRUNCATION on truncation
130  * returns SNORT_STRNCPY_ERROR on error
131  *
132  * Note: Do not set dst[0] = '\0' on error since it's possible that
133  * dst and src are the same pointer - it will at least be null
134  * terminated in any case
135  */
SnortStrncpy(char * dst,const char * src,size_t dst_size)136 int SnortStrncpy(char* dst, const char* src, size_t dst_size)
137 {
138     char* ret = nullptr;
139 
140     if (dst == nullptr || src == nullptr || dst_size == 0)
141         return SNORT_STRNCPY_ERROR;
142 
143     dst[dst_size - 1] = '\0';
144 
145     ret = strncpy(dst, src, dst_size);
146 
147     /* Not sure if this ever happens but might as
148      * well be on the safe side */
149     if (ret == nullptr)
150         return SNORT_STRNCPY_ERROR;
151 
152     if (dst[dst_size - 1] != '\0')
153     {
154         /* result was truncated */
155         dst[dst_size - 1] = '\0';
156         return SNORT_STRNCPY_TRUNCATION;
157     }
158 
159     return SNORT_STRNCPY_SUCCESS;
160 }
161 
162 /* Determines whether a buffer is '\0' terminated and returns the
163  * string length if so
164  *
165  * returns the string length if '\0' terminated
166  * returns SNORT_STRNLEN_ERROR if not '\0' terminated
167  */
SnortStrnlen(const char * buf,int buf_size)168 int SnortStrnlen(const char* buf, int buf_size)
169 {
170     int i = 0;
171 
172     if (buf == nullptr || buf_size <= 0)
173         return SNORT_STRNLEN_ERROR;
174 
175     for (i = 0; i < buf_size; i++)
176     {
177         if (buf[i] == '\0')
178             break;
179     }
180 
181     if (i == buf_size)
182         return SNORT_STRNLEN_ERROR;
183 
184     return i;
185 }
186 
187 /*
188  * Find first occurrence of char of accept in s, limited by slen.
189  * A 'safe' version of strpbrk that won't read past end of buffer s
190  * in cases that s is not null terminated.
191  *
192  * This code assumes 'accept' is a static string.
193  */
SnortStrnPbrk(const char * s,int slen,const char * accept)194 const char* SnortStrnPbrk(const char* s, int slen, const char* accept)
195 {
196     if (!s || (slen == 0) || !*s || !accept)
197         return nullptr;
198 
199     const char* s_end = s + slen;
200 
201     while (s < s_end)
202     {
203         char ch = *s;
204 
205         if (strchr(accept, ch))
206             return s;
207         s++;
208     }
209     return nullptr;
210 }
211 
212 /*
213  * Find first occurrence of searchstr in s, limited by slen.
214  * A 'safe' version of strstr that won't read past end of buffer s
215  * in cases that s is not null terminated.
216  */
SnortStrnStr(const char * s,int slen,const char * searchstr)217 const char* SnortStrnStr(const char* s, int slen, const char* searchstr)
218 {
219     if (!s || (slen == 0) || !*s || !searchstr)
220         return nullptr;
221 
222     char ch;
223 
224     if ((ch = *searchstr++) != 0)
225     {
226         int len = strlen(searchstr);
227         do
228         {
229             char nc;
230             do
231             {
232                 if ((nc = *s++) == 0)
233                 {
234                     return nullptr;
235                 }
236                 slen--;
237                 if (slen == 0)
238                     return nullptr;
239             }
240             while (nc != ch);
241 
242             if (slen - len < 0)
243                 return nullptr;
244         }
245         while (memcmp(s, searchstr, len) != 0);
246         s--;
247     }
248     return s;
249 }
250 
251 /*
252  * Find first occurrence of substring in s, ignore case.
253 */
SnortStrcasestr(const char * s,int slen,const char * substr)254 const char* SnortStrcasestr(const char* s, int slen, const char* substr)
255 {
256     if (!s || (slen == 0) || !*s || !substr)
257         return nullptr;
258 
259     char ch;
260 
261     if ((ch = *substr++) != 0)
262     {
263         ch = tolower((char)ch);
264         int len = strlen(substr);
265 
266         do
267         {
268             char nc;
269             do
270             {
271                 if ((nc = *s++) == 0)
272                 {
273                     return nullptr;
274                 }
275                 slen--;
276                 if (slen == 0)
277                     return nullptr;
278             }
279             while ((char)tolower((uint8_t)nc) != ch);
280 
281             if (slen - len < 0)
282                 return nullptr;
283         }
284         while (strncasecmp(s, substr, len) != 0);
285         s--;
286     }
287     return s;
288 }
289 
290 /****************************************************************************
291  *
292  * Function: sfsnprintfappend
293  *
294  * Purpose: snprintf that appends to destination buffer
295  *
296  *          Appends the snprintf format string and arguments to dest
297  *          without going beyond dsize bounds.  Assumes dest has
298  *          been properly allocated, and is of dsize in length.
299  *
300  * Arguments: dest      ==> pointer to string buffer to append to
301  *            dsize     ==> size of buffer dest
302  *            format    ==> snprintf format string
303  *            ...       ==> arguments for printf
304  *
305  * Returns: number of characters added to the buffer
306  *
307  ****************************************************************************/
sfsnprintfappend(char * dest,int dsize,const char * format,...)308 int sfsnprintfappend(char* dest, int dsize, const char* format, ...)
309 {
310     int currLen, appendLen;
311     va_list ap;
312 
313     if (!dest || dsize == 0)
314         return -1;
315 
316     currLen = SnortStrnlen(dest, dsize);
317     if (currLen == -1)
318         return -1;
319 
320     va_start(ap, format);
321     appendLen = vsnprintf(dest+currLen, dsize-currLen, format, ap);
322     va_end(ap);
323 
324     dest[dsize-1]=0; /* guarantee a null termination */
325 
326     if (appendLen >= (dsize - currLen))
327         appendLen = dsize - currLen - 1;
328     else if (appendLen < 0)
329         appendLen = 0;
330 
331     return appendLen;
332 }
333 
334 // return actual number of bytes written to buffer s
safe_snprintf(char * s,size_t n,const char * format,...)335 int safe_snprintf(char* s, size_t n, const char* format, ... )
336 {
337     va_list ap;
338 
339     va_start(ap, format);
340     int len = vsnprintf(s, n, format, ap);
341     va_end(ap);
342 
343     if (len >= (int)n)
344         len = n - 1;
345     else if (len < 0)
346         len = 0;
347 
348     return len;
349 }
350 
351 }
352 
353