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