1 /* parsing routines for the counted string class. for generic
2  * informaton see parse.h.
3  *
4  * begun 2005-09-15 rgerhards
5  *
6  * Copyright 2005-2017 Adiscon GmbH.
7  *
8  * This file is part of rsyslog.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *       http://www.apache.org/licenses/LICENSE-2.0
15  *       -or-
16  *       see COPYING.ASL20 in the source distribution
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  */
24 #include "config.h"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <arpa/inet.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netdb.h>
35 #include "rsyslog.h"
36 #include "net.h" /* struct NetAddr */
37 #include "parse.h"
38 #include "debug.h"
39 
40 /* ################################################################# *
41  * private members                                                   *
42  * ################################################################# */
43 
44 
45 
46 /* ################################################################# *
47  * public members                                                    *
48  * ################################################################# */
49 
50 
51 /**
52  * Destruct a rsPars object and its associated string.
53  * rgerhards, 2005-09-26
54  */
rsParsDestruct(rsParsObj * pThis)55 rsRetVal rsParsDestruct(rsParsObj *pThis)
56 {
57 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
58 
59 	if(pThis->pCStr != NULL)
60 		rsCStrDestruct(&pThis->pCStr);
61 	RSFREEOBJ(pThis);
62 	return RS_RET_OK;
63 }
64 
65 
66 /**
67  * Construct a rsPars object.
68  */
rsParsConstruct(rsParsObj ** ppThis)69 rsRetVal rsParsConstruct(rsParsObj **ppThis)
70 {
71 	rsParsObj *pThis;
72 
73 	assert(ppThis != NULL);
74 
75 	if((pThis = (rsParsObj*) calloc(1, sizeof(rsParsObj))) == NULL)
76 		return RS_RET_OUT_OF_MEMORY;
77 
78 	rsSETOBJTYPE(pThis, OIDrsPars);
79 
80 	*ppThis = pThis;
81 	return RS_RET_OK;
82 }
83 
84 /**
85  * Construct a rsPars object and populate it with a
86  * classical zero-terinated C-String.
87  * rgerhards, 2005-09-27
88  */
rsParsConstructFromSz(rsParsObj ** ppThis,unsigned char * psz)89 rsRetVal rsParsConstructFromSz(rsParsObj **ppThis, unsigned char *psz)
90 {
91 	DEFiRet;
92 	rsParsObj *pThis;
93 	cstr_t *pCS;
94 
95 	assert(ppThis != NULL);
96 	assert(psz != NULL);
97 
98 	/* create string for parser */
99 	CHKiRet(rsCStrConstructFromszStr(&pCS, psz));
100 
101 	/* create parser */
102 	if((iRet = rsParsConstruct(&pThis)) != RS_RET_OK) {
103 		rsCStrDestruct(&pCS);
104 		FINALIZE;
105 	}
106 
107 	/* assign string to parser */
108 	if((iRet = rsParsAssignString(pThis, pCS)) != RS_RET_OK) {
109 		rsParsDestruct(pThis);
110 		FINALIZE;
111 	}
112 	*ppThis = pThis;
113 
114 finalize_it:
115 	RETiRet;
116 }
117 
118 /**
119  * Assign the to-be-parsed string.
120  */
rsParsAssignString(rsParsObj * pThis,cstr_t * pCStr)121 rsRetVal rsParsAssignString(rsParsObj *pThis, cstr_t *pCStr)
122 {
123 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
124 	rsCHECKVALIDOBJECT(pCStr, OIDrsCStr);
125 
126 	pThis->pCStr = pCStr;
127 	pThis->iCurrPos = 0;
128 
129 	return RS_RET_OK;
130 }
131 
132 /* parse an integer. The parse pointer is advanced to the
133  * position directly after the last digit. If no digit is
134  * found at all, an error is returned and the parse pointer
135  * is NOT advanced.
136  * PORTABILITY WARNING: this function depends on the
137  * continues representation of digits inside the character
138  * set (as in ASCII).
139  * rgerhards 2005-09-27
140  */
parsInt(rsParsObj * pThis,int * pInt)141 rsRetVal parsInt(rsParsObj *pThis, int* pInt)
142 {
143 	unsigned char *pC;
144 	int iVal;
145 
146 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
147 	assert(pInt != NULL);
148 
149 	iVal = 0;
150 	pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
151 
152 	/* order of checks is important, else we might do
153 	 * mis-addressing! (off by one)
154 	 */
155 	if(pThis->iCurrPos >= rsCStrLen(pThis->pCStr))
156 		return RS_RET_NO_MORE_DATA;
157 	if(!isdigit((int)*pC))
158 		return RS_RET_NO_DIGIT;
159 
160 	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && isdigit((int)*pC)) {
161 		iVal = iVal * 10 + *pC - '0';
162 		++pThis->iCurrPos;
163 		++pC;
164 	}
165 
166 	*pInt = iVal;
167 
168 	return RS_RET_OK;
169 }
170 
171 /* Skip everything up to a specified character.
172  * Returns with ParsePointer set BEHIND this character.
173  * Returns RS_RET_OK if found, RS_RET_NOT_FOUND if not
174  * found. In that case, the ParsePointer is moved to the
175  * last character of the string.
176  * 2005-09-19 rgerhards
177  */
parsSkipAfterChar(rsParsObj * pThis,char c)178 rsRetVal parsSkipAfterChar(rsParsObj *pThis, char c)
179 {
180 	register unsigned char *pC;
181 	DEFiRet;
182 
183 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
184 
185 	pC = rsCStrGetBufBeg(pThis->pCStr);
186 
187 	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
188 		if(pC[pThis->iCurrPos] == c)
189 			break;
190 		++pThis->iCurrPos;
191 	}
192 
193 	/* delimiter found? */
194 	if(pC[pThis->iCurrPos] == c) {
195 		if(pThis->iCurrPos+1 < rsCStrLen(pThis->pCStr)) {
196 			iRet = RS_RET_OK;
197 			pThis->iCurrPos++; /* 'eat' delimiter */
198 		} else {
199 			iRet = RS_RET_FOUND_AT_STRING_END;
200 		}
201 	} else {
202 		iRet = RS_RET_NOT_FOUND;
203 	}
204 
205 	RETiRet;
206 }
207 
208 /* Skip whitespace. Often used to trim parsable entries.
209  * Returns with ParsePointer set to first non-whitespace
210  * character (or at end of string).
211  * If bRequireOne is set to true, at least one whitespace
212  * must exist, else an error is returned.
213  */
parsSkipWhitespace(rsParsObj * pThis)214 rsRetVal parsSkipWhitespace(rsParsObj *pThis)
215 {
216 	register unsigned char *pC;
217 	int numSkipped;
218 	DEFiRet;
219 
220 
221 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
222 
223 	pC = rsCStrGetBufBeg(pThis->pCStr);
224 
225 	numSkipped = 0;
226 	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
227 		if(!isspace((int)*(pC+pThis->iCurrPos)))
228 			break;
229 		++pThis->iCurrPos;
230 		++numSkipped;
231 	}
232 
233 	RETiRet;
234 }
235 
236 /* Parse string up to a delimiter.
237  *
238  * Input:
239  * cDelim - the delimiter. Note that SP within a value always is a delimiter,
240  * so cDelim is actually an *additional* delimiter.
241  *   The following two are for whitespace stripping,
242  *   0 means "no", 1 "yes"
243  *   - bTrimLeading
244  *   - bTrimTrailing
245  *   - bConvLower - convert string to lower case?
246  *
247  * Output:
248  * ppCStr Pointer to the parsed string - must be freed by caller!
249  */
parsDelimCStr(rsParsObj * pThis,cstr_t ** ppCStr,char cDelim,int bTrimLeading,int bTrimTrailing,int bConvLower)250 rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing,
251 	int bConvLower)
252 {
253 	DEFiRet;
254 	register unsigned char *pC;
255 	cstr_t *pCStr = NULL;
256 
257 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
258 
259 	CHKiRet(rsCStrConstruct(&pCStr));
260 
261 	if(bTrimLeading)
262 		parsSkipWhitespace(pThis);
263 
264 	pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
265 
266 	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) {
267 		CHKiRet(cstrAppendChar(pCStr, bConvLower ? tolower(*pC) : *pC));
268 		++pThis->iCurrPos;
269 		++pC;
270 	}
271 
272 	if(pThis->iCurrPos < cstrLen(pThis->pCStr)) { //BUGFIX!!
273 		++pThis->iCurrPos; /* eat delimiter */
274 	}
275 
276 	/* We got the string, now take it and see if we need to
277 	 * remove anything at its end.
278 	 */
279 	cstrFinalize(pCStr);
280 
281 	if(bTrimTrailing) {
282 		cstrTrimTrailingWhiteSpace(pCStr);
283 	}
284 
285 	/* done! */
286 	*ppCStr = pCStr;
287 
288 finalize_it:
289 	if(iRet != RS_RET_OK) {
290 		if(pCStr != NULL)
291 			rsCStrDestruct(&pCStr);
292 	}
293 
294 	RETiRet;
295 }
296 
297 /* Parse a quoted string ("-some-data") from the given position.
298  * Leading whitespace before the first quote is skipped. During
299  * parsing, escape sequences are detected and converted:
300  * \\ - backslash character
301  * \" - quote character
302  * any other value \<somechar> is reserved for future use.
303  *
304  * After return, the parse pointer is paced after the trailing
305  * quote.
306  *
307  * Output:
308  * ppCStr Pointer to the parsed string - must be freed by caller and
309  *        does NOT include the quotes.
310  * rgerhards, 2005-09-19
311  */
parsQuotedCStr(rsParsObj * pThis,cstr_t ** ppCStr)312 rsRetVal parsQuotedCStr(rsParsObj *pThis, cstr_t **ppCStr)
313 {
314 	register unsigned char *pC;
315 	cstr_t *pCStr = NULL;
316 	DEFiRet;
317 
318 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
319 
320 	CHKiRet(parsSkipAfterChar(pThis, '"'));
321 	pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
322 
323 	/* OK, we most probably can obtain a value... */
324 	CHKiRet(cstrConstruct(&pCStr));
325 
326 	while(pThis->iCurrPos < cstrLen(pThis->pCStr)) {
327 		if(*pC == '"') {
328 			break;	/* we are done! */
329 		} else if(*pC == '\\') {
330 			++pThis->iCurrPos;
331 			++pC;
332 			if(pThis->iCurrPos < cstrLen(pThis->pCStr)) {
333 				/* in this case, we copy the escaped character
334 				 * to the output buffer (but do not rely on this,
335 				 * we might later introduce other things, like \007!
336 				 */
337 				CHKiRet(cstrAppendChar(pCStr, *pC));
338 			}
339 		} else { /* regular character */
340 			CHKiRet(cstrAppendChar(pCStr, *pC));
341 		}
342 		++pThis->iCurrPos;
343 		++pC;
344 	}
345 
346 	if(*pC == '"') {
347 		++pThis->iCurrPos; /* 'eat' trailing quote */
348 	} else {
349 		/* error - improperly quoted string! */
350 		cstrDestruct(&pCStr);
351 		ABORT_FINALIZE(RS_RET_MISSING_TRAIL_QUOTE);
352 	}
353 
354 	cstrFinalize(pCStr);
355 
356 	/* done! */
357 	*ppCStr = pCStr;
358 
359 finalize_it:
360 	if(iRet != RS_RET_OK) {
361 		if(pCStr != NULL)
362 			cstrDestruct(&pCStr);
363 	}
364 
365 	RETiRet;
366 }
367 
368 /*
369  * Parsing routine for IPv4, IPv6 and domain name wildcards.
370  *
371  * Parses string in the format <addr>[/bits] where
372  * addr can be a IPv4 address (e.g.: 127.0.0.1), IPv6 address (e.g.: [::1]),
373  * full hostname (e.g.: localhost.localdomain) or hostname wildcard
374  * (e.g.: *.localdomain).
375  */
376 #ifdef SYSLOG_INET
parsAddrWithBits(rsParsObj * pThis,struct NetAddr ** pIP,int * pBits)377 rsRetVal parsAddrWithBits(rsParsObj *pThis, struct NetAddr **pIP, int *pBits)
378 {
379 	register uchar *pC;
380 	uchar *pszIP = NULL;
381 	uchar *pszTmp;
382 	struct addrinfo hints, *res = NULL;
383 	cstr_t *pCStr;
384 	DEFiRet;
385 
386 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
387 	assert(pIP != NULL);
388 	assert(pBits != NULL);
389 
390 	CHKiRet(cstrConstruct(&pCStr));
391 
392 	parsSkipWhitespace(pThis);
393 	pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
394 
395 	/* we parse everything until either '/', ',' or
396 	 * whitespace. Validity will be checked down below.
397 	 */
398 	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
399 	      && *pC != '/' && *pC != ',' && !isspace((int)*pC)) {
400 		if((iRet = cstrAppendChar(pCStr, *pC)) != RS_RET_OK) {
401 			cstrDestruct (&pCStr);
402 			FINALIZE;
403 		}
404 		++pThis->iCurrPos;
405 		++pC;
406 	}
407 
408 	cstrFinalize(pCStr);
409 
410 	/* now we have the string and must check/convert it to
411 	 * an NetAddr structure.
412 	 */
413 	CHKiRet(cstrConvSzStrAndDestruct(&pCStr, &pszIP, 0));
414 
415 	if((*pIP = calloc(1, sizeof(struct NetAddr))) == NULL)
416 		ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
417 
418 	if (*((char*)pszIP) == '[') {
419 		pszTmp = (uchar*)strchr ((char*)pszIP, ']');
420 		if (pszTmp == NULL) {
421 			free (*pIP);
422 			ABORT_FINALIZE(RS_RET_INVALID_IP);
423 		}
424 		*pszTmp = '\0';
425 
426 		memset (&hints, 0, sizeof (struct addrinfo));
427 		hints.ai_family = AF_INET6;
428 		hints.ai_flags  = AI_NUMERICHOST;
429 
430 		switch(getaddrinfo ((char*)pszIP+1, NULL, &hints, &res)) {
431 		case 0:
432 			(*pIP)->addr.NetAddr = malloc (res->ai_addrlen);
433 			memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen);
434 			freeaddrinfo (res);
435 			break;
436 		case EAI_NONAME:
437 			/* The "address" is not an IP prefix but a wildcard */
438 			F_SET((*pIP)->flags, ADDR_NAME|ADDR_PRI6);
439 			(*pIP)->addr.HostWildcard = strdup ((const char*)pszIP+1);
440 			break;
441 		default:
442 			free (*pIP);
443 			ABORT_FINALIZE(RS_RET_ERR);
444 		}
445 
446 		if(*pC == '/') {
447 			/* mask bits follow, let's parse them! */
448 			++pThis->iCurrPos; /* eat slash */
449 			if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) {
450 				free((*pIP)->addr.NetAddr);
451 				free((*pIP)->addr.HostWildcard);
452 				free (*pIP);
453 				FINALIZE;
454 			}
455 			/* we need to refresh pointer (changed by parsInt()) */
456 			pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
457 		} else {
458 			/* no slash, so we assume a single host (/128) */
459 			*pBits = 128;
460 		}
461 	} else { /* now parse IPv4 */
462 		memset (&hints, 0, sizeof (struct addrinfo));
463 		hints.ai_family = AF_INET;
464 		hints.ai_flags  = AI_NUMERICHOST;
465 
466 		switch(getaddrinfo ((char*)pszIP, NULL, &hints, &res)) {
467 		case 0:
468 			(*pIP)->addr.NetAddr = malloc (res->ai_addrlen);
469 			memcpy ((*pIP)->addr.NetAddr, res->ai_addr, res->ai_addrlen);
470 			freeaddrinfo (res);
471 			break;
472 		case EAI_NONAME:
473 			/* The "address" is not an IP prefix but a wildcard */
474 			F_SET((*pIP)->flags, ADDR_NAME);
475 			(*pIP)->addr.HostWildcard = strdup ((const char*)pszIP);
476 			break;
477 		default:
478 			free (*pIP);
479 			ABORT_FINALIZE(RS_RET_ERR);
480 		}
481 
482 		if(*pC == '/') {
483 			/* mask bits follow, let's parse them! */
484 			++pThis->iCurrPos; /* eat slash */
485 			if((iRet = parsInt(pThis, pBits)) != RS_RET_OK) {
486 				free((*pIP)->addr.NetAddr);
487 				free((*pIP)->addr.HostWildcard);
488 				free (*pIP);
489 				FINALIZE;
490 			}
491 			/* we need to refresh pointer (changed by parsInt()) */
492 			pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
493 		} else {
494 			/* no slash, so we assume a single host (/32) */
495 			*pBits = 32;
496 		}
497 	}
498 
499 	/* skip to next processable character */
500 	while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
501 	      && (*pC == ',' || isspace((int)*pC))) {
502 		++pThis->iCurrPos;
503 		++pC;
504 	}
505 
506 	iRet = RS_RET_OK;
507 
508 finalize_it:
509 	free(pszIP);
510 	RETiRet;
511 }
512 #endif  /* #ifdef SYSLOG_INET */
513 
514 
515 /* tell if the parsepointer is at the end of the
516  * to-be-parsed string. Returns 1, if so, 0
517  * otherwise. rgerhards, 2005-09-27
518  */
parsIsAtEndOfParseString(rsParsObj * pThis)519 int parsIsAtEndOfParseString(rsParsObj *pThis)
520 {
521 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
522 
523 	return (pThis->iCurrPos < rsCStrLen(pThis->pCStr)) ? 0 : 1;
524 }
525 
526 
527 /* return the position of the parse pointer
528  */
rsParsGetParsePointer(rsParsObj * pThis)529 int rsParsGetParsePointer(rsParsObj *pThis)
530 {
531 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
532 
533 	if(pThis->iCurrPos < rsCStrLen(pThis->pCStr))
534 		return pThis->iCurrPos;
535 	else
536 		return rsCStrLen(pThis->pCStr) - 1;
537 }
538 
539 /* peek at the character at the parse pointer
540  * the caller must ensure that the parse pointer is not
541  * at the end of the parse buffer (e.g. by first calling
542  * parsIsAtEndOfParseString).
543  * rgerhards, 2005-09-27
544  */
parsPeekAtCharAtParsPtr(rsParsObj * pThis)545 char parsPeekAtCharAtParsPtr(rsParsObj *pThis)
546 {
547 	rsCHECKVALIDOBJECT(pThis, OIDrsPars);
548 	assert(pThis->iCurrPos < rsCStrLen(pThis->pCStr));
549 
550 	return(*(pThis->pCStr->pBuf + pThis->iCurrPos));
551 }
552 
553 /* return the current position inside the parse object.
554  * rgerhards, 2007-07-04
555  */
parsGetCurrentPosition(rsParsObj * pThis)556 int parsGetCurrentPosition(rsParsObj *pThis)
557 {
558 	return pThis->iCurrPos;
559 }
560 
561 
562 /*
563  * Local variables:
564  *  c-indent-level: 8
565  *  c-basic-offset: 8
566  *  tab-width: 8
567  * End:
568  * vi:set ai:
569  */
570