1 /*
2  * Wireshark - Network traffic analyzer
3  * By Gerald Combs <gerald@wireshark.org>
4  * Copyright 2001 Gerald Combs
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "config.h"
10 
11 #include <stdio.h>
12 #include <ftypes-int.h>
13 #include <string.h>
14 
15 #define CMP_MATCHES cmp_matches
16 
17 #include <strutil.h>
18 #include <wsutil/ws_assert.h>
19 
20 static void
string_fvalue_new(fvalue_t * fv)21 string_fvalue_new(fvalue_t *fv)
22 {
23 	fv->value.string = NULL;
24 }
25 
26 static void
string_fvalue_free(fvalue_t * fv)27 string_fvalue_free(fvalue_t *fv)
28 {
29 	g_free(fv->value.string);
30 }
31 
32 static void
string_fvalue_set_string(fvalue_t * fv,const gchar * value)33 string_fvalue_set_string(fvalue_t *fv, const gchar *value)
34 {
35 	DISSECTOR_ASSERT(value != NULL);
36 
37 	/* Free up the old value, if we have one */
38 	string_fvalue_free(fv);
39 
40 	fv->value.string = (gchar *)g_strdup(value);
41 }
42 
43 static int
string_repr_len(fvalue_t * fv,ftrepr_t rtype,int field_display _U_)44 string_repr_len(fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
45 {
46 	switch (rtype) {
47 		case FTREPR_DISPLAY:
48 			return (int)strlen(fv->value.string);
49 
50 		case FTREPR_DFILTER:
51 			return escape_string_len(fv->value.string);
52 	}
53 	ws_assert_not_reached();
54 	return -1;
55 }
56 
57 static void
string_to_repr(fvalue_t * fv,ftrepr_t rtype,int field_display _U_,char * buf,unsigned int size)58 string_to_repr(fvalue_t *fv, ftrepr_t rtype, int field_display _U_, char *buf, unsigned int size)
59 {
60 	switch (rtype) {
61 		case FTREPR_DISPLAY:
62 			(void) g_strlcpy(buf, fv->value.string, size);
63 			return;
64 
65 		case FTREPR_DFILTER:
66 			escape_string(buf, fv->value.string);
67 			return;
68 	}
69 	ws_assert_not_reached();
70 }
71 
72 
73 static gpointer
value_get(fvalue_t * fv)74 value_get(fvalue_t *fv)
75 {
76 	return fv->value.string;
77 }
78 
79 static gboolean
val_from_string(fvalue_t * fv,const char * s,gchar ** err_msg _U_)80 val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
81 {
82 	/* Free up the old value, if we have one */
83 	string_fvalue_free(fv);
84 
85 	fv->value.string = g_strdup(s);
86 	return TRUE;
87 }
88 
89 static gboolean
val_from_unparsed(fvalue_t * fv,const char * s,gboolean allow_partial_value _U_,gchar ** err_msg)90 val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
91 {
92 	fvalue_t *fv_bytes;
93 
94 	/* Does this look like a byte-string? */
95 	fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL);
96 	if (fv_bytes) {
97 		/* Free up the old value, if we have one */
98 		string_fvalue_free(fv);
99 
100 		/* Copy the bytes over to a string and terminate it
101 		 * with a NUL. XXX - what if the user embeds a NUL
102 		 * in the middle of the byte string? */
103 		int num_bytes = fv_bytes->value.bytes->len;
104 
105 		fv->value.string = (gchar *)g_malloc(num_bytes + 1);
106 		memcpy(fv->value.string, fv_bytes->value.bytes->data, num_bytes);
107 		fv->value.string[num_bytes] = '\0';
108 
109 		FVALUE_FREE(fv_bytes);
110 		return TRUE;
111 	} else {
112 		/* Just turn it into a string */
113 		return val_from_string(fv, s, err_msg);
114 	}
115 }
116 
117 static guint
len(fvalue_t * fv)118 len(fvalue_t *fv)
119 {
120 	return (guint)strlen(fv->value.string);
121 }
122 
123 static void
slice(fvalue_t * fv,GByteArray * bytes,guint offset,guint length)124 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
125 {
126 	guint8* data;
127 
128 	data = fv->value.ustring + offset;
129 
130 	g_byte_array_append(bytes, data, length);
131 }
132 
133 
134 static gboolean
cmp_eq(const fvalue_t * a,const fvalue_t * b)135 cmp_eq(const fvalue_t *a, const fvalue_t *b)
136 {
137 	return (strcmp(a->value.string, b->value.string) == 0);
138 }
139 
140 static gboolean
cmp_ne(const fvalue_t * a,const fvalue_t * b)141 cmp_ne(const fvalue_t *a, const fvalue_t *b)
142 {
143 	return (strcmp(a->value.string, b->value.string) != 0);
144 }
145 
146 static gboolean
cmp_gt(const fvalue_t * a,const fvalue_t * b)147 cmp_gt(const fvalue_t *a, const fvalue_t *b)
148 {
149 	return (strcmp(a->value.string, b->value.string) > 0);
150 }
151 
152 static gboolean
cmp_ge(const fvalue_t * a,const fvalue_t * b)153 cmp_ge(const fvalue_t *a, const fvalue_t *b)
154 {
155 	return (strcmp(a->value.string, b->value.string) >= 0);
156 }
157 
158 static gboolean
cmp_lt(const fvalue_t * a,const fvalue_t * b)159 cmp_lt(const fvalue_t *a, const fvalue_t *b)
160 {
161 	return (strcmp(a->value.string, b->value.string) < 0);
162 }
163 
164 static gboolean
cmp_le(const fvalue_t * a,const fvalue_t * b)165 cmp_le(const fvalue_t *a, const fvalue_t *b)
166 {
167 	return (strcmp(a->value.string, b->value.string) <= 0);
168 }
169 
170 static gboolean
cmp_contains(const fvalue_t * fv_a,const fvalue_t * fv_b)171 cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b)
172 {
173 	/* According to
174 	* http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html
175 	* strstr() returns a non-NULL value if needle is an empty
176 	* string. We don't that behavior for cmp_contains. */
177 	if (strlen(fv_b->value.string) == 0) {
178 		return FALSE;
179 	}
180 
181 	if (strstr(fv_a->value.string, fv_b->value.string)) {
182 		return TRUE;
183 	}
184 	else {
185 		return FALSE;
186 	}
187 }
188 
189 static gboolean
cmp_matches(const fvalue_t * fv,const GRegex * regex)190 cmp_matches(const fvalue_t *fv, const GRegex *regex)
191 {
192 	char *str = fv->value.string;
193 
194 	if (! regex) {
195 		return FALSE;
196 	}
197 	return g_regex_match_full(
198 			regex,		/* Compiled PCRE */
199 			str,		/* The data to check for the pattern... */
200 			(int)strlen(str),	/* ... and its length */
201 			0,		/* Start offset within data */
202 			(GRegexMatchFlags)0,		/* GRegexMatchFlags */
203 			NULL,		/* We are not interested in the match information */
204 			NULL		/* We don't want error information */
205 			);
206 }
207 
208 void
ftype_register_string(void)209 ftype_register_string(void)
210 {
211 
212 	static ftype_t string_type = {
213 		FT_STRING,			/* ftype */
214 		"FT_STRING",			/* name */
215 		"Character string",		/* pretty_name */
216 		0,				/* wire_size */
217 		string_fvalue_new,		/* new_value */
218 		string_fvalue_free,		/* free_value */
219 		val_from_unparsed,		/* val_from_unparsed */
220 		val_from_string,		/* val_from_string */
221 		string_to_repr,			/* val_to_string_repr */
222 		string_repr_len,		/* len_string_repr */
223 
224 		{ .set_value_string = string_fvalue_set_string },	/* union set_value */
225 		{ .get_value_ptr = value_get },	/* union get_value */
226 
227 		cmp_eq,
228 		cmp_ne,
229 		cmp_gt,
230 		cmp_ge,
231 		cmp_lt,
232 		cmp_le,
233 		NULL,				/* cmp_bitwise_and */
234 		cmp_contains,
235 		CMP_MATCHES,
236 
237 		len,
238 		slice,
239 	};
240 	static ftype_t stringz_type = {
241 		FT_STRINGZ,			/* ftype */
242 		"FT_STRINGZ",			/* name */
243 		"Character string",		/* pretty name */
244 		0,				/* wire_size */
245 		string_fvalue_new,		/* new_value */
246 		string_fvalue_free,		/* free_value */
247 		val_from_unparsed,		/* val_from_unparsed */
248 		val_from_string,		/* val_from_string */
249 		string_to_repr,			/* val_to_string_repr */
250 		string_repr_len,		/* len_string_repr */
251 
252 		{ .set_value_string = string_fvalue_set_string },	/* union set_value */
253 		{ .get_value_ptr = value_get },	/* union get_value */
254 
255 		cmp_eq,
256 		cmp_ne,
257 		cmp_gt,
258 		cmp_ge,
259 		cmp_lt,
260 		cmp_le,
261 		NULL,				/* cmp_bitwise_and */
262 		cmp_contains,			/* cmp_contains */
263 		CMP_MATCHES,
264 
265 		len,
266 		slice,
267 	};
268 	static ftype_t uint_string_type = {
269 		FT_UINT_STRING,		/* ftype */
270 		"FT_UINT_STRING",		/* name */
271 		"Character string",		/* pretty_name */
272 		0,				/* wire_size */
273 		string_fvalue_new,		/* new_value */
274 		string_fvalue_free,		/* free_value */
275 		val_from_unparsed,		/* val_from_unparsed */
276 		val_from_string,		/* val_from_string */
277 		string_to_repr,			/* val_to_string_repr */
278 		string_repr_len,		/* len_string_repr */
279 
280 		{ .set_value_string = string_fvalue_set_string },	/* union set_value */
281 		{ .get_value_ptr = value_get },	/* union get_value */
282 
283 		cmp_eq,
284 		cmp_ne,
285 		cmp_gt,
286 		cmp_ge,
287 		cmp_lt,
288 		cmp_le,
289 		NULL,				/* cmp_bitwise_and */
290 		cmp_contains,			/* cmp_contains */
291 		CMP_MATCHES,
292 
293 		len,
294 		slice,
295 	};
296 	static ftype_t stringzpad_type = {
297 		FT_STRINGZPAD,			/* ftype */
298 		"FT_STRINGZPAD",		/* name */
299 		"Character string",		/* pretty name */
300 		0,				/* wire_size */
301 		string_fvalue_new,		/* new_value */
302 		string_fvalue_free,		/* free_value */
303 		val_from_unparsed,		/* val_from_unparsed */
304 		val_from_string,		/* val_from_string */
305 		string_to_repr,			/* val_to_string_repr */
306 		string_repr_len,		/* len_string_repr */
307 
308 		{ .set_value_string = string_fvalue_set_string },	/* union set_value */
309 		{ .get_value_ptr = value_get },	/* union get_value */
310 
311 		cmp_eq,
312 		cmp_ne,
313 		cmp_gt,
314 		cmp_ge,
315 		cmp_lt,
316 		cmp_le,
317 		NULL,				/* cmp_bitwise_and */
318 		cmp_contains,			/* cmp_contains */
319 		CMP_MATCHES,
320 
321 		len,
322 		slice,
323 	};
324 	static ftype_t stringztrunc_type = {
325 		FT_STRINGZTRUNC,		/* ftype */
326 		"FT_STRINGZTRUNC",		/* name */
327 		"Character string",		/* pretty name */
328 		0,				/* wire_size */
329 		string_fvalue_new,		/* new_value */
330 		string_fvalue_free,		/* free_value */
331 		val_from_unparsed,		/* val_from_unparsed */
332 		val_from_string,		/* val_from_string */
333 		string_to_repr,			/* val_to_string_repr */
334 		string_repr_len,		/* len_string_repr */
335 
336 		{ .set_value_string = string_fvalue_set_string },	/* union set_value */
337 		{ .get_value_ptr = value_get },	/* union get_value */
338 
339 		cmp_eq,
340 		cmp_ne,
341 		cmp_gt,
342 		cmp_ge,
343 		cmp_lt,
344 		cmp_le,
345 		NULL,				/* cmp_bitwise_and */
346 		cmp_contains,			/* cmp_contains */
347 		CMP_MATCHES,
348 
349 		len,
350 		slice,
351 	};
352 
353 	ftype_register(FT_STRING, &string_type);
354 	ftype_register(FT_STRINGZ, &stringz_type);
355 	ftype_register(FT_UINT_STRING, &uint_string_type);
356 	ftype_register(FT_STRINGZPAD, &stringzpad_type);
357 	ftype_register(FT_STRINGZTRUNC, &stringztrunc_type);
358 }
359 
360 /*
361  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
362  *
363  * Local variables:
364  * c-basic-offset: 8
365  * tab-width: 8
366  * indent-tabs-mode: t
367  * End:
368  *
369  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
370  * :indentSize=8:tabSize=8:noTabs=false:
371  */
372