~ubuntu-branches/ubuntu/wily/389-ds-base/wily

« back to all changes in this revision

Viewing changes to ldap/servers/plugins/syntaxes/validate.c

  • Committer: Package Import Robot
  • Author(s): Krzysztof Klimonda
  • Date: 2012-03-27 14:26:16 UTC
  • Revision ID: package-import@ubuntu.com-20120327142616-xt24t6nffm3f7ybz
Tags: upstream-1.2.11.7
ImportĀ upstreamĀ versionĀ 1.2.11.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** BEGIN COPYRIGHT BLOCK
 
2
 * This Program is free software; you can redistribute it and/or modify it under
 
3
 * the terms of the GNU General Public License as published by the Free Software
 
4
 * Foundation; version 2 of the License.
 
5
 * 
 
6
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 
7
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
8
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
9
 * 
 
10
 * You should have received a copy of the GNU General Public License along with
 
11
 * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
12
 * Place, Suite 330, Boston, MA 02111-1307 USA.
 
13
 * 
 
14
 * In addition, as a special exception, Red Hat, Inc. gives You the additional
 
15
 * right to link the code of this Program with code not covered under the GNU
 
16
 * General Public License ("Non-GPL Code") and to distribute linked combinations
 
17
 * including the two, subject to the limitations in this paragraph. Non-GPL Code
 
18
 * permitted under this exception must only link to the code of this Program
 
19
 * through those well defined interfaces identified in the file named EXCEPTION
 
20
 * found in the source code files (the "Approved Interfaces"). The files of
 
21
 * Non-GPL Code may instantiate templates or use macros or inline functions from
 
22
 * the Approved Interfaces without causing the resulting work to be covered by
 
23
 * the GNU General Public License. Only Red Hat, Inc. may make changes or
 
24
 * additions to the list of Approved Interfaces. You must obey the GNU General
 
25
 * Public License in all respects for all of the Program code and other code used
 
26
 * in conjunction with the Program except the Non-GPL Code covered by this
 
27
 * exception. If you modify this file, you may extend this exception to your
 
28
 * version of the file, but you are not obligated to do so. If you do not wish to
 
29
 * provide this exception without modification, you must delete this exception
 
30
 * statement from your version and license this file solely under the GPL without
 
31
 * exception. 
 
32
 * 
 
33
 * 
 
34
 * Copyright (C) 2009 Red Hat, Inc.
 
35
 * All rights reserved.
 
36
 * END COPYRIGHT BLOCK **/
 
37
 
 
38
#ifdef HAVE_CONFIG_H
 
39
#  include <config.h>
 
40
#endif
 
41
 
 
42
/* validate.c - syntax validation helper functions */
 
43
 
 
44
#include <stdio.h>
 
45
#include <string.h>
 
46
#include <sys/types.h>
 
47
#include "syntax.h"
 
48
 
 
49
/* Helper function for processing a 'keystring'.
 
50
 *
 
51
 * Returns 0 is the value between begin and end is a valid 'keystring'.
 
52
 * Returns non-zero if the value is not a valide 'keystring'.
 
53
 */
 
54
int keystring_validate(
 
55
        const char *begin,
 
56
        const char *end
 
57
)
 
58
{
 
59
        int rc = 0;    /* assume the value is valid */
 
60
        const char *p = begin;
 
61
        
 
62
        if ((begin == NULL) || (end == NULL)) {
 
63
                rc = 1;
 
64
                goto exit;
 
65
        }
 
66
 
 
67
        /* Per RFC4512:
 
68
         *
 
69
         *   keystring = leadkeychar *keychar
 
70
         */
 
71
        if (IS_LEADKEYCHAR(*p)) {
 
72
                for (p++; p <= end; p++) {
 
73
                        if (!IS_KEYCHAR(*p)) {
 
74
                                rc = 1;
 
75
                                goto exit;
 
76
                        }
 
77
                }
 
78
        } else {
 
79
                rc = 1;
 
80
                goto exit;
 
81
        }
 
82
 
 
83
exit:
 
84
        return( rc );
 
85
}
 
86
 
 
87
/* Helper function for processing a 'numericoid'.
 
88
 *
 
89
 * Returns 0 is the value between begin and end is a valid 'numericoid'.
 
90
 * Returns non-zero if the value is not a valide 'numericoid'.
 
91
 */
 
92
int numericoid_validate(
 
93
        const char *begin,
 
94
        const char *end
 
95
)
 
96
{
 
97
        int rc = 0; /* assume the value is valid */
 
98
        int found_separator = 0;
 
99
        const char *p = NULL;
 
100
 
 
101
        if ((begin == NULL) || (end == NULL)) {
 
102
                rc = 1;
 
103
                goto exit;
 
104
        }
 
105
 
 
106
        /* Per RFC 4512:
 
107
         *
 
108
         *   numericoid = number 1*( DOT number )
 
109
         */
 
110
 
 
111
        /* one pass of this loop should process one element of the oid (number DOT) */
 
112
        for (p = begin; p <= end; p++) {
 
113
                if (IS_LDIGIT(*p)) {
 
114
                        /* loop until we get to a separator char */
 
115
                        while(*p != '.') {
 
116
                                p++;
 
117
                                if (p > end) {
 
118
                                        /* ensure we got at least 2 elements */
 
119
                                        if (!found_separator) {
 
120
                                                rc = 1;
 
121
                                                goto exit;
 
122
                                        } else {
 
123
                                                /* looks like a valid numericoid */
 
124
                                                goto exit;
 
125
                                        }
 
126
                                } else if (*p == '.') {
 
127
                                        /* we can not end with a '.' */
 
128
                                        if (p == end) {
 
129
                                                rc = 1;
 
130
                                                goto exit;
 
131
                                        } else {
 
132
                                                found_separator = 1;
 
133
                                        }
 
134
                                } else if (!isdigit(*p)) {
 
135
                                        rc = 1;
 
136
                                        goto exit;
 
137
                                }
 
138
                        }
 
139
                } else if (*p == '0') {
 
140
                        p++;
 
141
                        if (p > end) {
 
142
                                /* ensure we got at least 2 elements */
 
143
                                if (!found_separator) {
 
144
                                        rc = 1;
 
145
                                        goto exit;
 
146
                                } else {
 
147
                                        /* looks like a valid numericoid */
 
148
                                        goto exit;
 
149
                                }
 
150
                        } else if (*p != '.') {
 
151
                                /* a leading 0 is not allowed unless the entire element is simply 0 */
 
152
                                rc = 1;
 
153
                                goto exit;
 
154
                        }
 
155
 
 
156
                        /* At this point, *p is '.'.  We can not end with a '.' */
 
157
                        if (p == end) {
 
158
                                rc = 1;
 
159
                                goto exit;
 
160
                        } else {
 
161
                                found_separator = 1;
 
162
                        }
 
163
                } else {
 
164
                        rc = 1;
 
165
                        goto exit;
 
166
                }
 
167
        }
 
168
 
 
169
exit:
 
170
        return(rc);
 
171
}
 
172
 
 
173
/* Helper to validate a single UTF-8 character.
 
174
 * It is assumed that the first byte of the character
 
175
 * is pointed to by begin.  This function will not read
 
176
 * past the byte pointed to by the end parameter.  The
 
177
 * last pointer will be filled in the the address of
 
178
 * the last byte of the validated character if the
 
179
 * character is valid, or the last byte processed
 
180
 * in the invalid case.
 
181
 *
 
182
 * Returns 0 if it is valid and non-zero otherwise. */
 
183
int utf8char_validate(
 
184
        const char *begin,
 
185
        const char *end,
 
186
        const char **last
 
187
)
 
188
{
 
189
        int rc = 0; /* Assume char is valid */
 
190
        const char *p = begin;
 
191
 
 
192
        if ((begin == NULL) || (end == NULL)) {
 
193
                rc = 1;
 
194
                goto exit;
 
195
        }
 
196
 
 
197
        /* Per RFC 4512:
 
198
         *
 
199
         *   UTF8  = UTF1 / UTFMB
 
200
         *   UTFMB = UTF2 / UTF3 / UTF4
 
201
         *   UTF0  = %x80-BF
 
202
         *   UTF1  = %x00-7F
 
203
         *   UTF2  = %xC2-DF UTF0
 
204
         *   UTF3  = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
 
205
         *           %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
 
206
         *   UTF4  = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
 
207
         *           %xF4 %x80-8F 2(UTF0)
 
208
         */
 
209
 
 
210
        /* If we have a single byte (ASCII) character, we
 
211
         * don't really have any work to do. */
 
212
        if (IS_UTF1(*p)) {
 
213
                goto exit;
 
214
        } else if (IS_UTF2(*p)) {
 
215
                /* Ensure that there is another byte
 
216
                 * and that is is 'UTF0'. */
 
217
                if ((p == end) || !IS_UTF0(*(p + 1))) {
 
218
                        rc = 1;
 
219
                        goto exit;
 
220
                }
 
221
 
 
222
                /* Advance p so last is set correctly */
 
223
                p++;
 
224
        } else if (IS_UTF3(*p)) {
 
225
                /* Ensure that there are at least 2 more bytes. */
 
226
                if (end - p < 2) {
 
227
                        rc = 1;
 
228
                        goto exit;
 
229
                }
 
230
 
 
231
                /* The first byte determines what is legal for
 
232
                 * the second byte. */
 
233
                if (*p == '\xE0') {
 
234
                        /* The next byte must be %xA0-BF. */
 
235
                        p++;
 
236
                        if (((unsigned char)*p < (unsigned char)'\xA0') || ((unsigned char)*p > (unsigned char)'\xBF')) {
 
237
                                rc = 1;
 
238
                                goto exit;
 
239
                        }
 
240
                } else if (*p == '\xED') {
 
241
                        /* The next byte must be %x80-9F. */
 
242
                        p++;
 
243
                        if (((unsigned char)*p < (unsigned char)'\x80') || ((unsigned char)*p > (unsigned char)'\x9F')) {
 
244
                                rc = 1;
 
245
                                goto exit;
 
246
                        }
 
247
                } else {
 
248
                        /* The next byte must each be 'UTF0'. */
 
249
                        p++;
 
250
                        if (!IS_UTF0(*p)) {
 
251
                                rc = 1;
 
252
                                goto exit;
 
253
                        }
 
254
                }
 
255
 
 
256
                /* The last byte must be 'UTF0'. */
 
257
                p++;
 
258
                if (!IS_UTF0(*p)) {
 
259
                        rc = 1;
 
260
                        goto exit;
 
261
                }
 
262
        } else if (IS_UTF4(*p)) {
 
263
                /* Ensure that there are at least 3 more bytes. */
 
264
                if (end - p < 3) {
 
265
                        rc = 1;
 
266
                        goto exit;
 
267
                }
 
268
 
 
269
                /* The first byte determines what is legal for
 
270
                 * the second byte. */
 
271
                if (*p == '\xF0') {
 
272
                        /* The next byte must be %x90-BF. */
 
273
                        if (((unsigned char)*p < (unsigned char)'\x90') || ((unsigned char)*p > (unsigned char)'\xBF')) {
 
274
                                rc = 1;
 
275
                                goto exit;
 
276
                        }
 
277
                } else if (*p == '\xF4') {
 
278
                        /* The next byte must be %x80-BF. */
 
279
                        if (((unsigned char)*p < (unsigned char)'\x80') || ((unsigned char)*p > (unsigned char)'\xBF')) {
 
280
                                rc = 1;
 
281
                                goto exit;
 
282
                        }
 
283
                } else {
 
284
                        /* The next byte must each be 'UTF0'. */
 
285
                        p++;
 
286
                        if (!IS_UTF0(*p)) {
 
287
                                rc = 1;
 
288
                                goto exit;
 
289
                        }
 
290
                }
 
291
 
 
292
                /* The last 2 bytes must be 'UTF0'. */
 
293
                p++;
 
294
                if (!IS_UTF0(*p) || !IS_UTF0(*(p + 1))) {
 
295
                        rc = 1;
 
296
                        goto exit;
 
297
                }
 
298
 
 
299
                /* Advance the pointer so last is set correctly
 
300
                 * when we return. */
 
301
                p++;
 
302
        } else {
 
303
                /* We found an illegal first byte. */
 
304
                rc = 1;
 
305
                goto exit;
 
306
        }
 
307
 
 
308
exit:
 
309
        if (last) {
 
310
                *last = (const char *)p;
 
311
        }
 
312
        return(rc);
 
313
}
 
314
 
 
315
/* Validates that a non '\0' terminated string is UTF8.  This
 
316
 * function will not read past the byte pointed to by the end
 
317
 * parameter.  The last pointer will be filled in to point to
 
318
 * the address of the last byte of the last validated character
 
319
 * if the string is valid, or the last byte processed in the
 
320
 * invalid case.
 
321
 *
 
322
 * Returns 0 if it is valid and non-zero otherwise. */
 
323
int utf8string_validate(
 
324
        const char *begin,
 
325
        const char *end,
 
326
        const char **last
 
327
)
 
328
{
 
329
        int rc = 0; /* Assume string is valid */
 
330
        const char *p = NULL;
 
331
 
 
332
        if ((begin == NULL) || (end == NULL)) {
 
333
                rc = 1;
 
334
                goto exit;
 
335
        }
 
336
 
 
337
        for (p = begin; p <= end; p++) {
 
338
                if ((rc = utf8char_validate(p, end, &p)) != 0) {
 
339
                        goto exit;
 
340
                }
 
341
        }
 
342
 
 
343
        /* Adjust the pointer so last is set correctly for caller. */
 
344
        p--;
 
345
 
 
346
exit:
 
347
        if (last) {
 
348
                *last = p;
 
349
        }
 
350
        return(rc);
 
351
}
 
352
 
 
353
/*
 
354
 * Validates a distinguishedName as degined in RFC 4514.  Returns
 
355
 * 0 if the value from begin to end is a valid distinguishedName.
 
356
 * Returns 1 otherwise.
 
357
 */
 
358
int distinguishedname_validate(
 
359
        const char *begin,
 
360
        const char *end
 
361
)
 
362
{
 
363
        int rc = 0; /* Assume value is valid */
 
364
        const char *p = begin;
 
365
        const char *last = NULL;
 
366
 
 
367
        /* Per RFC 4514:
 
368
         *
 
369
         * distinguishedName = [ relativeDistinguishedName
 
370
         *     *( COMMA relativeDistinguishedName ) ]
 
371
         * relativeDistinguishedName = attributeTypeAndValue
 
372
         *     *( PLUS attributeTypeAndValue )
 
373
         * attributeTypeAndValue = attribyteType EQUALS attributeValue
 
374
         * attributeType = descr / numericoid
 
375
         * attributeValue = string / hexstring
 
376
         */
 
377
 
 
378
        /* Validate one RDN at a time in a loop. */
 
379
        while (p <= end) {
 
380
                if ((rc = rdn_validate(p, end, &last)) != 0) {
 
381
                        goto exit;
 
382
                }
 
383
                p = last + 1;
 
384
 
 
385
                /* p should be pointing at a comma, or one past
 
386
                 * the end of the entire dn value.  If we have
 
387
                 * not reached the end, ensure that the next
 
388
                 * character is a comma and that there is at
 
389
                 * least another character after the comma. */
 
390
                if ((p <= end) && ((p == end) || (*p != ','))) {
 
391
                        rc = 1;
 
392
                        goto exit;
 
393
                }
 
394
 
 
395
                /* Advance the pointer past the comma so it
 
396
                 * points at the beginning of the next RDN
 
397
                 * (if there is one). */
 
398
                p++;
 
399
        }
 
400
 
 
401
exit:
 
402
        return rc;
 
403
}
 
404
 
 
405
/*
 
406
 * Helper function for validating a DN.  This function will validate
 
407
 * a single RDN.  If the RDN is valid, 0 will be returned, otherwise
 
408
 * non-zero will be returned. A pointer to the last character processed
 
409
 * will be set in the "last parameter.  This will be the end of the RDN
 
410
 * in the valid case, and the illegal character in the invalid case.
 
411
 */
 
412
int rdn_validate( const char *begin, const char *end, const char **last )
 
413
{
 
414
        int rc = 0; /* Assume RDN is valid */
 
415
        int numericform = 0;
 
416
        char *separator = NULL;
 
417
        const char *p = begin;
 
418
 
 
419
        /* Find the '=', then use the helpers for descr and numericoid */
 
420
        if ((separator = PL_strnchr(p, '=', end - begin + 1)) == NULL) {
 
421
                rc = 1;
 
422
                goto exit;
 
423
        }
 
424
 
 
425
        /* Process an attribute type. The 'descr'
 
426
         * form must start with a 'leadkeychar'. */
 
427
        if (IS_LEADKEYCHAR(*p)) {
 
428
                if ((rc = keystring_validate(p, separator - 1))) {
 
429
                        goto exit;
 
430
                }
 
431
        /* See if the 'numericoid' form is being used */
 
432
        } else if (isdigit(*p)) {
 
433
                numericform = 1;
 
434
                if ((rc = numericoid_validate(p, separator - 1))) {
 
435
                        goto exit;
 
436
                }
 
437
        } else {
 
438
                rc = 1;
 
439
                goto exit;
 
440
        }
 
441
 
 
442
        /* Advance the pointer past the '=' and make sure
 
443
         * we're not past the end of the string. */
 
444
        p = separator + 1;
 
445
        if (p > end) {
 
446
                rc = 1;
 
447
                goto exit;
 
448
        }
 
449
 
 
450
        /* The value must be a 'hexstring' if the 'numericoid'
 
451
         * form of 'attributeType' is used.  Per RFC 4514:
 
452
         *
 
453
         *   hexstring = SHARP 1*hexpair
 
454
         *   hexpair = HEX HEX
 
455
         */
 
456
        if (numericform) {
 
457
                if ((p == end) || !IS_SHARP(*p)) {
 
458
                        rc = 1;
 
459
                        goto exit;
 
460
                }
 
461
                p++;
 
462
        /* The value must be a 'string' when the 'descr' form
 
463
         * of 'attributeType' is used.  Per RFC 4514:
 
464
         *
 
465
         *   string = [ ( leadchar / pair ) [ *( stringchar / pair )
 
466
         *      ( trailchar / pair ) ] ]
 
467
         *
 
468
         *   leadchar   = LUTF1 / UTFMB
 
469
         *   trailchar  = TUTF1 / UTFMB
 
470
         *   stringchar = SUTF1 / UTFMB
 
471
         *
 
472
         *   pair = ESC (ESC / special / hexpair )
 
473
         *   special = escaped / SPACE / SHARP / EQUALS
 
474
         *   escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
 
475
         *   hexpair = HEX HEX
 
476
         */
 
477
        } else {
 
478
                /* Check the leadchar to see if anything illegal
 
479
                 * is there.  We need to allow a 'pair' to get
 
480
                 * through, so we'll assume that a '\' is the
 
481
                 * start of a 'pair' for now. */
 
482
                if (IS_UTF1(*p) && !IS_ESC(*p) && !IS_LUTF1(*p)) {
 
483
                        rc = 1;
 
484
                        goto exit;
 
485
                }
 
486
        }
 
487
 
 
488
        /* Loop through string until we find the ',' separator, a '+'
 
489
         * char indicating a multi-value RDN, or we reach the end.  */
 
490
        while ((p <= end) && (*p != ',') && (*p != '+')) {
 
491
                if (numericform) {
 
492
                        /* Process a single 'hexpair' */
 
493
                        if ((p == end) || !isxdigit(*p) || !isxdigit(*p + 1)) {
 
494
                                rc = 1;
 
495
                                goto exit;
 
496
                        }
 
497
                        p = p + 2;
 
498
                } else {
 
499
                        /* Check for a valid 'stringchar'.  We handle
 
500
                         * multi-byte characters separately. */
 
501
                        if (IS_UTF1(*p)) {
 
502
                                /* If we're at the end, check if we have
 
503
                                 * a valid 'trailchar'. */
 
504
                                if ((p == end) && !IS_TUTF1(*p)) {
 
505
                                        rc = 1;
 
506
                                        goto exit;
 
507
                                /* Check for a 'pair'. */
 
508
                                } else if (IS_ESC(*p)) {
 
509
                                        /* We're guaranteed to still have at
 
510
                                         * least one more character, so lets
 
511
                                         * take a look at it. */
 
512
                                        p++;
 
513
                                        if (!IS_ESC(*p) && !IS_SPECIAL(*p)) {
 
514
                                                /* The only thing valid now
 
515
                                                 * is a 'hexpair'. */
 
516
                                                if ((p == end) || !isxdigit(*p) ||!isxdigit(*p + 1)) {
 
517
                                                        rc = 1;
 
518
                                                        goto exit;
 
519
                                                }
 
520
                                                p++;
 
521
                                        }
 
522
                                /* Only allow 'SUTF1' chars now. */
 
523
                                } else if (!IS_SUTF1(*p)) {
 
524
                                        rc = 1;
 
525
                                        goto exit;
 
526
                                }
 
527
 
 
528
                                p++;
 
529
                        } else {
 
530
                                /* Validate a single 'UTFMB' (multi-byte) character. */
 
531
                                if (utf8char_validate(p, end, &p ) != 0) {
 
532
                                        rc = 1;
 
533
                                        goto exit;
 
534
                                }
 
535
 
 
536
                                /* Advance the pointer past the multi-byte char. */
 
537
                                p++;
 
538
                        }
 
539
                }
 
540
        }
 
541
 
 
542
        /* We'll end up either at the comma, a '+', or one past end.
 
543
         * If we are processing a multi-valued RDN, we recurse to
 
544
         * process the next 'attributeTypeAndValue'. */
 
545
        if ((p <= end) && (*p == '+')) {
 
546
                /* Make sure that there is something after the '+'. */
 
547
                if (p == end) {
 
548
                        rc = 1;
 
549
                        goto exit;
 
550
                }
 
551
                p++;
 
552
 
 
553
                /* Recurse to process the next value.  We need to reset p to
 
554
                 * ensure that last is set correctly for the original caller. */
 
555
                rc = rdn_validate( p, end, last );
 
556
                p = *last + 1;
 
557
        }
 
558
 
 
559
exit:
 
560
        *last = p - 1;
 
561
        return rc;
 
562
}
 
563
 
 
564
int
 
565
bitstring_validate_internal(const char *begin, const char *end)
 
566
{
 
567
        int     rc = 0;    /* assume the value is valid */
 
568
        const char *p = NULL;
 
569
 
 
570
        /* Per RFC4517:
 
571
         *
 
572
         * BitString    = SQUOTE *binary-digit SQUOTE "B"
 
573
         * binary-digit = "0" / "1"
 
574
         */
 
575
 
 
576
        /* Check that the value starts with a SQUOTE and
 
577
         * ends with SQUOTE "B". */
 
578
        if (!IS_SQUOTE(*begin) || (*end != 'B') ||
 
579
            !IS_SQUOTE(*(end - 1))) {
 
580
                rc = 1;
 
581
                goto exit;
 
582
        }
 
583
 
 
584
        /* Ensure that only '0' and '1' are between the SQUOTE chars. */
 
585
        for (p = begin + 1; p <= end - 2; p++) {
 
586
                if ((*p != '0') && (*p != '1')) {
 
587
                        rc = 1;
 
588
                        goto exit;
 
589
                }
 
590
        }
 
591
 
 
592
exit:
 
593
        return rc;
 
594
}