~ubuntu-branches/ubuntu/lucid/rsyslog/lucid

« back to all changes in this revision

Viewing changes to parse.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2007-10-19 17:21:49 UTC
  • Revision ID: james.westby@ubuntu.com-20071019172149-ie6ej2xve33mxiu7
Tags: upstream-1.19.10
ImportĀ upstreamĀ versionĀ 1.19.10

Show diffs side-by-side

added added

removed removed

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