~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to libraries/libldap/schema.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $OpenLDAP: pkg/ldap/libraries/libldap/schema.c,v 1.77.2.4 2008/04/14 22:32:48 quanah Exp $ */
 
2
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
3
 *
 
4
 * Copyright 1998-2008 The OpenLDAP Foundation.
 
5
 * All rights reserved.
 
6
 *
 
7
 * Redistribution and use in source and binary forms, with or without
 
8
 * modification, are permitted only as authorized by the OpenLDAP
 
9
 * Public License.
 
10
 *
 
11
 * A copy of this license is available in the file LICENSE in the
 
12
 * top-level directory of the distribution or, alternatively, at
 
13
 * <http://www.OpenLDAP.org/license.html>.
 
14
 */
 
15
 
 
16
/*
 
17
 * schema.c:  parsing routines used by servers and clients to process
 
18
 *      schema definitions
 
19
 */
 
20
 
 
21
#include "portable.h"
 
22
 
 
23
#include <stdio.h>
 
24
#include <ac/stdlib.h>
 
25
 
 
26
#include <ac/string.h>
 
27
#include <ac/time.h>
 
28
 
 
29
#include "ldap-int.h"
 
30
 
 
31
#include <ldap_schema.h>
 
32
 
 
33
static const char EndOfInput[] = "end of input";
 
34
 
 
35
static const char *
 
36
choose_name( char *names[], const char *fallback )
 
37
{
 
38
        return (names != NULL && names[0] != NULL) ? names[0] : fallback;
 
39
}
 
40
 
 
41
LDAP_CONST char *
 
42
ldap_syntax2name( LDAPSyntax * syn )
 
43
{
 
44
        return( syn->syn_oid );
 
45
}
 
46
 
 
47
LDAP_CONST char *
 
48
ldap_matchingrule2name( LDAPMatchingRule * mr )
 
49
{
 
50
        return( choose_name( mr->mr_names, mr->mr_oid ) );
 
51
}
 
52
 
 
53
LDAP_CONST char *
 
54
ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
 
55
{
 
56
        return( choose_name( mru->mru_names, mru->mru_oid ) );
 
57
}
 
58
 
 
59
LDAP_CONST char *
 
60
ldap_attributetype2name( LDAPAttributeType * at )
 
61
{
 
62
        return( choose_name( at->at_names, at->at_oid ) );
 
63
}
 
64
 
 
65
LDAP_CONST char *
 
66
ldap_objectclass2name( LDAPObjectClass * oc )
 
67
{
 
68
        return( choose_name( oc->oc_names, oc->oc_oid ) );
 
69
}
 
70
 
 
71
LDAP_CONST char *
 
72
ldap_contentrule2name( LDAPContentRule * cr )
 
73
{
 
74
        return( choose_name( cr->cr_names, cr->cr_oid ) );
 
75
}
 
76
 
 
77
LDAP_CONST char *
 
78
ldap_nameform2name( LDAPNameForm * nf )
 
79
{
 
80
        return( choose_name( nf->nf_names, nf->nf_oid ) );
 
81
}
 
82
 
 
83
LDAP_CONST char *
 
84
ldap_structurerule2name( LDAPStructureRule * sr )
 
85
{
 
86
        return( choose_name( sr->sr_names, NULL ) );
 
87
}
 
88
 
 
89
/*
 
90
 * When pretty printing the entities we will be appending to a buffer.
 
91
 * Since checking for overflow, realloc'ing and checking if no error
 
92
 * is extremely boring, we will use a protection layer that will let
 
93
 * us blissfully ignore the error until the end.  This layer is
 
94
 * implemented with the help of the next type.
 
95
 */
 
96
 
 
97
typedef struct safe_string {
 
98
        char * val;
 
99
        ber_len_t size;
 
100
        ber_len_t pos;
 
101
        int at_whsp;
 
102
} safe_string;
 
103
 
 
104
static safe_string *
 
105
new_safe_string(int size)
 
106
{
 
107
        safe_string * ss;
 
108
        
 
109
        ss = LDAP_MALLOC(sizeof(safe_string));
 
110
        if ( !ss )
 
111
                return(NULL);
 
112
 
 
113
        ss->val = LDAP_MALLOC(size);
 
114
        if ( !ss->val ) {
 
115
                LDAP_FREE(ss);
 
116
                return(NULL);
 
117
        }
 
118
 
 
119
        ss->size = size;
 
120
        ss->pos = 0;
 
121
        ss->at_whsp = 0;
 
122
 
 
123
        return ss;
 
124
}
 
125
 
 
126
static void
 
127
safe_string_free(safe_string * ss)
 
128
{
 
129
        if ( !ss )
 
130
                return;
 
131
        LDAP_FREE(ss->val);
 
132
        LDAP_FREE(ss);
 
133
}
 
134
 
 
135
#if 0   /* unused */
 
136
static char *
 
137
safe_string_val(safe_string * ss)
 
138
{
 
139
        ss->val[ss->pos] = '\0';
 
140
        return(ss->val);
 
141
}
 
142
#endif
 
143
 
 
144
static char *
 
145
safe_strdup(safe_string * ss)
 
146
{
 
147
        char *ret = LDAP_MALLOC(ss->pos+1);
 
148
        if (!ret)
 
149
                return NULL;
 
150
        AC_MEMCPY(ret, ss->val, ss->pos);
 
151
        ret[ss->pos] = '\0';
 
152
        return ret;
 
153
}
 
154
 
 
155
static int
 
156
append_to_safe_string(safe_string * ss, char * s)
 
157
{
 
158
        int l = strlen(s);
 
159
        char * temp;
 
160
 
 
161
        /*
 
162
         * Some runaway process is trying to append to a string that
 
163
         * overflowed and we could not extend.
 
164
         */
 
165
        if ( !ss->val )
 
166
                return -1;
 
167
 
 
168
        /* We always make sure there is at least one position available */
 
169
        if ( ss->pos + l >= ss->size-1 ) {
 
170
                ss->size *= 2;
 
171
                if ( ss->pos + l >= ss->size-1 ) {
 
172
                        ss->size = ss->pos + l + 1;
 
173
                }
 
174
 
 
175
                temp = LDAP_REALLOC(ss->val, ss->size);
 
176
                if ( !temp ) {
 
177
                        /* Trouble, out of memory */
 
178
                        LDAP_FREE(ss->val);
 
179
                        return -1;
 
180
                }
 
181
                ss->val = temp;
 
182
        }
 
183
        strncpy(&ss->val[ss->pos], s, l);
 
184
        ss->pos += l;
 
185
        if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
 
186
                ss->at_whsp = 1;
 
187
        else
 
188
                ss->at_whsp = 0;
 
189
 
 
190
        return 0;
 
191
}
 
192
 
 
193
static int
 
194
print_literal(safe_string *ss, char *s)
 
195
{
 
196
        return(append_to_safe_string(ss,s));
 
197
}
 
198
 
 
199
static int
 
200
print_whsp(safe_string *ss)
 
201
{
 
202
        if ( ss->at_whsp )
 
203
                return(append_to_safe_string(ss,""));
 
204
        else
 
205
                return(append_to_safe_string(ss," "));
 
206
}
 
207
 
 
208
static int
 
209
print_numericoid(safe_string *ss, char *s)
 
210
{
 
211
        if ( s )
 
212
                return(append_to_safe_string(ss,s));
 
213
        else
 
214
                return(append_to_safe_string(ss,""));
 
215
}
 
216
 
 
217
/* This one is identical to print_qdescr */
 
218
static int
 
219
print_qdstring(safe_string *ss, char *s)
 
220
{
 
221
        print_whsp(ss);
 
222
        print_literal(ss,"'");
 
223
        append_to_safe_string(ss,s);
 
224
        print_literal(ss,"'");
 
225
        return(print_whsp(ss));
 
226
}
 
227
 
 
228
static int
 
229
print_qdescr(safe_string *ss, char *s)
 
230
{
 
231
        print_whsp(ss);
 
232
        print_literal(ss,"'");
 
233
        append_to_safe_string(ss,s);
 
234
        print_literal(ss,"'");
 
235
        return(print_whsp(ss));
 
236
}
 
237
 
 
238
static int
 
239
print_qdescrlist(safe_string *ss, char **sa)
 
240
{
 
241
        char **sp;
 
242
        int ret = 0;
 
243
        
 
244
        for (sp=sa; *sp; sp++) {
 
245
                ret = print_qdescr(ss,*sp);
 
246
        }
 
247
        /* If the list was empty, we return zero that is potentially
 
248
         * incorrect, but since we will be still appending things, the
 
249
         * overflow will be detected later.  Maybe FIX.
 
250
         */
 
251
        return(ret);
 
252
}
 
253
 
 
254
static int
 
255
print_qdescrs(safe_string *ss, char **sa)
 
256
{
 
257
        /* The only way to represent an empty list is as a qdescrlist
 
258
         * so, if the list is empty we treat it as a long list.
 
259
         * Really, this is what the syntax mandates.  We should not
 
260
         * be here if the list was empty, but if it happens, a label
 
261
         * has already been output and we cannot undo it.
 
262
         */
 
263
        if ( !sa[0] || ( sa[0] && sa[1] ) ) {
 
264
                print_whsp(ss);
 
265
                print_literal(ss,"("/*)*/);
 
266
                print_qdescrlist(ss,sa);
 
267
                print_literal(ss,/*(*/")");
 
268
                return(print_whsp(ss));
 
269
        } else {
 
270
          return(print_qdescr(ss,*sa));
 
271
        }
 
272
}
 
273
 
 
274
static int
 
275
print_woid(safe_string *ss, char *s)
 
276
{
 
277
        print_whsp(ss);
 
278
        append_to_safe_string(ss,s);
 
279
        return print_whsp(ss);
 
280
}
 
281
 
 
282
static int
 
283
print_oidlist(safe_string *ss, char **sa)
 
284
{
 
285
        char **sp;
 
286
 
 
287
        for (sp=sa; *(sp+1); sp++) {
 
288
                print_woid(ss,*sp);
 
289
                print_literal(ss,"$");
 
290
        }
 
291
        return(print_woid(ss,*sp));
 
292
}
 
293
 
 
294
static int
 
295
print_oids(safe_string *ss, char **sa)
 
296
{
 
297
        if ( sa[0] && sa[1] ) {
 
298
                print_literal(ss,"("/*)*/);
 
299
                print_oidlist(ss,sa);
 
300
                print_whsp(ss);
 
301
                return(print_literal(ss,/*(*/")"));
 
302
        } else {
 
303
                return(print_woid(ss,*sa));
 
304
        }
 
305
}
 
306
 
 
307
static int
 
308
print_noidlen(safe_string *ss, char *s, int l)
 
309
{
 
310
        char buf[64];
 
311
        int ret;
 
312
 
 
313
        ret = print_numericoid(ss,s);
 
314
        if ( l ) {
 
315
                snprintf(buf, sizeof buf, "{%d}",l);
 
316
                ret = print_literal(ss,buf);
 
317
        }
 
318
        return(ret);
 
319
}
 
320
 
 
321
static int
 
322
print_ruleid(safe_string *ss, int rid)
 
323
{
 
324
        char buf[64];
 
325
        snprintf(buf, sizeof buf, "%d", rid);
 
326
        return print_literal(ss,buf);
 
327
}
 
328
 
 
329
static int
 
330
print_ruleids(safe_string *ss, int n, int *rids)
 
331
{
 
332
        int i;
 
333
 
 
334
        if( n == 1 ) {
 
335
                print_ruleid(ss,rids[0]);
 
336
                return print_whsp(ss);
 
337
        } else {
 
338
                print_literal(ss,"("/*)*/);
 
339
                for( i=0; i<n; i++ ) {
 
340
                        print_whsp(ss);
 
341
                        print_ruleid(ss,rids[i]);
 
342
                }
 
343
                print_whsp(ss);
 
344
                return print_literal(ss,/*(*/")");
 
345
        }
 
346
}
 
347
 
 
348
 
 
349
static int
 
350
print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
 
351
{
 
352
        LDAPSchemaExtensionItem **ext;
 
353
 
 
354
        if ( extensions ) {
 
355
                print_whsp(ss);
 
356
                for ( ext = extensions; *ext != NULL; ext++ ) {
 
357
                        print_literal(ss, (*ext)->lsei_name);
 
358
                        print_whsp(ss);
 
359
                        /* Should be print_qdstrings */
 
360
                        print_qdescrs(ss, (*ext)->lsei_values);
 
361
                        print_whsp(ss);
 
362
                }
 
363
        }
 
364
 
 
365
        return 0;
 
366
}
 
367
 
 
368
char *
 
369
ldap_syntax2str( LDAPSyntax * syn )
 
370
{
 
371
        struct berval bv;
 
372
        if (ldap_syntax2bv( syn, &bv ))
 
373
                return(bv.bv_val);
 
374
        else
 
375
                return NULL;
 
376
}
 
377
 
 
378
struct berval *
 
379
ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
 
380
{
 
381
        safe_string * ss;
 
382
        
 
383
        ss = new_safe_string(256);
 
384
        if ( !ss )
 
385
                return NULL;
 
386
 
 
387
        print_literal(ss,"("/*)*/);
 
388
        print_whsp(ss);
 
389
 
 
390
        print_numericoid(ss, syn->syn_oid);
 
391
        print_whsp(ss);
 
392
 
 
393
        if ( syn->syn_desc ) {
 
394
                print_literal(ss,"DESC");
 
395
                print_qdstring(ss,syn->syn_desc);
 
396
        }
 
397
 
 
398
        print_whsp(ss);
 
399
 
 
400
        print_extensions(ss, syn->syn_extensions);
 
401
 
 
402
        print_literal(ss,/*(*/ ")");
 
403
 
 
404
        bv->bv_val = safe_strdup(ss);
 
405
        bv->bv_len = ss->pos;
 
406
        safe_string_free(ss);
 
407
        return(bv);
 
408
}
 
409
 
 
410
char *
 
411
ldap_matchingrule2str( LDAPMatchingRule * mr )
 
412
{
 
413
        struct berval bv;
 
414
        if (ldap_matchingrule2bv( mr, &bv ))
 
415
                return(bv.bv_val);
 
416
        else
 
417
                return NULL;
 
418
}
 
419
 
 
420
struct berval *
 
421
ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
 
422
{
 
423
        safe_string * ss;
 
424
        
 
425
        ss = new_safe_string(256);
 
426
        if ( !ss )
 
427
                return NULL;
 
428
 
 
429
        print_literal(ss,"(" /*)*/);
 
430
        print_whsp(ss);
 
431
 
 
432
        print_numericoid(ss, mr->mr_oid);
 
433
        print_whsp(ss);
 
434
 
 
435
        if ( mr->mr_names ) {
 
436
                print_literal(ss,"NAME");
 
437
                print_qdescrs(ss,mr->mr_names);
 
438
        }
 
439
 
 
440
        if ( mr->mr_desc ) {
 
441
                print_literal(ss,"DESC");
 
442
                print_qdstring(ss,mr->mr_desc);
 
443
        }
 
444
 
 
445
        if ( mr->mr_obsolete ) {
 
446
                print_literal(ss, "OBSOLETE");
 
447
                print_whsp(ss);
 
448
        }
 
449
 
 
450
        if ( mr->mr_syntax_oid ) {
 
451
                print_literal(ss,"SYNTAX");
 
452
                print_whsp(ss);
 
453
                print_literal(ss, mr->mr_syntax_oid);
 
454
                print_whsp(ss);
 
455
        }
 
456
 
 
457
        print_whsp(ss);
 
458
 
 
459
        print_extensions(ss, mr->mr_extensions);
 
460
 
 
461
        print_literal(ss,/*(*/")");
 
462
 
 
463
        bv->bv_val = safe_strdup(ss);
 
464
        bv->bv_len = ss->pos;
 
465
        safe_string_free(ss);
 
466
        return(bv);
 
467
}
 
468
 
 
469
char *
 
470
ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
 
471
{
 
472
        struct berval bv;
 
473
        if (ldap_matchingruleuse2bv( mru, &bv ))
 
474
                return(bv.bv_val);
 
475
        else
 
476
                return NULL;
 
477
}
 
478
 
 
479
struct berval *
 
480
ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
 
481
{
 
482
        safe_string * ss;
 
483
        
 
484
        ss = new_safe_string(256);
 
485
        if ( !ss )
 
486
                return NULL;
 
487
 
 
488
        print_literal(ss,"(" /*)*/);
 
489
        print_whsp(ss);
 
490
 
 
491
        print_numericoid(ss, mru->mru_oid);
 
492
        print_whsp(ss);
 
493
 
 
494
        if ( mru->mru_names ) {
 
495
                print_literal(ss,"NAME");
 
496
                print_qdescrs(ss,mru->mru_names);
 
497
        }
 
498
 
 
499
        if ( mru->mru_desc ) {
 
500
                print_literal(ss,"DESC");
 
501
                print_qdstring(ss,mru->mru_desc);
 
502
        }
 
503
 
 
504
        if ( mru->mru_obsolete ) {
 
505
                print_literal(ss, "OBSOLETE");
 
506
                print_whsp(ss);
 
507
        }
 
508
 
 
509
        if ( mru->mru_applies_oids ) {
 
510
                print_literal(ss,"APPLIES");
 
511
                print_whsp(ss);
 
512
                print_oids(ss, mru->mru_applies_oids);
 
513
                print_whsp(ss);
 
514
        }
 
515
 
 
516
        print_whsp(ss);
 
517
 
 
518
        print_extensions(ss, mru->mru_extensions);
 
519
 
 
520
        print_literal(ss,/*(*/")");
 
521
 
 
522
        bv->bv_val = safe_strdup(ss);
 
523
        bv->bv_len = ss->pos;
 
524
        safe_string_free(ss);
 
525
        return(bv);
 
526
}
 
527
 
 
528
char *
 
529
ldap_objectclass2str( LDAPObjectClass * oc )
 
530
{
 
531
        struct berval bv;
 
532
        if (ldap_objectclass2bv( oc, &bv ))
 
533
                return(bv.bv_val);
 
534
        else
 
535
                return NULL;
 
536
}
 
537
 
 
538
struct berval *
 
539
ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
 
540
{
 
541
        safe_string * ss;
 
542
        
 
543
        ss = new_safe_string(256);
 
544
        if ( !ss )
 
545
                return NULL;
 
546
 
 
547
        print_literal(ss,"("/*)*/);
 
548
        print_whsp(ss);
 
549
 
 
550
        print_numericoid(ss, oc->oc_oid);
 
551
        print_whsp(ss);
 
552
 
 
553
        if ( oc->oc_names ) {
 
554
                print_literal(ss,"NAME");
 
555
                print_qdescrs(ss,oc->oc_names);
 
556
        }
 
557
 
 
558
        if ( oc->oc_desc ) {
 
559
                print_literal(ss,"DESC");
 
560
                print_qdstring(ss,oc->oc_desc);
 
561
        }
 
562
 
 
563
        if ( oc->oc_obsolete ) {
 
564
                print_literal(ss, "OBSOLETE");
 
565
                print_whsp(ss);
 
566
        }
 
567
 
 
568
        if ( oc->oc_sup_oids ) {
 
569
                print_literal(ss,"SUP");
 
570
                print_whsp(ss);
 
571
                print_oids(ss,oc->oc_sup_oids);
 
572
                print_whsp(ss);
 
573
        }
 
574
 
 
575
        switch (oc->oc_kind) {
 
576
        case LDAP_SCHEMA_ABSTRACT:
 
577
                print_literal(ss,"ABSTRACT");
 
578
                break;
 
579
        case LDAP_SCHEMA_STRUCTURAL:
 
580
                print_literal(ss,"STRUCTURAL");
 
581
                break;
 
582
        case LDAP_SCHEMA_AUXILIARY:
 
583
                print_literal(ss,"AUXILIARY");
 
584
                break;
 
585
        default:
 
586
                print_literal(ss,"KIND-UNKNOWN");
 
587
                break;
 
588
        }
 
589
        print_whsp(ss);
 
590
        
 
591
        if ( oc->oc_at_oids_must ) {
 
592
                print_literal(ss,"MUST");
 
593
                print_whsp(ss);
 
594
                print_oids(ss,oc->oc_at_oids_must);
 
595
                print_whsp(ss);
 
596
        }
 
597
 
 
598
        if ( oc->oc_at_oids_may ) {
 
599
                print_literal(ss,"MAY");
 
600
                print_whsp(ss);
 
601
                print_oids(ss,oc->oc_at_oids_may);
 
602
                print_whsp(ss);
 
603
        }
 
604
 
 
605
        print_whsp(ss);
 
606
 
 
607
        print_extensions(ss, oc->oc_extensions);
 
608
 
 
609
        print_literal(ss, /*(*/")");
 
610
 
 
611
        bv->bv_val = safe_strdup(ss);
 
612
        bv->bv_len = ss->pos;
 
613
        safe_string_free(ss);
 
614
        return(bv);
 
615
}
 
616
 
 
617
char *
 
618
ldap_contentrule2str( LDAPContentRule * cr )
 
619
{
 
620
        struct berval bv;
 
621
        if (ldap_contentrule2bv( cr, &bv ))
 
622
                return(bv.bv_val);
 
623
        else
 
624
                return NULL;
 
625
}
 
626
 
 
627
struct berval *
 
628
ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv )
 
629
{
 
630
        safe_string * ss;
 
631
        
 
632
        ss = new_safe_string(256);
 
633
        if ( !ss )
 
634
                return NULL;
 
635
 
 
636
        print_literal(ss,"("/*)*/);
 
637
        print_whsp(ss);
 
638
 
 
639
        print_numericoid(ss, cr->cr_oid);
 
640
        print_whsp(ss);
 
641
 
 
642
        if ( cr->cr_names ) {
 
643
                print_literal(ss,"NAME");
 
644
                print_qdescrs(ss,cr->cr_names);
 
645
        }
 
646
 
 
647
        if ( cr->cr_desc ) {
 
648
                print_literal(ss,"DESC");
 
649
                print_qdstring(ss,cr->cr_desc);
 
650
        }
 
651
 
 
652
        if ( cr->cr_obsolete ) {
 
653
                print_literal(ss, "OBSOLETE");
 
654
                print_whsp(ss);
 
655
        }
 
656
 
 
657
        if ( cr->cr_oc_oids_aux ) {
 
658
                print_literal(ss,"AUX");
 
659
                print_whsp(ss);
 
660
                print_oids(ss,cr->cr_oc_oids_aux);
 
661
                print_whsp(ss);
 
662
        }
 
663
 
 
664
        if ( cr->cr_at_oids_must ) {
 
665
                print_literal(ss,"MUST");
 
666
                print_whsp(ss);
 
667
                print_oids(ss,cr->cr_at_oids_must);
 
668
                print_whsp(ss);
 
669
        }
 
670
 
 
671
        if ( cr->cr_at_oids_may ) {
 
672
                print_literal(ss,"MAY");
 
673
                print_whsp(ss);
 
674
                print_oids(ss,cr->cr_at_oids_may);
 
675
                print_whsp(ss);
 
676
        }
 
677
 
 
678
        if ( cr->cr_at_oids_not ) {
 
679
                print_literal(ss,"NOT");
 
680
                print_whsp(ss);
 
681
                print_oids(ss,cr->cr_at_oids_not);
 
682
                print_whsp(ss);
 
683
        }
 
684
 
 
685
        print_whsp(ss);
 
686
        print_extensions(ss, cr->cr_extensions);
 
687
 
 
688
        print_literal(ss, /*(*/")");
 
689
 
 
690
        bv->bv_val = safe_strdup(ss);
 
691
        bv->bv_len = ss->pos;
 
692
        safe_string_free(ss);
 
693
        return(bv);
 
694
}
 
695
 
 
696
char *
 
697
ldap_structurerule2str( LDAPStructureRule * sr )
 
698
{
 
699
        struct berval bv;
 
700
        if (ldap_structurerule2bv( sr, &bv ))
 
701
                return(bv.bv_val);
 
702
        else
 
703
                return NULL;
 
704
}
 
705
 
 
706
struct berval *
 
707
ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv )
 
708
{
 
709
        safe_string * ss;
 
710
        
 
711
        ss = new_safe_string(256);
 
712
        if ( !ss )
 
713
                return NULL;
 
714
 
 
715
        print_literal(ss,"("/*)*/);
 
716
        print_whsp(ss);
 
717
 
 
718
        print_ruleid(ss, sr->sr_ruleid);
 
719
        print_whsp(ss);
 
720
 
 
721
        if ( sr->sr_names ) {
 
722
                print_literal(ss,"NAME");
 
723
                print_qdescrs(ss,sr->sr_names);
 
724
        }
 
725
 
 
726
        if ( sr->sr_desc ) {
 
727
                print_literal(ss,"DESC");
 
728
                print_qdstring(ss,sr->sr_desc);
 
729
        }
 
730
 
 
731
        if ( sr->sr_obsolete ) {
 
732
                print_literal(ss, "OBSOLETE");
 
733
                print_whsp(ss);
 
734
        }
 
735
 
 
736
        print_literal(ss,"FORM");
 
737
        print_whsp(ss);
 
738
        print_woid(ss,sr->sr_nameform);
 
739
        print_whsp(ss);
 
740
 
 
741
        if ( sr->sr_nsup_ruleids ) {
 
742
                print_literal(ss,"SUP");
 
743
                print_whsp(ss);
 
744
                print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids);
 
745
                print_whsp(ss);
 
746
        }
 
747
 
 
748
        print_whsp(ss);
 
749
        print_extensions(ss, sr->sr_extensions);
 
750
 
 
751
        print_literal(ss, /*(*/")");
 
752
 
 
753
        bv->bv_val = safe_strdup(ss);
 
754
        bv->bv_len = ss->pos;
 
755
        safe_string_free(ss);
 
756
        return(bv);
 
757
}
 
758
 
 
759
 
 
760
char *
 
761
ldap_nameform2str( LDAPNameForm * nf )
 
762
{
 
763
        struct berval bv;
 
764
        if (ldap_nameform2bv( nf, &bv ))
 
765
                return(bv.bv_val);
 
766
        else
 
767
                return NULL;
 
768
}
 
769
 
 
770
struct berval *
 
771
ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv )
 
772
{
 
773
        safe_string * ss;
 
774
        
 
775
        ss = new_safe_string(256);
 
776
        if ( !ss )
 
777
                return NULL;
 
778
 
 
779
        print_literal(ss,"("/*)*/);
 
780
        print_whsp(ss);
 
781
 
 
782
        print_numericoid(ss, nf->nf_oid);
 
783
        print_whsp(ss);
 
784
 
 
785
        if ( nf->nf_names ) {
 
786
                print_literal(ss,"NAME");
 
787
                print_qdescrs(ss,nf->nf_names);
 
788
        }
 
789
 
 
790
        if ( nf->nf_desc ) {
 
791
                print_literal(ss,"DESC");
 
792
                print_qdstring(ss,nf->nf_desc);
 
793
        }
 
794
 
 
795
        if ( nf->nf_obsolete ) {
 
796
                print_literal(ss, "OBSOLETE");
 
797
                print_whsp(ss);
 
798
        }
 
799
 
 
800
        print_literal(ss,"OC");
 
801
        print_whsp(ss);
 
802
        print_woid(ss,nf->nf_objectclass);
 
803
        print_whsp(ss);
 
804
 
 
805
        print_literal(ss,"MUST");
 
806
        print_whsp(ss);
 
807
        print_oids(ss,nf->nf_at_oids_must);
 
808
        print_whsp(ss);
 
809
 
 
810
 
 
811
        if ( nf->nf_at_oids_may ) {
 
812
                print_literal(ss,"MAY");
 
813
                print_whsp(ss);
 
814
                print_oids(ss,nf->nf_at_oids_may);
 
815
                print_whsp(ss);
 
816
        }
 
817
 
 
818
        print_whsp(ss);
 
819
        print_extensions(ss, nf->nf_extensions);
 
820
 
 
821
        print_literal(ss, /*(*/")");
 
822
 
 
823
        bv->bv_val = safe_strdup(ss);
 
824
        bv->bv_len = ss->pos;
 
825
        safe_string_free(ss);
 
826
        return(bv);
 
827
}
 
828
 
 
829
char *
 
830
ldap_attributetype2str( LDAPAttributeType * at )
 
831
{
 
832
        struct berval bv;
 
833
        if (ldap_attributetype2bv( at, &bv ))
 
834
                return(bv.bv_val);
 
835
        else
 
836
                return NULL;
 
837
}
 
838
 
 
839
struct berval *
 
840
ldap_attributetype2bv(  LDAPAttributeType * at, struct berval *bv )
 
841
{
 
842
        safe_string * ss;
 
843
        
 
844
        ss = new_safe_string(256);
 
845
        if ( !ss )
 
846
                return NULL;
 
847
 
 
848
        print_literal(ss,"("/*)*/);
 
849
        print_whsp(ss);
 
850
 
 
851
        print_numericoid(ss, at->at_oid);
 
852
        print_whsp(ss);
 
853
 
 
854
        if ( at->at_names ) {
 
855
                print_literal(ss,"NAME");
 
856
                print_qdescrs(ss,at->at_names);
 
857
        }
 
858
 
 
859
        if ( at->at_desc ) {
 
860
                print_literal(ss,"DESC");
 
861
                print_qdstring(ss,at->at_desc);
 
862
        }
 
863
 
 
864
        if ( at->at_obsolete ) {
 
865
                print_literal(ss, "OBSOLETE");
 
866
                print_whsp(ss);
 
867
        }
 
868
 
 
869
        if ( at->at_sup_oid ) {
 
870
                print_literal(ss,"SUP");
 
871
                print_woid(ss,at->at_sup_oid);
 
872
        }
 
873
 
 
874
        if ( at->at_equality_oid ) {
 
875
                print_literal(ss,"EQUALITY");
 
876
                print_woid(ss,at->at_equality_oid);
 
877
        }
 
878
 
 
879
        if ( at->at_ordering_oid ) {
 
880
                print_literal(ss,"ORDERING");
 
881
                print_woid(ss,at->at_ordering_oid);
 
882
        }
 
883
 
 
884
        if ( at->at_substr_oid ) {
 
885
                print_literal(ss,"SUBSTR");
 
886
                print_woid(ss,at->at_substr_oid);
 
887
        }
 
888
 
 
889
        if ( at->at_syntax_oid ) {
 
890
                print_literal(ss,"SYNTAX");
 
891
                print_whsp(ss);
 
892
                print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
 
893
                print_whsp(ss);
 
894
        }
 
895
 
 
896
        if ( at->at_single_value == LDAP_SCHEMA_YES ) {
 
897
                print_literal(ss,"SINGLE-VALUE");
 
898
                print_whsp(ss);
 
899
        }
 
900
 
 
901
        if ( at->at_collective == LDAP_SCHEMA_YES ) {
 
902
                print_literal(ss,"COLLECTIVE");
 
903
                print_whsp(ss);
 
904
        }
 
905
 
 
906
        if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
 
907
                print_literal(ss,"NO-USER-MODIFICATION");
 
908
                print_whsp(ss);
 
909
        }
 
910
 
 
911
        if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
 
912
                print_literal(ss,"USAGE");
 
913
                print_whsp(ss);
 
914
                switch (at->at_usage) {
 
915
                case LDAP_SCHEMA_DIRECTORY_OPERATION:
 
916
                        print_literal(ss,"directoryOperation");
 
917
                        break;
 
918
                case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
 
919
                        print_literal(ss,"distributedOperation");
 
920
                        break;
 
921
                case LDAP_SCHEMA_DSA_OPERATION:
 
922
                        print_literal(ss,"dSAOperation");
 
923
                        break;
 
924
                default:
 
925
                        print_literal(ss,"UNKNOWN");
 
926
                        break;
 
927
                }
 
928
        }
 
929
        
 
930
        print_whsp(ss);
 
931
 
 
932
        print_extensions(ss, at->at_extensions);
 
933
 
 
934
        print_literal(ss,/*(*/")");
 
935
 
 
936
        bv->bv_val = safe_strdup(ss);
 
937
        bv->bv_len = ss->pos;
 
938
        safe_string_free(ss);
 
939
        return(bv);
 
940
}
 
941
 
 
942
/*
 
943
 * Now come the parsers.  There is one parser for each entity type:
 
944
 * objectclasses, attributetypes, etc.
 
945
 *
 
946
 * Each of them is written as a recursive-descent parser, except that
 
947
 * none of them is really recursive.  But the idea is kept: there
 
948
 * is one routine per non-terminal that eithers gobbles lexical tokens
 
949
 * or calls lower-level routines, etc.
 
950
 *
 
951
 * The scanner is implemented in the routine get_token.  Actually,
 
952
 * get_token is more than a scanner and will return tokens that are
 
953
 * in fact non-terminals in the grammar.  So you can see the whole
 
954
 * approach as the combination of a low-level bottom-up recognizer
 
955
 * combined with a scanner and a number of top-down parsers.  Or just
 
956
 * consider that the real grammars recognized by the parsers are not
 
957
 * those of the standards.  As a matter of fact, our parsers are more
 
958
 * liberal than the spec when there is no ambiguity.
 
959
 *
 
960
 * The difference is pretty academic (modulo bugs or incorrect
 
961
 * interpretation of the specs).
 
962
 */
 
963
 
 
964
typedef enum tk_t {
 
965
        TK_NOENDQUOTE   = -2,
 
966
        TK_OUTOFMEM     = -1,
 
967
        TK_EOS          = 0,
 
968
        TK_UNEXPCHAR    = 1,
 
969
        TK_BAREWORD     = 2,
 
970
        TK_QDSTRING     = 3,
 
971
        TK_LEFTPAREN    = 4,
 
972
        TK_RIGHTPAREN   = 5,
 
973
        TK_DOLLAR       = 6,
 
974
        TK_QDESCR       = TK_QDSTRING
 
975
} tk_t;
 
976
 
 
977
static tk_t
 
978
get_token( const char ** sp, char ** token_val )
 
979
{
 
980
        tk_t kind;
 
981
        const char * p;
 
982
        const char * q;
 
983
        char * res;
 
984
 
 
985
        *token_val = NULL;
 
986
        switch (**sp) {
 
987
        case '\0':
 
988
                kind = TK_EOS;
 
989
                (*sp)++;
 
990
                break;
 
991
        case '(':
 
992
                kind = TK_LEFTPAREN;
 
993
                (*sp)++;
 
994
                break;
 
995
        case ')':
 
996
                kind = TK_RIGHTPAREN;
 
997
                (*sp)++;
 
998
                break;
 
999
        case '$':
 
1000
                kind = TK_DOLLAR;
 
1001
                (*sp)++;
 
1002
                break;
 
1003
        case '\'':
 
1004
                kind = TK_QDSTRING;
 
1005
                (*sp)++;
 
1006
                p = *sp;
 
1007
                while ( **sp != '\'' && **sp != '\0' )
 
1008
                        (*sp)++;
 
1009
                if ( **sp == '\'' ) {
 
1010
                        q = *sp;
 
1011
                        res = LDAP_MALLOC(q-p+1);
 
1012
                        if ( !res ) {
 
1013
                                kind = TK_OUTOFMEM;
 
1014
                        } else {
 
1015
                                strncpy(res,p,q-p);
 
1016
                                res[q-p] = '\0';
 
1017
                                *token_val = res;
 
1018
                        }
 
1019
                        (*sp)++;
 
1020
                } else {
 
1021
                        kind = TK_NOENDQUOTE;
 
1022
                }
 
1023
                break;
 
1024
        default:
 
1025
                kind = TK_BAREWORD;
 
1026
                p = *sp;
 
1027
                while ( !LDAP_SPACE(**sp) &&
 
1028
                        **sp != '(' &&
 
1029
                        **sp != ')' &&
 
1030
                        **sp != '$' &&
 
1031
                        **sp != '\'' &&
 
1032
                        /* for suggested minimum upper bound on the number
 
1033
                         * of characters (RFC 4517) */
 
1034
                        **sp != '{' &&
 
1035
                        **sp != '\0' )
 
1036
                        (*sp)++;
 
1037
                q = *sp;
 
1038
                res = LDAP_MALLOC(q-p+1);
 
1039
                if ( !res ) {
 
1040
                        kind = TK_OUTOFMEM;
 
1041
                } else {
 
1042
                        strncpy(res,p,q-p);
 
1043
                        res[q-p] = '\0';
 
1044
                        *token_val = res;
 
1045
                }
 
1046
                break;
 
1047
/*              kind = TK_UNEXPCHAR; */
 
1048
/*              break; */
 
1049
        }
 
1050
        
 
1051
        return kind;
 
1052
}
 
1053
 
 
1054
/* Gobble optional whitespace */
 
1055
static void
 
1056
parse_whsp(const char **sp)
 
1057
{
 
1058
        while (LDAP_SPACE(**sp))
 
1059
                (*sp)++;
 
1060
}
 
1061
 
 
1062
/* TBC:!!
 
1063
 * General note for all parsers: to guarantee the algorithm halts they
 
1064
 * must always advance the pointer even when an error is found.  For
 
1065
 * this one is not that important since an error here is fatal at the
 
1066
 * upper layers, but it is a simple strategy that will not get in
 
1067
 * endless loops.
 
1068
 */
 
1069
 
 
1070
/* Parse a sequence of dot-separated decimal strings */
 
1071
char *
 
1072
ldap_int_parse_numericoid(const char **sp, int *code, const int flags)
 
1073
{
 
1074
        char * res = NULL;
 
1075
        const char * start = *sp;
 
1076
        int len;
 
1077
        int quoted = 0;
 
1078
 
 
1079
        /* Netscape puts the SYNTAX value in quotes (incorrectly) */
 
1080
        if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
 
1081
                quoted = 1;
 
1082
                (*sp)++;
 
1083
                start++;
 
1084
        }
 
1085
        /* Each iteration of this loop gets one decimal string */
 
1086
        while (**sp) {
 
1087
                if ( !LDAP_DIGIT(**sp) ) {
 
1088
                        /*
 
1089
                         * Initial char is not a digit or char after dot is
 
1090
                         * not a digit
 
1091
                         */
 
1092
                        *code = LDAP_SCHERR_NODIGIT;
 
1093
                        return NULL;
 
1094
                }
 
1095
                (*sp)++;
 
1096
                while ( LDAP_DIGIT(**sp) )
 
1097
                        (*sp)++;
 
1098
                if ( **sp != '.' )
 
1099
                        break;
 
1100
                /* Otherwise, gobble the dot and loop again */
 
1101
                (*sp)++;
 
1102
        }
 
1103
        /* Now *sp points at the char past the numericoid. Perfect. */
 
1104
        len = *sp - start;
 
1105
        if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
 
1106
                if ( **sp == '\'' ) {
 
1107
                        (*sp)++;
 
1108
                } else {
 
1109
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1110
                        return NULL;
 
1111
                }
 
1112
        }
 
1113
        if (flags & LDAP_SCHEMA_SKIP) {
 
1114
                res = (char *)start;
 
1115
        } else {
 
1116
                res = LDAP_MALLOC(len+1);
 
1117
                if (!res) {
 
1118
                        *code = LDAP_SCHERR_OUTOFMEM;
 
1119
                        return(NULL);
 
1120
                }
 
1121
                strncpy(res,start,len);
 
1122
                res[len] = '\0';
 
1123
        }
 
1124
        return(res);
 
1125
}
 
1126
 
 
1127
/* Parse a sequence of dot-separated decimal strings */
 
1128
int
 
1129
ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid)
 
1130
{
 
1131
        *ruleid=0;
 
1132
 
 
1133
        if ( !LDAP_DIGIT(**sp) ) {
 
1134
                *code = LDAP_SCHERR_NODIGIT;
 
1135
                return -1;
 
1136
        }
 
1137
        *ruleid = (**sp) - '0';
 
1138
        (*sp)++;
 
1139
 
 
1140
        while ( LDAP_DIGIT(**sp) ) {
 
1141
                *ruleid *= 10;
 
1142
                *ruleid += (**sp) - '0';
 
1143
                (*sp)++;
 
1144
        }
 
1145
 
 
1146
        return 0;
 
1147
}
 
1148
 
 
1149
/* Parse a qdescr or a list of them enclosed in () */
 
1150
static char **
 
1151
parse_qdescrs(const char **sp, int *code)
 
1152
{
 
1153
        char ** res;
 
1154
        char ** res1;
 
1155
        tk_t kind;
 
1156
        char * sval;
 
1157
        int size;
 
1158
        int pos;
 
1159
 
 
1160
        parse_whsp(sp);
 
1161
        kind = get_token(sp,&sval);
 
1162
        if ( kind == TK_LEFTPAREN ) {
 
1163
                /* Let's presume there will be at least 2 entries */
 
1164
                size = 3;
 
1165
                res = LDAP_CALLOC(3,sizeof(char *));
 
1166
                if ( !res ) {
 
1167
                        *code = LDAP_SCHERR_OUTOFMEM;
 
1168
                        return NULL;
 
1169
                }
 
1170
                pos = 0;
 
1171
                while (1) {
 
1172
                        parse_whsp(sp);
 
1173
                        kind = get_token(sp,&sval);
 
1174
                        if ( kind == TK_RIGHTPAREN )
 
1175
                                break;
 
1176
                        if ( kind == TK_QDESCR ) {
 
1177
                                if ( pos == size-2 ) {
 
1178
                                        size++;
 
1179
                                        res1 = LDAP_REALLOC(res,size*sizeof(char *));
 
1180
                                        if ( !res1 ) {
 
1181
                                                LDAP_VFREE(res);
 
1182
                                                LDAP_FREE(sval);
 
1183
                                                *code = LDAP_SCHERR_OUTOFMEM;
 
1184
                                                return(NULL);
 
1185
                                        }
 
1186
                                        res = res1;
 
1187
                                }
 
1188
                                res[pos++] = sval;
 
1189
                                res[pos] = NULL;
 
1190
                                parse_whsp(sp);
 
1191
                        } else {
 
1192
                                LDAP_VFREE(res);
 
1193
                                LDAP_FREE(sval);
 
1194
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
1195
                                return(NULL);
 
1196
                        }
 
1197
                }
 
1198
                parse_whsp(sp);
 
1199
                return(res);
 
1200
        } else if ( kind == TK_QDESCR ) {
 
1201
                res = LDAP_CALLOC(2,sizeof(char *));
 
1202
                if ( !res ) {
 
1203
                        *code = LDAP_SCHERR_OUTOFMEM;
 
1204
                        return NULL;
 
1205
                }
 
1206
                res[0] = sval;
 
1207
                res[1] = NULL;
 
1208
                parse_whsp(sp);
 
1209
                return res;
 
1210
        } else {
 
1211
                LDAP_FREE(sval);
 
1212
                *code = LDAP_SCHERR_BADNAME;
 
1213
                return NULL;
 
1214
        }
 
1215
}
 
1216
 
 
1217
/* Parse a woid */
 
1218
static char *
 
1219
parse_woid(const char **sp, int *code)
 
1220
{
 
1221
        char * sval;
 
1222
        tk_t kind;
 
1223
 
 
1224
        parse_whsp(sp);
 
1225
        kind = get_token(sp, &sval);
 
1226
        if ( kind != TK_BAREWORD ) {
 
1227
                LDAP_FREE(sval);
 
1228
                *code = LDAP_SCHERR_UNEXPTOKEN;
 
1229
                return NULL;
 
1230
        }
 
1231
        parse_whsp(sp);
 
1232
        return sval;
 
1233
}
 
1234
 
 
1235
/* Parse a noidlen */
 
1236
static char *
 
1237
parse_noidlen(const char **sp, int *code, int *len, int flags)
 
1238
{
 
1239
        char * sval;
 
1240
        const char *savepos;
 
1241
        int quoted = 0;
 
1242
        int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED );
 
1243
        int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO );
 
1244
 
 
1245
        *len = 0;
 
1246
        /* Netscape puts the SYNTAX value in quotes (incorrectly) */
 
1247
        if ( allow_quoted && **sp == '\'' ) {
 
1248
                quoted = 1;
 
1249
                (*sp)++;
 
1250
        }
 
1251
        savepos = *sp;
 
1252
        sval = ldap_int_parse_numericoid(sp, code, 0);
 
1253
        if ( !sval ) {
 
1254
                if ( allow_oidmacro
 
1255
                        && *sp == savepos
 
1256
                        && *code == LDAP_SCHERR_NODIGIT )
 
1257
                {
 
1258
                        if ( get_token(sp, &sval) != TK_BAREWORD ) {
 
1259
                                if ( sval != NULL ) {
 
1260
                                        LDAP_FREE(sval);
 
1261
                                }
 
1262
                                return NULL;
 
1263
                        }
 
1264
                } else {
 
1265
                        return NULL;
 
1266
                }
 
1267
        }
 
1268
        if ( **sp == '{' /*}*/ ) {
 
1269
                (*sp)++;
 
1270
                *len = atoi(*sp);
 
1271
                while ( LDAP_DIGIT(**sp) )
 
1272
                        (*sp)++;
 
1273
                if ( **sp != /*{*/ '}' ) {
 
1274
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1275
                        LDAP_FREE(sval);
 
1276
                        return NULL;
 
1277
                }
 
1278
                (*sp)++;
 
1279
        }               
 
1280
        if ( allow_quoted && quoted ) {
 
1281
                if ( **sp == '\'' ) {
 
1282
                        (*sp)++;
 
1283
                } else {
 
1284
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1285
                        LDAP_FREE(sval);
 
1286
                        return NULL;
 
1287
                }
 
1288
        }
 
1289
        return sval;
 
1290
}
 
1291
 
 
1292
/*
 
1293
 * Next routine will accept a qdstring in place of an oid if
 
1294
 * allow_quoted is set.  This is necessary to interoperate with
 
1295
 * Netscape Directory server that will improperly quote each oid (at
 
1296
 * least those of the descr kind) in the SUP clause.
 
1297
 */
 
1298
 
 
1299
/* Parse a woid or a $-separated list of them enclosed in () */
 
1300
static char **
 
1301
parse_oids(const char **sp, int *code, const int allow_quoted)
 
1302
{
 
1303
        char ** res;
 
1304
        char ** res1;
 
1305
        tk_t kind;
 
1306
        char * sval;
 
1307
        int size;
 
1308
        int pos;
 
1309
 
 
1310
        /*
 
1311
         * Strictly speaking, doing this here accepts whsp before the
 
1312
         * ( at the begining of an oidlist, but this is harmless.  Also,
 
1313
         * we are very liberal in what we accept as an OID.  Maybe
 
1314
         * refine later.
 
1315
         */
 
1316
        parse_whsp(sp);
 
1317
        kind = get_token(sp,&sval);
 
1318
        if ( kind == TK_LEFTPAREN ) {
 
1319
                /* Let's presume there will be at least 2 entries */
 
1320
                size = 3;
 
1321
                res = LDAP_CALLOC(3,sizeof(char *));
 
1322
                if ( !res ) {
 
1323
                        *code = LDAP_SCHERR_OUTOFMEM;
 
1324
                        return NULL;
 
1325
                }
 
1326
                pos = 0;
 
1327
                parse_whsp(sp);
 
1328
                kind = get_token(sp,&sval);
 
1329
                if ( kind == TK_BAREWORD ||
 
1330
                     ( allow_quoted && kind == TK_QDSTRING ) ) {
 
1331
                        res[pos++] = sval;
 
1332
                        res[pos] = NULL;
 
1333
                } else if ( kind == TK_RIGHTPAREN ) {
 
1334
                        /* FIXME: be liberal in what we accept... */
 
1335
                        parse_whsp(sp);
 
1336
                        LDAP_FREE(res);
 
1337
                        return NULL;
 
1338
                } else {
 
1339
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1340
                        LDAP_FREE(sval);
 
1341
                        LDAP_VFREE(res);
 
1342
                        return NULL;
 
1343
                }
 
1344
                parse_whsp(sp);
 
1345
                while (1) {
 
1346
                        kind = get_token(sp,&sval);
 
1347
                        if ( kind == TK_RIGHTPAREN )
 
1348
                                break;
 
1349
                        if ( kind == TK_DOLLAR ) {
 
1350
                                parse_whsp(sp);
 
1351
                                kind = get_token(sp,&sval);
 
1352
                                if ( kind == TK_BAREWORD ||
 
1353
                                     ( allow_quoted &&
 
1354
                                       kind == TK_QDSTRING ) ) {
 
1355
                                        if ( pos == size-2 ) {
 
1356
                                                size++;
 
1357
                                                res1 = LDAP_REALLOC(res,size*sizeof(char *));
 
1358
                                                if ( !res1 ) {
 
1359
                                                        LDAP_FREE(sval);
 
1360
                                                        LDAP_VFREE(res);
 
1361
                                                        *code = LDAP_SCHERR_OUTOFMEM;
 
1362
                                                        return(NULL);
 
1363
                                                }
 
1364
                                                res = res1;
 
1365
                                        }
 
1366
                                        res[pos++] = sval;
 
1367
                                        res[pos] = NULL;
 
1368
                                } else {
 
1369
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1370
                                        LDAP_FREE(sval);
 
1371
                                        LDAP_VFREE(res);
 
1372
                                        return NULL;
 
1373
                                }
 
1374
                                parse_whsp(sp);
 
1375
                        } else {
 
1376
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
1377
                                LDAP_FREE(sval);
 
1378
                                LDAP_VFREE(res);
 
1379
                                return NULL;
 
1380
                        }
 
1381
                }
 
1382
                parse_whsp(sp);
 
1383
                return(res);
 
1384
        } else if ( kind == TK_BAREWORD ||
 
1385
                    ( allow_quoted && kind == TK_QDSTRING ) ) {
 
1386
                res = LDAP_CALLOC(2,sizeof(char *));
 
1387
                if ( !res ) {
 
1388
                        LDAP_FREE(sval);
 
1389
                        *code = LDAP_SCHERR_OUTOFMEM;
 
1390
                        return NULL;
 
1391
                }
 
1392
                res[0] = sval;
 
1393
                res[1] = NULL;
 
1394
                parse_whsp(sp);
 
1395
                return res;
 
1396
        } else {
 
1397
                LDAP_FREE(sval);
 
1398
                *code = LDAP_SCHERR_BADNAME;
 
1399
                return NULL;
 
1400
        }
 
1401
}
 
1402
 
 
1403
static int
 
1404
add_extension(LDAPSchemaExtensionItem ***extensions,
 
1405
              char * name, char ** values)
 
1406
{
 
1407
        int n;
 
1408
        LDAPSchemaExtensionItem **tmp, *ext;
 
1409
 
 
1410
        ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
 
1411
        if ( !ext )
 
1412
                return 1;
 
1413
        ext->lsei_name = name;
 
1414
        ext->lsei_values = values;
 
1415
 
 
1416
        if ( !*extensions ) {
 
1417
                *extensions =
 
1418
                  LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
 
1419
                if ( !*extensions ) {
 
1420
                        LDAP_FREE( ext );
 
1421
                        return 1;
 
1422
                }
 
1423
                n = 0;
 
1424
        } else {
 
1425
                for ( n=0; (*extensions)[n] != NULL; n++ )
 
1426
                        ;
 
1427
                tmp = LDAP_REALLOC(*extensions,
 
1428
                                   (n+2)*sizeof(LDAPSchemaExtensionItem *));
 
1429
                if ( !tmp ) {
 
1430
                        LDAP_FREE( ext );
 
1431
                        return 1;
 
1432
                }
 
1433
                *extensions = tmp;
 
1434
        }
 
1435
        (*extensions)[n] = ext;
 
1436
        (*extensions)[n+1] = NULL;
 
1437
        return 0;
 
1438
}
 
1439
 
 
1440
static void
 
1441
free_extensions(LDAPSchemaExtensionItem **extensions)
 
1442
{
 
1443
        LDAPSchemaExtensionItem **ext;
 
1444
 
 
1445
        if ( extensions ) {
 
1446
                for ( ext = extensions; *ext != NULL; ext++ ) {
 
1447
                        LDAP_FREE((*ext)->lsei_name);
 
1448
                        LDAP_VFREE((*ext)->lsei_values);
 
1449
                        LDAP_FREE(*ext);
 
1450
                }
 
1451
                LDAP_FREE(extensions);
 
1452
        }
 
1453
}
 
1454
 
 
1455
void
 
1456
ldap_syntax_free( LDAPSyntax * syn )
 
1457
{
 
1458
        LDAP_FREE(syn->syn_oid);
 
1459
        if (syn->syn_names) LDAP_VFREE(syn->syn_names);
 
1460
        if (syn->syn_desc) LDAP_FREE(syn->syn_desc);
 
1461
        free_extensions(syn->syn_extensions);
 
1462
        LDAP_FREE(syn);
 
1463
}
 
1464
 
 
1465
LDAPSyntax *
 
1466
ldap_str2syntax( LDAP_CONST char * s,
 
1467
        int * code,
 
1468
        LDAP_CONST char ** errp,
 
1469
        LDAP_CONST unsigned flags )
 
1470
{
 
1471
        tk_t kind;
 
1472
        const char * ss = s;
 
1473
        char * sval;
 
1474
        int seen_name = 0;
 
1475
        int seen_desc = 0;
 
1476
        LDAPSyntax * syn;
 
1477
        char ** ext_vals;
 
1478
 
 
1479
        if ( !s ) {
 
1480
                *code = LDAP_SCHERR_EMPTY;
 
1481
                *errp = "";
 
1482
                return NULL;
 
1483
        }
 
1484
 
 
1485
        *errp = s;
 
1486
        syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
 
1487
 
 
1488
        if ( !syn ) {
 
1489
                *code = LDAP_SCHERR_OUTOFMEM;
 
1490
                return NULL;
 
1491
        }
 
1492
 
 
1493
        kind = get_token(&ss,&sval);
 
1494
        if ( kind != TK_LEFTPAREN ) {
 
1495
                LDAP_FREE(sval);
 
1496
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
1497
                ldap_syntax_free(syn);
 
1498
                return NULL;
 
1499
        }
 
1500
 
 
1501
        parse_whsp(&ss);
 
1502
        syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0);
 
1503
        if ( !syn->syn_oid ) {
 
1504
                *errp = ss;
 
1505
                ldap_syntax_free(syn);
 
1506
                return NULL;
 
1507
        }
 
1508
        parse_whsp(&ss);
 
1509
 
 
1510
        /*
 
1511
         * Beyond this point we will be liberal and accept the items
 
1512
         * in any order.
 
1513
         */
 
1514
        while (1) {
 
1515
                kind = get_token(&ss,&sval);
 
1516
                switch (kind) {
 
1517
                case TK_EOS:
 
1518
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
1519
                        *errp = EndOfInput;
 
1520
                        ldap_syntax_free(syn);
 
1521
                        return NULL;
 
1522
                case TK_RIGHTPAREN:
 
1523
                        return syn;
 
1524
                case TK_BAREWORD:
 
1525
                        if ( !strcasecmp(sval,"NAME") ) {
 
1526
                                LDAP_FREE(sval);
 
1527
                                if ( seen_name ) {
 
1528
                                        *code = LDAP_SCHERR_DUPOPT;
 
1529
                                        *errp = ss;
 
1530
                                        ldap_syntax_free(syn);
 
1531
                                        return(NULL);
 
1532
                                }
 
1533
                                seen_name = 1;
 
1534
                                syn->syn_names = parse_qdescrs(&ss,code);
 
1535
                                if ( !syn->syn_names ) {
 
1536
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
1537
                                                *code = LDAP_SCHERR_BADNAME;
 
1538
                                        *errp = ss;
 
1539
                                        ldap_syntax_free(syn);
 
1540
                                        return NULL;
 
1541
                                }
 
1542
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
1543
                                LDAP_FREE(sval);
 
1544
                                if ( seen_desc ) {
 
1545
                                        *code = LDAP_SCHERR_DUPOPT;
 
1546
                                        *errp = ss;
 
1547
                                        ldap_syntax_free(syn);
 
1548
                                        return(NULL);
 
1549
                                }
 
1550
                                seen_desc = 1;
 
1551
                                parse_whsp(&ss);
 
1552
                                kind = get_token(&ss,&sval);
 
1553
                                if ( kind != TK_QDSTRING ) {
 
1554
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1555
                                        *errp = ss;
 
1556
                                        LDAP_FREE(sval);
 
1557
                                        ldap_syntax_free(syn);
 
1558
                                        return NULL;
 
1559
                                }
 
1560
                                syn->syn_desc = sval;
 
1561
                                parse_whsp(&ss);
 
1562
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
1563
                                /* Should be parse_qdstrings */
 
1564
                                ext_vals = parse_qdescrs(&ss, code);
 
1565
                                if ( !ext_vals ) {
 
1566
                                        *errp = ss;
 
1567
                                        ldap_syntax_free(syn);
 
1568
                                        return NULL;
 
1569
                                }
 
1570
                                if ( add_extension(&syn->syn_extensions,
 
1571
                                                    sval, ext_vals) ) {
 
1572
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
1573
                                        *errp = ss;
 
1574
                                        LDAP_FREE(sval);
 
1575
                                        ldap_syntax_free(syn);
 
1576
                                        return NULL;
 
1577
                                }
 
1578
                        } else {
 
1579
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
1580
                                *errp = ss;
 
1581
                                LDAP_FREE(sval);
 
1582
                                ldap_syntax_free(syn);
 
1583
                                return NULL;
 
1584
                        }
 
1585
                        break;
 
1586
                default:
 
1587
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1588
                        *errp = ss;
 
1589
                        LDAP_FREE(sval);
 
1590
                        ldap_syntax_free(syn);
 
1591
                        return NULL;
 
1592
                }
 
1593
        }
 
1594
}
 
1595
 
 
1596
void
 
1597
ldap_matchingrule_free( LDAPMatchingRule * mr )
 
1598
{
 
1599
        LDAP_FREE(mr->mr_oid);
 
1600
        if (mr->mr_names) LDAP_VFREE(mr->mr_names);
 
1601
        if (mr->mr_desc) LDAP_FREE(mr->mr_desc);
 
1602
        if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid);
 
1603
        free_extensions(mr->mr_extensions);
 
1604
        LDAP_FREE(mr);
 
1605
}
 
1606
 
 
1607
LDAPMatchingRule *
 
1608
ldap_str2matchingrule( LDAP_CONST char * s,
 
1609
        int * code,
 
1610
        LDAP_CONST char ** errp,
 
1611
        LDAP_CONST unsigned flags )
 
1612
{
 
1613
        tk_t kind;
 
1614
        const char * ss = s;
 
1615
        char * sval;
 
1616
        int seen_name = 0;
 
1617
        int seen_desc = 0;
 
1618
        int seen_obsolete = 0;
 
1619
        int seen_syntax = 0;
 
1620
        LDAPMatchingRule * mr;
 
1621
        char ** ext_vals;
 
1622
        const char * savepos;
 
1623
 
 
1624
        if ( !s ) {
 
1625
                *code = LDAP_SCHERR_EMPTY;
 
1626
                *errp = "";
 
1627
                return NULL;
 
1628
        }
 
1629
 
 
1630
        *errp = s;
 
1631
        mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
 
1632
 
 
1633
        if ( !mr ) {
 
1634
                *code = LDAP_SCHERR_OUTOFMEM;
 
1635
                return NULL;
 
1636
        }
 
1637
 
 
1638
        kind = get_token(&ss,&sval);
 
1639
        if ( kind != TK_LEFTPAREN ) {
 
1640
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
1641
                LDAP_FREE(sval);
 
1642
                ldap_matchingrule_free(mr);
 
1643
                return NULL;
 
1644
        }
 
1645
 
 
1646
        parse_whsp(&ss);
 
1647
        savepos = ss;
 
1648
        mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags);
 
1649
        if ( !mr->mr_oid ) {
 
1650
                if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
 
1651
                        /* Backtracking */
 
1652
                        ss = savepos;
 
1653
                        kind = get_token(&ss,&sval);
 
1654
                        if ( kind == TK_BAREWORD ) {
 
1655
                                if ( !strcasecmp(sval, "NAME") ||
 
1656
                                     !strcasecmp(sval, "DESC") ||
 
1657
                                     !strcasecmp(sval, "OBSOLETE") ||
 
1658
                                     !strcasecmp(sval, "SYNTAX") ||
 
1659
                                     !strncasecmp(sval, "X-", 2) ) {
 
1660
                                        /* Missing OID, backtrack */
 
1661
                                        ss = savepos;
 
1662
                                } else {
 
1663
                                        /* Non-numerical OID, ignore */
 
1664
                                }
 
1665
                        }
 
1666
                        LDAP_FREE(sval);
 
1667
                } else {
 
1668
                        *errp = ss;
 
1669
                        ldap_matchingrule_free(mr);
 
1670
                        return NULL;
 
1671
                }
 
1672
        }
 
1673
        parse_whsp(&ss);
 
1674
 
 
1675
        /*
 
1676
         * Beyond this point we will be liberal and accept the items
 
1677
         * in any order.
 
1678
         */
 
1679
        while (1) {
 
1680
                kind = get_token(&ss,&sval);
 
1681
                switch (kind) {
 
1682
                case TK_EOS:
 
1683
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
1684
                        *errp = EndOfInput;
 
1685
                        ldap_matchingrule_free(mr);
 
1686
                        return NULL;
 
1687
                case TK_RIGHTPAREN:
 
1688
                        if( !seen_syntax ) {
 
1689
                                *code = LDAP_SCHERR_MISSING;
 
1690
                                ldap_matchingrule_free(mr);
 
1691
                                return NULL;
 
1692
                        }
 
1693
                        return mr;
 
1694
                case TK_BAREWORD:
 
1695
                        if ( !strcasecmp(sval,"NAME") ) {
 
1696
                                LDAP_FREE(sval);
 
1697
                                if ( seen_name ) {
 
1698
                                        *code = LDAP_SCHERR_DUPOPT;
 
1699
                                        *errp = ss;
 
1700
                                        ldap_matchingrule_free(mr);
 
1701
                                        return(NULL);
 
1702
                                }
 
1703
                                seen_name = 1;
 
1704
                                mr->mr_names = parse_qdescrs(&ss,code);
 
1705
                                if ( !mr->mr_names ) {
 
1706
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
1707
                                                *code = LDAP_SCHERR_BADNAME;
 
1708
                                        *errp = ss;
 
1709
                                        ldap_matchingrule_free(mr);
 
1710
                                        return NULL;
 
1711
                                }
 
1712
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
1713
                                LDAP_FREE(sval);
 
1714
                                if ( seen_desc ) {
 
1715
                                        *code = LDAP_SCHERR_DUPOPT;
 
1716
                                        *errp = ss;
 
1717
                                        ldap_matchingrule_free(mr);
 
1718
                                        return(NULL);
 
1719
                                }
 
1720
                                seen_desc = 1;
 
1721
                                parse_whsp(&ss);
 
1722
                                kind = get_token(&ss,&sval);
 
1723
                                if ( kind != TK_QDSTRING ) {
 
1724
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1725
                                        *errp = ss;
 
1726
                                        LDAP_FREE(sval);
 
1727
                                        ldap_matchingrule_free(mr);
 
1728
                                        return NULL;
 
1729
                                }
 
1730
                                mr->mr_desc = sval;
 
1731
                                parse_whsp(&ss);
 
1732
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
1733
                                LDAP_FREE(sval);
 
1734
                                if ( seen_obsolete ) {
 
1735
                                        *code = LDAP_SCHERR_DUPOPT;
 
1736
                                        *errp = ss;
 
1737
                                        ldap_matchingrule_free(mr);
 
1738
                                        return(NULL);
 
1739
                                }
 
1740
                                seen_obsolete = 1;
 
1741
                                mr->mr_obsolete = LDAP_SCHEMA_YES;
 
1742
                                parse_whsp(&ss);
 
1743
                        } else if ( !strcasecmp(sval,"SYNTAX") ) {
 
1744
                                LDAP_FREE(sval);
 
1745
                                if ( seen_syntax ) {
 
1746
                                        *code = LDAP_SCHERR_DUPOPT;
 
1747
                                        *errp = ss;
 
1748
                                        ldap_matchingrule_free(mr);
 
1749
                                        return(NULL);
 
1750
                                }
 
1751
                                seen_syntax = 1;
 
1752
                                parse_whsp(&ss);
 
1753
                                mr->mr_syntax_oid =
 
1754
                                        ldap_int_parse_numericoid(&ss,code,flags);
 
1755
                                if ( !mr->mr_syntax_oid ) {
 
1756
                                        *errp = ss;
 
1757
                                        ldap_matchingrule_free(mr);
 
1758
                                        return NULL;
 
1759
                                }
 
1760
                                parse_whsp(&ss);
 
1761
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
1762
                                /* Should be parse_qdstrings */
 
1763
                                ext_vals = parse_qdescrs(&ss, code);
 
1764
                                if ( !ext_vals ) {
 
1765
                                        *errp = ss;
 
1766
                                        ldap_matchingrule_free(mr);
 
1767
                                        return NULL;
 
1768
                                }
 
1769
                                if ( add_extension(&mr->mr_extensions,
 
1770
                                                    sval, ext_vals) ) {
 
1771
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
1772
                                        *errp = ss;
 
1773
                                        LDAP_FREE(sval);
 
1774
                                        ldap_matchingrule_free(mr);
 
1775
                                        return NULL;
 
1776
                                }
 
1777
                        } else {
 
1778
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
1779
                                *errp = ss;
 
1780
                                LDAP_FREE(sval);
 
1781
                                ldap_matchingrule_free(mr);
 
1782
                                return NULL;
 
1783
                        }
 
1784
                        break;
 
1785
                default:
 
1786
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1787
                        *errp = ss;
 
1788
                        LDAP_FREE(sval);
 
1789
                        ldap_matchingrule_free(mr);
 
1790
                        return NULL;
 
1791
                }
 
1792
        }
 
1793
}
 
1794
 
 
1795
void
 
1796
ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
 
1797
{
 
1798
        LDAP_FREE(mru->mru_oid);
 
1799
        if (mru->mru_names) LDAP_VFREE(mru->mru_names);
 
1800
        if (mru->mru_desc) LDAP_FREE(mru->mru_desc);
 
1801
        if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids);
 
1802
        free_extensions(mru->mru_extensions);
 
1803
        LDAP_FREE(mru);
 
1804
}
 
1805
 
 
1806
LDAPMatchingRuleUse *
 
1807
ldap_str2matchingruleuse( LDAP_CONST char * s,
 
1808
        int * code,
 
1809
        LDAP_CONST char ** errp,
 
1810
        LDAP_CONST unsigned flags )
 
1811
{
 
1812
        tk_t kind;
 
1813
        const char * ss = s;
 
1814
        char * sval;
 
1815
        int seen_name = 0;
 
1816
        int seen_desc = 0;
 
1817
        int seen_obsolete = 0;
 
1818
        int seen_applies = 0;
 
1819
        LDAPMatchingRuleUse * mru;
 
1820
        char ** ext_vals;
 
1821
        const char * savepos;
 
1822
 
 
1823
        if ( !s ) {
 
1824
                *code = LDAP_SCHERR_EMPTY;
 
1825
                *errp = "";
 
1826
                return NULL;
 
1827
        }
 
1828
 
 
1829
        *errp = s;
 
1830
        mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
 
1831
 
 
1832
        if ( !mru ) {
 
1833
                *code = LDAP_SCHERR_OUTOFMEM;
 
1834
                return NULL;
 
1835
        }
 
1836
 
 
1837
        kind = get_token(&ss,&sval);
 
1838
        if ( kind != TK_LEFTPAREN ) {
 
1839
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
1840
                LDAP_FREE(sval);
 
1841
                ldap_matchingruleuse_free(mru);
 
1842
                return NULL;
 
1843
        }
 
1844
 
 
1845
        parse_whsp(&ss);
 
1846
        savepos = ss;
 
1847
        mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags);
 
1848
        if ( !mru->mru_oid ) {
 
1849
                if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
 
1850
                        /* Backtracking */
 
1851
                        ss = savepos;
 
1852
                        kind = get_token(&ss,&sval);
 
1853
                        if ( kind == TK_BAREWORD ) {
 
1854
                                if ( !strcasecmp(sval, "NAME") ||
 
1855
                                     !strcasecmp(sval, "DESC") ||
 
1856
                                     !strcasecmp(sval, "OBSOLETE") ||
 
1857
                                     !strcasecmp(sval, "APPLIES") ||
 
1858
                                     !strncasecmp(sval, "X-", 2) ) {
 
1859
                                        /* Missing OID, backtrack */
 
1860
                                        ss = savepos;
 
1861
                                } else {
 
1862
                                        /* Non-numerical OID, ignore */
 
1863
                                }
 
1864
                        }
 
1865
                        LDAP_FREE(sval);
 
1866
                } else {
 
1867
                        *errp = ss;
 
1868
                        ldap_matchingruleuse_free(mru);
 
1869
                        return NULL;
 
1870
                }
 
1871
        }
 
1872
        parse_whsp(&ss);
 
1873
 
 
1874
        /*
 
1875
         * Beyond this point we will be liberal and accept the items
 
1876
         * in any order.
 
1877
         */
 
1878
        while (1) {
 
1879
                kind = get_token(&ss,&sval);
 
1880
                switch (kind) {
 
1881
                case TK_EOS:
 
1882
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
1883
                        *errp = EndOfInput;
 
1884
                        ldap_matchingruleuse_free(mru);
 
1885
                        return NULL;
 
1886
                case TK_RIGHTPAREN:
 
1887
                        if( !seen_applies ) {
 
1888
                                *code = LDAP_SCHERR_MISSING;
 
1889
                                ldap_matchingruleuse_free(mru);
 
1890
                                return NULL;
 
1891
                        }
 
1892
                        return mru;
 
1893
                case TK_BAREWORD:
 
1894
                        if ( !strcasecmp(sval,"NAME") ) {
 
1895
                                LDAP_FREE(sval);
 
1896
                                if ( seen_name ) {
 
1897
                                        *code = LDAP_SCHERR_DUPOPT;
 
1898
                                        *errp = ss;
 
1899
                                        ldap_matchingruleuse_free(mru);
 
1900
                                        return(NULL);
 
1901
                                }
 
1902
                                seen_name = 1;
 
1903
                                mru->mru_names = parse_qdescrs(&ss,code);
 
1904
                                if ( !mru->mru_names ) {
 
1905
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
1906
                                                *code = LDAP_SCHERR_BADNAME;
 
1907
                                        *errp = ss;
 
1908
                                        ldap_matchingruleuse_free(mru);
 
1909
                                        return NULL;
 
1910
                                }
 
1911
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
1912
                                LDAP_FREE(sval);
 
1913
                                if ( seen_desc ) {
 
1914
                                        *code = LDAP_SCHERR_DUPOPT;
 
1915
                                        *errp = ss;
 
1916
                                        ldap_matchingruleuse_free(mru);
 
1917
                                        return(NULL);
 
1918
                                }
 
1919
                                seen_desc = 1;
 
1920
                                parse_whsp(&ss);
 
1921
                                kind = get_token(&ss,&sval);
 
1922
                                if ( kind != TK_QDSTRING ) {
 
1923
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1924
                                        *errp = ss;
 
1925
                                        LDAP_FREE(sval);
 
1926
                                        ldap_matchingruleuse_free(mru);
 
1927
                                        return NULL;
 
1928
                                }
 
1929
                                mru->mru_desc = sval;
 
1930
                                parse_whsp(&ss);
 
1931
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
1932
                                LDAP_FREE(sval);
 
1933
                                if ( seen_obsolete ) {
 
1934
                                        *code = LDAP_SCHERR_DUPOPT;
 
1935
                                        *errp = ss;
 
1936
                                        ldap_matchingruleuse_free(mru);
 
1937
                                        return(NULL);
 
1938
                                }
 
1939
                                seen_obsolete = 1;
 
1940
                                mru->mru_obsolete = LDAP_SCHEMA_YES;
 
1941
                                parse_whsp(&ss);
 
1942
                        } else if ( !strcasecmp(sval,"APPLIES") ) {
 
1943
                                LDAP_FREE(sval);
 
1944
                                if ( seen_applies ) {
 
1945
                                        *code = LDAP_SCHERR_DUPOPT;
 
1946
                                        *errp = ss;
 
1947
                                        ldap_matchingruleuse_free(mru);
 
1948
                                        return(NULL);
 
1949
                                }
 
1950
                                seen_applies = 1;
 
1951
                                mru->mru_applies_oids = parse_oids(&ss,
 
1952
                                                             code,
 
1953
                                                             flags);
 
1954
                                if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) {
 
1955
                                        *errp = ss;
 
1956
                                        ldap_matchingruleuse_free(mru);
 
1957
                                        return NULL;
 
1958
                                }
 
1959
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
1960
                                /* Should be parse_qdstrings */
 
1961
                                ext_vals = parse_qdescrs(&ss, code);
 
1962
                                if ( !ext_vals ) {
 
1963
                                        *errp = ss;
 
1964
                                        ldap_matchingruleuse_free(mru);
 
1965
                                        return NULL;
 
1966
                                }
 
1967
                                if ( add_extension(&mru->mru_extensions,
 
1968
                                                    sval, ext_vals) ) {
 
1969
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
1970
                                        *errp = ss;
 
1971
                                        LDAP_FREE(sval);
 
1972
                                        ldap_matchingruleuse_free(mru);
 
1973
                                        return NULL;
 
1974
                                }
 
1975
                        } else {
 
1976
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
1977
                                *errp = ss;
 
1978
                                LDAP_FREE(sval);
 
1979
                                ldap_matchingruleuse_free(mru);
 
1980
                                return NULL;
 
1981
                        }
 
1982
                        break;
 
1983
                default:
 
1984
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
1985
                        *errp = ss;
 
1986
                        LDAP_FREE(sval);
 
1987
                        ldap_matchingruleuse_free(mru);
 
1988
                        return NULL;
 
1989
                }
 
1990
        }
 
1991
}
 
1992
 
 
1993
void
 
1994
ldap_attributetype_free(LDAPAttributeType * at)
 
1995
{
 
1996
        LDAP_FREE(at->at_oid);
 
1997
        if (at->at_names) LDAP_VFREE(at->at_names);
 
1998
        if (at->at_desc) LDAP_FREE(at->at_desc);
 
1999
        if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid);
 
2000
        if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid);
 
2001
        if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid);
 
2002
        if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid);
 
2003
        if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid);
 
2004
        free_extensions(at->at_extensions);
 
2005
        LDAP_FREE(at);
 
2006
}
 
2007
 
 
2008
LDAPAttributeType *
 
2009
ldap_str2attributetype( LDAP_CONST char * s,
 
2010
        int * code,
 
2011
        LDAP_CONST char ** errp,
 
2012
        LDAP_CONST unsigned flags )
 
2013
{
 
2014
        tk_t kind;
 
2015
        const char * ss = s;
 
2016
        char * sval;
 
2017
        int seen_name = 0;
 
2018
        int seen_desc = 0;
 
2019
        int seen_obsolete = 0;
 
2020
        int seen_sup = 0;
 
2021
        int seen_equality = 0;
 
2022
        int seen_ordering = 0;
 
2023
        int seen_substr = 0;
 
2024
        int seen_syntax = 0;
 
2025
        int seen_usage = 0;
 
2026
        LDAPAttributeType * at;
 
2027
        char ** ext_vals;
 
2028
        const char * savepos;
 
2029
 
 
2030
        if ( !s ) {
 
2031
                *code = LDAP_SCHERR_EMPTY;
 
2032
                *errp = "";
 
2033
                return NULL;
 
2034
        }
 
2035
 
 
2036
        *errp = s;
 
2037
        at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
 
2038
 
 
2039
        if ( !at ) {
 
2040
                *code = LDAP_SCHERR_OUTOFMEM;
 
2041
                return NULL;
 
2042
        }
 
2043
 
 
2044
        kind = get_token(&ss,&sval);
 
2045
        if ( kind != TK_LEFTPAREN ) {
 
2046
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
2047
                LDAP_FREE(sval);
 
2048
                ldap_attributetype_free(at);
 
2049
                return NULL;
 
2050
        }
 
2051
 
 
2052
        /*
 
2053
         * Definitions MUST begin with an OID in the numericoid format.
 
2054
         * However, this routine is used by clients to parse the response
 
2055
         * from servers and very well known servers will provide an OID
 
2056
         * in the wrong format or even no OID at all.  We do our best to
 
2057
         * extract info from those servers.
 
2058
         */
 
2059
        parse_whsp(&ss);
 
2060
        savepos = ss;
 
2061
        at->at_oid = ldap_int_parse_numericoid(&ss,code,0);
 
2062
        if ( !at->at_oid ) {
 
2063
                if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
 
2064
                                | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
 
2065
                            && (ss == savepos) )
 
2066
                {
 
2067
                        /* Backtracking */
 
2068
                        ss = savepos;
 
2069
                        kind = get_token(&ss,&sval);
 
2070
                        if ( kind == TK_BAREWORD ) {
 
2071
                                if ( !strcasecmp(sval, "NAME") ||
 
2072
                                     !strcasecmp(sval, "DESC") ||
 
2073
                                     !strcasecmp(sval, "OBSOLETE") ||
 
2074
                                     !strcasecmp(sval, "SUP") ||
 
2075
                                     !strcasecmp(sval, "EQUALITY") ||
 
2076
                                     !strcasecmp(sval, "ORDERING") ||
 
2077
                                     !strcasecmp(sval, "SUBSTR") ||
 
2078
                                     !strcasecmp(sval, "SYNTAX") ||
 
2079
                                     !strcasecmp(sval, "SINGLE-VALUE") ||
 
2080
                                     !strcasecmp(sval, "COLLECTIVE") ||
 
2081
                                     !strcasecmp(sval, "NO-USER-MODIFICATION") ||
 
2082
                                     !strcasecmp(sval, "USAGE") ||
 
2083
                                     !strncasecmp(sval, "X-", 2) )
 
2084
                                {
 
2085
                                        /* Missing OID, backtrack */
 
2086
                                        ss = savepos;
 
2087
                                } else if ( flags
 
2088
                                        & LDAP_SCHEMA_ALLOW_OID_MACRO)
 
2089
                                {
 
2090
                                        /* Non-numerical OID ... */
 
2091
                                        int len = ss-savepos;
 
2092
                                        at->at_oid = LDAP_MALLOC(len+1);
 
2093
                                        strncpy(at->at_oid, savepos, len);
 
2094
                                        at->at_oid[len] = 0;
 
2095
                                }
 
2096
                        }
 
2097
                        LDAP_FREE(sval);
 
2098
                } else {
 
2099
                        *errp = ss;
 
2100
                        ldap_attributetype_free(at);
 
2101
                        return NULL;
 
2102
                }
 
2103
        }
 
2104
        parse_whsp(&ss);
 
2105
 
 
2106
        /*
 
2107
         * Beyond this point we will be liberal and accept the items
 
2108
         * in any order.
 
2109
         */
 
2110
        while (1) {
 
2111
                kind = get_token(&ss,&sval);
 
2112
                switch (kind) {
 
2113
                case TK_EOS:
 
2114
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
2115
                        *errp = EndOfInput;
 
2116
                        ldap_attributetype_free(at);
 
2117
                        return NULL;
 
2118
                case TK_RIGHTPAREN:
 
2119
                        return at;
 
2120
                case TK_BAREWORD:
 
2121
                        if ( !strcasecmp(sval,"NAME") ) {
 
2122
                                LDAP_FREE(sval);
 
2123
                                if ( seen_name ) {
 
2124
                                        *code = LDAP_SCHERR_DUPOPT;
 
2125
                                        *errp = ss;
 
2126
                                        ldap_attributetype_free(at);
 
2127
                                        return(NULL);
 
2128
                                }
 
2129
                                seen_name = 1;
 
2130
                                at->at_names = parse_qdescrs(&ss,code);
 
2131
                                if ( !at->at_names ) {
 
2132
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
2133
                                                *code = LDAP_SCHERR_BADNAME;
 
2134
                                        *errp = ss;
 
2135
                                        ldap_attributetype_free(at);
 
2136
                                        return NULL;
 
2137
                                }
 
2138
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
2139
                                LDAP_FREE(sval);
 
2140
                                if ( seen_desc ) {
 
2141
                                        *code = LDAP_SCHERR_DUPOPT;
 
2142
                                        *errp = ss;
 
2143
                                        ldap_attributetype_free(at);
 
2144
                                        return(NULL);
 
2145
                                }
 
2146
                                seen_desc = 1;
 
2147
                                parse_whsp(&ss);
 
2148
                                kind = get_token(&ss,&sval);
 
2149
                                if ( kind != TK_QDSTRING ) {
 
2150
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2151
                                        *errp = ss;
 
2152
                                        LDAP_FREE(sval);
 
2153
                                        ldap_attributetype_free(at);
 
2154
                                        return NULL;
 
2155
                                }
 
2156
                                at->at_desc = sval;
 
2157
                                parse_whsp(&ss);
 
2158
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
2159
                                LDAP_FREE(sval);
 
2160
                                if ( seen_obsolete ) {
 
2161
                                        *code = LDAP_SCHERR_DUPOPT;
 
2162
                                        *errp = ss;
 
2163
                                        ldap_attributetype_free(at);
 
2164
                                        return(NULL);
 
2165
                                }
 
2166
                                seen_obsolete = 1;
 
2167
                                at->at_obsolete = LDAP_SCHEMA_YES;
 
2168
                                parse_whsp(&ss);
 
2169
                        } else if ( !strcasecmp(sval,"SUP") ) {
 
2170
                                LDAP_FREE(sval);
 
2171
                                if ( seen_sup ) {
 
2172
                                        *code = LDAP_SCHERR_DUPOPT;
 
2173
                                        *errp = ss;
 
2174
                                        ldap_attributetype_free(at);
 
2175
                                        return(NULL);
 
2176
                                }
 
2177
                                seen_sup = 1;
 
2178
                                at->at_sup_oid = parse_woid(&ss,code);
 
2179
                                if ( !at->at_sup_oid ) {
 
2180
                                        *errp = ss;
 
2181
                                        ldap_attributetype_free(at);
 
2182
                                        return NULL;
 
2183
                                }
 
2184
                        } else if ( !strcasecmp(sval,"EQUALITY") ) {
 
2185
                                LDAP_FREE(sval);
 
2186
                                if ( seen_equality ) {
 
2187
                                        *code = LDAP_SCHERR_DUPOPT;
 
2188
                                        *errp = ss;
 
2189
                                        ldap_attributetype_free(at);
 
2190
                                        return(NULL);
 
2191
                                }
 
2192
                                seen_equality = 1;
 
2193
                                at->at_equality_oid = parse_woid(&ss,code);
 
2194
                                if ( !at->at_equality_oid ) {
 
2195
                                        *errp = ss;
 
2196
                                        ldap_attributetype_free(at);
 
2197
                                        return NULL;
 
2198
                                }
 
2199
                        } else if ( !strcasecmp(sval,"ORDERING") ) {
 
2200
                                LDAP_FREE(sval);
 
2201
                                if ( seen_ordering ) {
 
2202
                                        *code = LDAP_SCHERR_DUPOPT;
 
2203
                                        *errp = ss;
 
2204
                                        ldap_attributetype_free(at);
 
2205
                                        return(NULL);
 
2206
                                }
 
2207
                                seen_ordering = 1;
 
2208
                                at->at_ordering_oid = parse_woid(&ss,code);
 
2209
                                if ( !at->at_ordering_oid ) {
 
2210
                                        *errp = ss;
 
2211
                                        ldap_attributetype_free(at);
 
2212
                                        return NULL;
 
2213
                                }
 
2214
                        } else if ( !strcasecmp(sval,"SUBSTR") ) {
 
2215
                                LDAP_FREE(sval);
 
2216
                                if ( seen_substr ) {
 
2217
                                        *code = LDAP_SCHERR_DUPOPT;
 
2218
                                        *errp = ss;
 
2219
                                        ldap_attributetype_free(at);
 
2220
                                        return(NULL);
 
2221
                                }
 
2222
                                seen_substr = 1;
 
2223
                                at->at_substr_oid = parse_woid(&ss,code);
 
2224
                                if ( !at->at_substr_oid ) {
 
2225
                                        *errp = ss;
 
2226
                                        ldap_attributetype_free(at);
 
2227
                                        return NULL;
 
2228
                                }
 
2229
                        } else if ( !strcasecmp(sval,"SYNTAX") ) {
 
2230
                                LDAP_FREE(sval);
 
2231
                                if ( seen_syntax ) {
 
2232
                                        *code = LDAP_SCHERR_DUPOPT;
 
2233
                                        *errp = ss;
 
2234
                                        ldap_attributetype_free(at);
 
2235
                                        return(NULL);
 
2236
                                }
 
2237
                                seen_syntax = 1;
 
2238
                                parse_whsp(&ss);
 
2239
                                savepos = ss;
 
2240
                                at->at_syntax_oid =
 
2241
                                        parse_noidlen(&ss,
 
2242
                                                      code,
 
2243
                                                      &at->at_syntax_len,
 
2244
                                                      flags);
 
2245
                                if ( !at->at_syntax_oid ) {
 
2246
                                    if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
 
2247
                                        kind = get_token(&ss,&sval);
 
2248
                                        if (kind == TK_BAREWORD)
 
2249
                                        {
 
2250
                                            char *sp = strchr(sval, '{');
 
2251
                                            at->at_syntax_oid = sval;
 
2252
                                            if (sp)
 
2253
                                            {
 
2254
                                                *sp++ = 0;
 
2255
                                                at->at_syntax_len = atoi(sp);
 
2256
                                                while ( LDAP_DIGIT(*sp) )
 
2257
                                                        sp++;
 
2258
                                                if ( *sp != '}' ) {
 
2259
                                                    *code = LDAP_SCHERR_UNEXPTOKEN;
 
2260
                                                    *errp = ss;
 
2261
                                                    ldap_attributetype_free(at);
 
2262
                                                    return NULL;
 
2263
                                                }
 
2264
                                            }
 
2265
                                        }
 
2266
                                    } else {
 
2267
                                        *errp = ss;
 
2268
                                        ldap_attributetype_free(at);
 
2269
                                        return NULL;
 
2270
                                    }
 
2271
                                }
 
2272
                                parse_whsp(&ss);
 
2273
                        } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) {
 
2274
                                LDAP_FREE(sval);
 
2275
                                if ( at->at_single_value ) {
 
2276
                                        *code = LDAP_SCHERR_DUPOPT;
 
2277
                                        *errp = ss;
 
2278
                                        ldap_attributetype_free(at);
 
2279
                                        return(NULL);
 
2280
                                }
 
2281
                                at->at_single_value = LDAP_SCHEMA_YES;
 
2282
                                parse_whsp(&ss);
 
2283
                        } else if ( !strcasecmp(sval,"COLLECTIVE") ) {
 
2284
                                LDAP_FREE(sval);
 
2285
                                if ( at->at_collective ) {
 
2286
                                        *code = LDAP_SCHERR_DUPOPT;
 
2287
                                        *errp = ss;
 
2288
                                        ldap_attributetype_free(at);
 
2289
                                        return(NULL);
 
2290
                                }
 
2291
                                at->at_collective = LDAP_SCHEMA_YES;
 
2292
                                parse_whsp(&ss);
 
2293
                        } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) {
 
2294
                                LDAP_FREE(sval);
 
2295
                                if ( at->at_no_user_mod ) {
 
2296
                                        *code = LDAP_SCHERR_DUPOPT;
 
2297
                                        *errp = ss;
 
2298
                                        ldap_attributetype_free(at);
 
2299
                                        return(NULL);
 
2300
                                }
 
2301
                                at->at_no_user_mod = LDAP_SCHEMA_YES;
 
2302
                                parse_whsp(&ss);
 
2303
                        } else if ( !strcasecmp(sval,"USAGE") ) {
 
2304
                                LDAP_FREE(sval);
 
2305
                                if ( seen_usage ) {
 
2306
                                        *code = LDAP_SCHERR_DUPOPT;
 
2307
                                        *errp = ss;
 
2308
                                        ldap_attributetype_free(at);
 
2309
                                        return(NULL);
 
2310
                                }
 
2311
                                seen_usage = 1;
 
2312
                                parse_whsp(&ss);
 
2313
                                kind = get_token(&ss,&sval);
 
2314
                                if ( kind != TK_BAREWORD ) {
 
2315
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2316
                                        *errp = ss;
 
2317
                                        LDAP_FREE(sval);
 
2318
                                        ldap_attributetype_free(at);
 
2319
                                        return NULL;
 
2320
                                }
 
2321
                                if ( !strcasecmp(sval,"userApplications") )
 
2322
                                        at->at_usage =
 
2323
                                            LDAP_SCHEMA_USER_APPLICATIONS;
 
2324
                                else if ( !strcasecmp(sval,"directoryOperation") )
 
2325
                                        at->at_usage =
 
2326
                                            LDAP_SCHEMA_DIRECTORY_OPERATION;
 
2327
                                else if ( !strcasecmp(sval,"distributedOperation") )
 
2328
                                        at->at_usage =
 
2329
                                            LDAP_SCHEMA_DISTRIBUTED_OPERATION;
 
2330
                                else if ( !strcasecmp(sval,"dSAOperation") )
 
2331
                                        at->at_usage =
 
2332
                                            LDAP_SCHEMA_DSA_OPERATION;
 
2333
                                else {
 
2334
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2335
                                        *errp = ss;
 
2336
                                        LDAP_FREE(sval);
 
2337
                                        ldap_attributetype_free(at);
 
2338
                                        return NULL;
 
2339
                                }
 
2340
                                LDAP_FREE(sval);
 
2341
                                parse_whsp(&ss);
 
2342
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
2343
                                /* Should be parse_qdstrings */
 
2344
                                ext_vals = parse_qdescrs(&ss, code);
 
2345
                                if ( !ext_vals ) {
 
2346
                                        *errp = ss;
 
2347
                                        ldap_attributetype_free(at);
 
2348
                                        return NULL;
 
2349
                                }
 
2350
                                if ( add_extension(&at->at_extensions,
 
2351
                                                    sval, ext_vals) ) {
 
2352
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
2353
                                        *errp = ss;
 
2354
                                        LDAP_FREE(sval);
 
2355
                                        ldap_attributetype_free(at);
 
2356
                                        return NULL;
 
2357
                                }
 
2358
                        } else {
 
2359
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
2360
                                *errp = ss;
 
2361
                                LDAP_FREE(sval);
 
2362
                                ldap_attributetype_free(at);
 
2363
                                return NULL;
 
2364
                        }
 
2365
                        break;
 
2366
                default:
 
2367
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2368
                        *errp = ss;
 
2369
                        LDAP_FREE(sval);
 
2370
                        ldap_attributetype_free(at);
 
2371
                        return NULL;
 
2372
                }
 
2373
        }
 
2374
}
 
2375
 
 
2376
void
 
2377
ldap_objectclass_free(LDAPObjectClass * oc)
 
2378
{
 
2379
        LDAP_FREE(oc->oc_oid);
 
2380
        if (oc->oc_names) LDAP_VFREE(oc->oc_names);
 
2381
        if (oc->oc_desc) LDAP_FREE(oc->oc_desc);
 
2382
        if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids);
 
2383
        if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must);
 
2384
        if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may);
 
2385
        free_extensions(oc->oc_extensions);
 
2386
        LDAP_FREE(oc);
 
2387
}
 
2388
 
 
2389
LDAPObjectClass *
 
2390
ldap_str2objectclass( LDAP_CONST char * s,
 
2391
        int * code,
 
2392
        LDAP_CONST char ** errp,
 
2393
        LDAP_CONST unsigned flags )
 
2394
{
 
2395
        tk_t kind;
 
2396
        const char * ss = s;
 
2397
        char * sval;
 
2398
        int seen_name = 0;
 
2399
        int seen_desc = 0;
 
2400
        int seen_obsolete = 0;
 
2401
        int seen_sup = 0;
 
2402
        int seen_kind = 0;
 
2403
        int seen_must = 0;
 
2404
        int seen_may = 0;
 
2405
        LDAPObjectClass * oc;
 
2406
        char ** ext_vals;
 
2407
        const char * savepos;
 
2408
 
 
2409
        if ( !s ) {
 
2410
                *code = LDAP_SCHERR_EMPTY;
 
2411
                *errp = "";
 
2412
                return NULL;
 
2413
        }
 
2414
 
 
2415
        *errp = s;
 
2416
        oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
 
2417
 
 
2418
        if ( !oc ) {
 
2419
                *code = LDAP_SCHERR_OUTOFMEM;
 
2420
                return NULL;
 
2421
        }
 
2422
        oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
 
2423
 
 
2424
        kind = get_token(&ss,&sval);
 
2425
        if ( kind != TK_LEFTPAREN ) {
 
2426
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
2427
                LDAP_FREE(sval);
 
2428
                ldap_objectclass_free(oc);
 
2429
                return NULL;
 
2430
        }
 
2431
 
 
2432
        /*
 
2433
         * Definitions MUST begin with an OID in the numericoid format.
 
2434
         * However, this routine is used by clients to parse the response
 
2435
         * from servers and very well known servers will provide an OID
 
2436
         * in the wrong format or even no OID at all.  We do our best to
 
2437
         * extract info from those servers.
 
2438
         */
 
2439
        parse_whsp(&ss);
 
2440
        savepos = ss;
 
2441
        oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0);
 
2442
        if ( !oc->oc_oid ) {
 
2443
                if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
 
2444
                        /* Backtracking */
 
2445
                        ss = savepos;
 
2446
                        kind = get_token(&ss,&sval);
 
2447
                        if ( kind == TK_BAREWORD ) {
 
2448
                                if ( !strcasecmp(sval, "NAME") ||
 
2449
                                     !strcasecmp(sval, "DESC") ||
 
2450
                                     !strcasecmp(sval, "OBSOLETE") ||
 
2451
                                     !strcasecmp(sval, "SUP") ||
 
2452
                                     !strcasecmp(sval, "ABSTRACT") ||
 
2453
                                     !strcasecmp(sval, "STRUCTURAL") ||
 
2454
                                     !strcasecmp(sval, "AUXILIARY") ||
 
2455
                                     !strcasecmp(sval, "MUST") ||
 
2456
                                     !strcasecmp(sval, "MAY") ||
 
2457
                                     !strncasecmp(sval, "X-", 2) ) {
 
2458
                                        /* Missing OID, backtrack */
 
2459
                                        ss = savepos;
 
2460
                                } else if ( flags &
 
2461
                                        LDAP_SCHEMA_ALLOW_OID_MACRO ) {
 
2462
                                        /* Non-numerical OID, ignore */
 
2463
                                        int len = ss-savepos;
 
2464
                                        oc->oc_oid = LDAP_MALLOC(len+1);
 
2465
                                        strncpy(oc->oc_oid, savepos, len);
 
2466
                                        oc->oc_oid[len] = 0;
 
2467
                                }
 
2468
                        }
 
2469
                        LDAP_FREE(sval);
 
2470
                        *code = 0;
 
2471
                } else {
 
2472
                        *errp = ss;
 
2473
                        ldap_objectclass_free(oc);
 
2474
                        return NULL;
 
2475
                }
 
2476
        }
 
2477
        parse_whsp(&ss);
 
2478
 
 
2479
        /*
 
2480
         * Beyond this point we will be liberal an accept the items
 
2481
         * in any order.
 
2482
         */
 
2483
        while (1) {
 
2484
                kind = get_token(&ss,&sval);
 
2485
                switch (kind) {
 
2486
                case TK_EOS:
 
2487
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
2488
                        *errp = EndOfInput;
 
2489
                        ldap_objectclass_free(oc);
 
2490
                        return NULL;
 
2491
                case TK_RIGHTPAREN:
 
2492
                        return oc;
 
2493
                case TK_BAREWORD:
 
2494
                        if ( !strcasecmp(sval,"NAME") ) {
 
2495
                                LDAP_FREE(sval);
 
2496
                                if ( seen_name ) {
 
2497
                                        *code = LDAP_SCHERR_DUPOPT;
 
2498
                                        *errp = ss;
 
2499
                                        ldap_objectclass_free(oc);
 
2500
                                        return(NULL);
 
2501
                                }
 
2502
                                seen_name = 1;
 
2503
                                oc->oc_names = parse_qdescrs(&ss,code);
 
2504
                                if ( !oc->oc_names ) {
 
2505
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
2506
                                                *code = LDAP_SCHERR_BADNAME;
 
2507
                                        *errp = ss;
 
2508
                                        ldap_objectclass_free(oc);
 
2509
                                        return NULL;
 
2510
                                }
 
2511
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
2512
                                LDAP_FREE(sval);
 
2513
                                if ( seen_desc ) {
 
2514
                                        *code = LDAP_SCHERR_DUPOPT;
 
2515
                                        *errp = ss;
 
2516
                                        ldap_objectclass_free(oc);
 
2517
                                        return(NULL);
 
2518
                                }
 
2519
                                seen_desc = 1;
 
2520
                                parse_whsp(&ss);
 
2521
                                kind = get_token(&ss,&sval);
 
2522
                                if ( kind != TK_QDSTRING ) {
 
2523
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2524
                                        *errp = ss;
 
2525
                                        LDAP_FREE(sval);
 
2526
                                        ldap_objectclass_free(oc);
 
2527
                                        return NULL;
 
2528
                                }
 
2529
                                oc->oc_desc = sval;
 
2530
                                parse_whsp(&ss);
 
2531
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
2532
                                LDAP_FREE(sval);
 
2533
                                if ( seen_obsolete ) {
 
2534
                                        *code = LDAP_SCHERR_DUPOPT;
 
2535
                                        *errp = ss;
 
2536
                                        ldap_objectclass_free(oc);
 
2537
                                        return(NULL);
 
2538
                                }
 
2539
                                seen_obsolete = 1;
 
2540
                                oc->oc_obsolete = LDAP_SCHEMA_YES;
 
2541
                                parse_whsp(&ss);
 
2542
                        } else if ( !strcasecmp(sval,"SUP") ) {
 
2543
                                LDAP_FREE(sval);
 
2544
                                if ( seen_sup ) {
 
2545
                                        *code = LDAP_SCHERR_DUPOPT;
 
2546
                                        *errp = ss;
 
2547
                                        ldap_objectclass_free(oc);
 
2548
                                        return(NULL);
 
2549
                                }
 
2550
                                seen_sup = 1;
 
2551
                                oc->oc_sup_oids = parse_oids(&ss,
 
2552
                                                             code,
 
2553
                                                             flags);
 
2554
                                if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) {
 
2555
                                        *errp = ss;
 
2556
                                        ldap_objectclass_free(oc);
 
2557
                                        return NULL;
 
2558
                                }
 
2559
                                *code = 0;
 
2560
                        } else if ( !strcasecmp(sval,"ABSTRACT") ) {
 
2561
                                LDAP_FREE(sval);
 
2562
                                if ( seen_kind ) {
 
2563
                                        *code = LDAP_SCHERR_DUPOPT;
 
2564
                                        *errp = ss;
 
2565
                                        ldap_objectclass_free(oc);
 
2566
                                        return(NULL);
 
2567
                                }
 
2568
                                seen_kind = 1;
 
2569
                                oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
 
2570
                                parse_whsp(&ss);
 
2571
                        } else if ( !strcasecmp(sval,"STRUCTURAL") ) {
 
2572
                                LDAP_FREE(sval);
 
2573
                                if ( seen_kind ) {
 
2574
                                        *code = LDAP_SCHERR_DUPOPT;
 
2575
                                        *errp = ss;
 
2576
                                        ldap_objectclass_free(oc);
 
2577
                                        return(NULL);
 
2578
                                }
 
2579
                                seen_kind = 1;
 
2580
                                oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
 
2581
                                parse_whsp(&ss);
 
2582
                        } else if ( !strcasecmp(sval,"AUXILIARY") ) {
 
2583
                                LDAP_FREE(sval);
 
2584
                                if ( seen_kind ) {
 
2585
                                        *code = LDAP_SCHERR_DUPOPT;
 
2586
                                        *errp = ss;
 
2587
                                        ldap_objectclass_free(oc);
 
2588
                                        return(NULL);
 
2589
                                }
 
2590
                                seen_kind = 1;
 
2591
                                oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
 
2592
                                parse_whsp(&ss);
 
2593
                        } else if ( !strcasecmp(sval,"MUST") ) {
 
2594
                                LDAP_FREE(sval);
 
2595
                                if ( seen_must ) {
 
2596
                                        *code = LDAP_SCHERR_DUPOPT;
 
2597
                                        *errp = ss;
 
2598
                                        ldap_objectclass_free(oc);
 
2599
                                        return(NULL);
 
2600
                                }
 
2601
                                seen_must = 1;
 
2602
                                oc->oc_at_oids_must = parse_oids(&ss,code,0);
 
2603
                                if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) {
 
2604
                                        *errp = ss;
 
2605
                                        ldap_objectclass_free(oc);
 
2606
                                        return NULL;
 
2607
                                }
 
2608
                                *code = 0;
 
2609
                                parse_whsp(&ss);
 
2610
                        } else if ( !strcasecmp(sval,"MAY") ) {
 
2611
                                LDAP_FREE(sval);
 
2612
                                if ( seen_may ) {
 
2613
                                        *code = LDAP_SCHERR_DUPOPT;
 
2614
                                        *errp = ss;
 
2615
                                        ldap_objectclass_free(oc);
 
2616
                                        return(NULL);
 
2617
                                }
 
2618
                                seen_may = 1;
 
2619
                                oc->oc_at_oids_may = parse_oids(&ss,code,0);
 
2620
                                if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) {
 
2621
                                        *errp = ss;
 
2622
                                        ldap_objectclass_free(oc);
 
2623
                                        return NULL;
 
2624
                                }
 
2625
                                *code = 0;
 
2626
                                parse_whsp(&ss);
 
2627
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
2628
                                /* Should be parse_qdstrings */
 
2629
                                ext_vals = parse_qdescrs(&ss, code);
 
2630
                                *code = 0;
 
2631
                                if ( !ext_vals ) {
 
2632
                                        *errp = ss;
 
2633
                                        ldap_objectclass_free(oc);
 
2634
                                        return NULL;
 
2635
                                }
 
2636
                                if ( add_extension(&oc->oc_extensions,
 
2637
                                                    sval, ext_vals) ) {
 
2638
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
2639
                                        *errp = ss;
 
2640
                                        LDAP_FREE(sval);
 
2641
                                        ldap_objectclass_free(oc);
 
2642
                                        return NULL;
 
2643
                                }
 
2644
                        } else {
 
2645
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
2646
                                *errp = ss;
 
2647
                                LDAP_FREE(sval);
 
2648
                                ldap_objectclass_free(oc);
 
2649
                                return NULL;
 
2650
                        }
 
2651
                        break;
 
2652
                default:
 
2653
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2654
                        *errp = ss;
 
2655
                        LDAP_FREE(sval);
 
2656
                        ldap_objectclass_free(oc);
 
2657
                        return NULL;
 
2658
                }
 
2659
        }
 
2660
}
 
2661
 
 
2662
void
 
2663
ldap_contentrule_free(LDAPContentRule * cr)
 
2664
{
 
2665
        LDAP_FREE(cr->cr_oid);
 
2666
        if (cr->cr_names) LDAP_VFREE(cr->cr_names);
 
2667
        if (cr->cr_desc) LDAP_FREE(cr->cr_desc);
 
2668
        if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux);
 
2669
        if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must);
 
2670
        if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may);
 
2671
        if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not);
 
2672
        free_extensions(cr->cr_extensions);
 
2673
        LDAP_FREE(cr);
 
2674
}
 
2675
 
 
2676
LDAPContentRule *
 
2677
ldap_str2contentrule( LDAP_CONST char * s,
 
2678
        int * code,
 
2679
        LDAP_CONST char ** errp,
 
2680
        LDAP_CONST unsigned flags )
 
2681
{
 
2682
        tk_t kind;
 
2683
        const char * ss = s;
 
2684
        char * sval;
 
2685
        int seen_name = 0;
 
2686
        int seen_desc = 0;
 
2687
        int seen_obsolete = 0;
 
2688
        int seen_aux = 0;
 
2689
        int seen_must = 0;
 
2690
        int seen_may = 0;
 
2691
        int seen_not = 0;
 
2692
        LDAPContentRule * cr;
 
2693
        char ** ext_vals;
 
2694
        const char * savepos;
 
2695
 
 
2696
        if ( !s ) {
 
2697
                *code = LDAP_SCHERR_EMPTY;
 
2698
                *errp = "";
 
2699
                return NULL;
 
2700
        }
 
2701
 
 
2702
        *errp = s;
 
2703
        cr = LDAP_CALLOC(1,sizeof(LDAPContentRule));
 
2704
 
 
2705
        if ( !cr ) {
 
2706
                *code = LDAP_SCHERR_OUTOFMEM;
 
2707
                return NULL;
 
2708
        }
 
2709
 
 
2710
        kind = get_token(&ss,&sval);
 
2711
        if ( kind != TK_LEFTPAREN ) {
 
2712
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
2713
                LDAP_FREE(sval);
 
2714
                ldap_contentrule_free(cr);
 
2715
                return NULL;
 
2716
        }
 
2717
 
 
2718
        /*
 
2719
         * Definitions MUST begin with an OID in the numericoid format.
 
2720
         */
 
2721
        parse_whsp(&ss);
 
2722
        savepos = ss;
 
2723
        cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0);
 
2724
        if ( !cr->cr_oid ) {
 
2725
                if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
 
2726
                        /* Backtracking */
 
2727
                        ss = savepos;
 
2728
                        kind = get_token(&ss,&sval);
 
2729
                        if ( kind == TK_BAREWORD ) {
 
2730
                                if ( !strcasecmp(sval, "NAME") ||
 
2731
                                     !strcasecmp(sval, "DESC") ||
 
2732
                                     !strcasecmp(sval, "OBSOLETE") ||
 
2733
                                     !strcasecmp(sval, "AUX") ||
 
2734
                                     !strcasecmp(sval, "MUST") ||
 
2735
                                     !strcasecmp(sval, "MAY") ||
 
2736
                                     !strcasecmp(sval, "NOT") ||
 
2737
                                     !strncasecmp(sval, "X-", 2) ) {
 
2738
                                        /* Missing OID, backtrack */
 
2739
                                        ss = savepos;
 
2740
                                } else if ( flags &
 
2741
                                        LDAP_SCHEMA_ALLOW_OID_MACRO ) {
 
2742
                                        /* Non-numerical OID, ignore */
 
2743
                                        int len = ss-savepos;
 
2744
                                        cr->cr_oid = LDAP_MALLOC(len+1);
 
2745
                                        strncpy(cr->cr_oid, savepos, len);
 
2746
                                        cr->cr_oid[len] = 0;
 
2747
                                }
 
2748
                        }
 
2749
                        LDAP_FREE(sval);
 
2750
                } else {
 
2751
                        *errp = ss;
 
2752
                        ldap_contentrule_free(cr);
 
2753
                        return NULL;
 
2754
                }
 
2755
        }
 
2756
        parse_whsp(&ss);
 
2757
 
 
2758
        /*
 
2759
         * Beyond this point we will be liberal an accept the items
 
2760
         * in any order.
 
2761
         */
 
2762
        while (1) {
 
2763
                kind = get_token(&ss,&sval);
 
2764
                switch (kind) {
 
2765
                case TK_EOS:
 
2766
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
2767
                        *errp = EndOfInput;
 
2768
                        ldap_contentrule_free(cr);
 
2769
                        return NULL;
 
2770
                case TK_RIGHTPAREN:
 
2771
                        return cr;
 
2772
                case TK_BAREWORD:
 
2773
                        if ( !strcasecmp(sval,"NAME") ) {
 
2774
                                LDAP_FREE(sval);
 
2775
                                if ( seen_name ) {
 
2776
                                        *code = LDAP_SCHERR_DUPOPT;
 
2777
                                        *errp = ss;
 
2778
                                        ldap_contentrule_free(cr);
 
2779
                                        return(NULL);
 
2780
                                }
 
2781
                                seen_name = 1;
 
2782
                                cr->cr_names = parse_qdescrs(&ss,code);
 
2783
                                if ( !cr->cr_names ) {
 
2784
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
2785
                                                *code = LDAP_SCHERR_BADNAME;
 
2786
                                        *errp = ss;
 
2787
                                        ldap_contentrule_free(cr);
 
2788
                                        return NULL;
 
2789
                                }
 
2790
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
2791
                                LDAP_FREE(sval);
 
2792
                                if ( seen_desc ) {
 
2793
                                        *code = LDAP_SCHERR_DUPOPT;
 
2794
                                        *errp = ss;
 
2795
                                        ldap_contentrule_free(cr);
 
2796
                                        return(NULL);
 
2797
                                }
 
2798
                                seen_desc = 1;
 
2799
                                parse_whsp(&ss);
 
2800
                                kind = get_token(&ss,&sval);
 
2801
                                if ( kind != TK_QDSTRING ) {
 
2802
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2803
                                        *errp = ss;
 
2804
                                        LDAP_FREE(sval);
 
2805
                                        ldap_contentrule_free(cr);
 
2806
                                        return NULL;
 
2807
                                }
 
2808
                                cr->cr_desc = sval;
 
2809
                                parse_whsp(&ss);
 
2810
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
2811
                                LDAP_FREE(sval);
 
2812
                                if ( seen_obsolete ) {
 
2813
                                        *code = LDAP_SCHERR_DUPOPT;
 
2814
                                        *errp = ss;
 
2815
                                        ldap_contentrule_free(cr);
 
2816
                                        return(NULL);
 
2817
                                }
 
2818
                                seen_obsolete = 1;
 
2819
                                cr->cr_obsolete = LDAP_SCHEMA_YES;
 
2820
                                parse_whsp(&ss);
 
2821
                        } else if ( !strcasecmp(sval,"AUX") ) {
 
2822
                                LDAP_FREE(sval);
 
2823
                                if ( seen_aux ) {
 
2824
                                        *code = LDAP_SCHERR_DUPOPT;
 
2825
                                        *errp = ss;
 
2826
                                        ldap_contentrule_free(cr);
 
2827
                                        return(NULL);
 
2828
                                }
 
2829
                                seen_aux = 1;
 
2830
                                cr->cr_oc_oids_aux = parse_oids(&ss,code,0);
 
2831
                                if ( !cr->cr_oc_oids_aux ) {
 
2832
                                        *errp = ss;
 
2833
                                        ldap_contentrule_free(cr);
 
2834
                                        return NULL;
 
2835
                                }
 
2836
                                parse_whsp(&ss);
 
2837
                        } else if ( !strcasecmp(sval,"MUST") ) {
 
2838
                                LDAP_FREE(sval);
 
2839
                                if ( seen_must ) {
 
2840
                                        *code = LDAP_SCHERR_DUPOPT;
 
2841
                                        *errp = ss;
 
2842
                                        ldap_contentrule_free(cr);
 
2843
                                        return(NULL);
 
2844
                                }
 
2845
                                seen_must = 1;
 
2846
                                cr->cr_at_oids_must = parse_oids(&ss,code,0);
 
2847
                                if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) {
 
2848
                                        *errp = ss;
 
2849
                                        ldap_contentrule_free(cr);
 
2850
                                        return NULL;
 
2851
                                }
 
2852
                                parse_whsp(&ss);
 
2853
                        } else if ( !strcasecmp(sval,"MAY") ) {
 
2854
                                LDAP_FREE(sval);
 
2855
                                if ( seen_may ) {
 
2856
                                        *code = LDAP_SCHERR_DUPOPT;
 
2857
                                        *errp = ss;
 
2858
                                        ldap_contentrule_free(cr);
 
2859
                                        return(NULL);
 
2860
                                }
 
2861
                                seen_may = 1;
 
2862
                                cr->cr_at_oids_may = parse_oids(&ss,code,0);
 
2863
                                if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) {
 
2864
                                        *errp = ss;
 
2865
                                        ldap_contentrule_free(cr);
 
2866
                                        return NULL;
 
2867
                                }
 
2868
                                parse_whsp(&ss);
 
2869
                        } else if ( !strcasecmp(sval,"NOT") ) {
 
2870
                                LDAP_FREE(sval);
 
2871
                                if ( seen_not ) {
 
2872
                                        *code = LDAP_SCHERR_DUPOPT;
 
2873
                                        *errp = ss;
 
2874
                                        ldap_contentrule_free(cr);
 
2875
                                        return(NULL);
 
2876
                                }
 
2877
                                seen_not = 1;
 
2878
                                cr->cr_at_oids_not = parse_oids(&ss,code,0);
 
2879
                                if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) {
 
2880
                                        *errp = ss;
 
2881
                                        ldap_contentrule_free(cr);
 
2882
                                        return NULL;
 
2883
                                }
 
2884
                                parse_whsp(&ss);
 
2885
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
2886
                                /* Should be parse_qdstrings */
 
2887
                                ext_vals = parse_qdescrs(&ss, code);
 
2888
                                if ( !ext_vals ) {
 
2889
                                        *errp = ss;
 
2890
                                        ldap_contentrule_free(cr);
 
2891
                                        return NULL;
 
2892
                                }
 
2893
                                if ( add_extension(&cr->cr_extensions,
 
2894
                                                    sval, ext_vals) ) {
 
2895
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
2896
                                        *errp = ss;
 
2897
                                        LDAP_FREE(sval);
 
2898
                                        ldap_contentrule_free(cr);
 
2899
                                        return NULL;
 
2900
                                }
 
2901
                        } else {
 
2902
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
2903
                                *errp = ss;
 
2904
                                LDAP_FREE(sval);
 
2905
                                ldap_contentrule_free(cr);
 
2906
                                return NULL;
 
2907
                        }
 
2908
                        break;
 
2909
                default:
 
2910
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
2911
                        *errp = ss;
 
2912
                        LDAP_FREE(sval);
 
2913
                        ldap_contentrule_free(cr);
 
2914
                        return NULL;
 
2915
                }
 
2916
        }
 
2917
}
 
2918
 
 
2919
void
 
2920
ldap_structurerule_free(LDAPStructureRule * sr)
 
2921
{
 
2922
        if (sr->sr_names) LDAP_VFREE(sr->sr_names);
 
2923
        if (sr->sr_desc) LDAP_FREE(sr->sr_desc);
 
2924
        if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform);
 
2925
        if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids);
 
2926
        free_extensions(sr->sr_extensions);
 
2927
        LDAP_FREE(sr);
 
2928
}
 
2929
 
 
2930
LDAPStructureRule *
 
2931
ldap_str2structurerule( LDAP_CONST char * s,
 
2932
        int * code,
 
2933
        LDAP_CONST char ** errp,
 
2934
        LDAP_CONST unsigned flags )
 
2935
{
 
2936
        tk_t kind;
 
2937
        int ret;
 
2938
        const char * ss = s;
 
2939
        char * sval;
 
2940
        int seen_name = 0;
 
2941
        int seen_desc = 0;
 
2942
        int seen_obsolete = 0;
 
2943
        int seen_nameform = 0;
 
2944
        LDAPStructureRule * sr;
 
2945
        char ** ext_vals;
 
2946
        const char * savepos;
 
2947
 
 
2948
        if ( !s ) {
 
2949
                *code = LDAP_SCHERR_EMPTY;
 
2950
                *errp = "";
 
2951
                return NULL;
 
2952
        }
 
2953
 
 
2954
        *errp = s;
 
2955
        sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule));
 
2956
 
 
2957
        if ( !sr ) {
 
2958
                *code = LDAP_SCHERR_OUTOFMEM;
 
2959
                return NULL;
 
2960
        }
 
2961
 
 
2962
        kind = get_token(&ss,&sval);
 
2963
        if ( kind != TK_LEFTPAREN ) {
 
2964
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
2965
                LDAP_FREE(sval);
 
2966
                ldap_structurerule_free(sr);
 
2967
                return NULL;
 
2968
        }
 
2969
 
 
2970
        /*
 
2971
         * Definitions MUST begin with a ruleid.
 
2972
         */
 
2973
        parse_whsp(&ss);
 
2974
        savepos = ss;
 
2975
        ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid);
 
2976
        if ( ret ) {
 
2977
                *errp = ss;
 
2978
                ldap_structurerule_free(sr);
 
2979
                return NULL;
 
2980
        }
 
2981
        parse_whsp(&ss);
 
2982
 
 
2983
        /*
 
2984
         * Beyond this point we will be liberal an accept the items
 
2985
         * in any order.
 
2986
         */
 
2987
        while (1) {
 
2988
                kind = get_token(&ss,&sval);
 
2989
                switch (kind) {
 
2990
                case TK_EOS:
 
2991
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
2992
                        *errp = EndOfInput;
 
2993
                        ldap_structurerule_free(sr);
 
2994
                        return NULL;
 
2995
                case TK_RIGHTPAREN:
 
2996
                        if( !seen_nameform ) {
 
2997
                                *code = LDAP_SCHERR_MISSING;
 
2998
                                ldap_structurerule_free(sr);
 
2999
                                return NULL;
 
3000
                        }
 
3001
                        return sr;
 
3002
                case TK_BAREWORD:
 
3003
                        if ( !strcasecmp(sval,"NAME") ) {
 
3004
                                LDAP_FREE(sval);
 
3005
                                if ( seen_name ) {
 
3006
                                        *code = LDAP_SCHERR_DUPOPT;
 
3007
                                        *errp = ss;
 
3008
                                        ldap_structurerule_free(sr);
 
3009
                                        return(NULL);
 
3010
                                }
 
3011
                                seen_name = 1;
 
3012
                                sr->sr_names = parse_qdescrs(&ss,code);
 
3013
                                if ( !sr->sr_names ) {
 
3014
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
3015
                                                *code = LDAP_SCHERR_BADNAME;
 
3016
                                        *errp = ss;
 
3017
                                        ldap_structurerule_free(sr);
 
3018
                                        return NULL;
 
3019
                                }
 
3020
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
3021
                                LDAP_FREE(sval);
 
3022
                                if ( seen_desc ) {
 
3023
                                        *code = LDAP_SCHERR_DUPOPT;
 
3024
                                        *errp = ss;
 
3025
                                        ldap_structurerule_free(sr);
 
3026
                                        return(NULL);
 
3027
                                }
 
3028
                                seen_desc = 1;
 
3029
                                parse_whsp(&ss);
 
3030
                                kind = get_token(&ss,&sval);
 
3031
                                if ( kind != TK_QDSTRING ) {
 
3032
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
3033
                                        *errp = ss;
 
3034
                                        LDAP_FREE(sval);
 
3035
                                        ldap_structurerule_free(sr);
 
3036
                                        return NULL;
 
3037
                                }
 
3038
                                sr->sr_desc = sval;
 
3039
                                parse_whsp(&ss);
 
3040
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
3041
                                LDAP_FREE(sval);
 
3042
                                if ( seen_obsolete ) {
 
3043
                                        *code = LDAP_SCHERR_DUPOPT;
 
3044
                                        *errp = ss;
 
3045
                                        ldap_structurerule_free(sr);
 
3046
                                        return(NULL);
 
3047
                                }
 
3048
                                seen_obsolete = 1;
 
3049
                                sr->sr_obsolete = LDAP_SCHEMA_YES;
 
3050
                                parse_whsp(&ss);
 
3051
                        } else if ( !strcasecmp(sval,"FORM") ) {
 
3052
                                LDAP_FREE(sval);
 
3053
                                if ( seen_nameform ) {
 
3054
                                        *code = LDAP_SCHERR_DUPOPT;
 
3055
                                        *errp = ss;
 
3056
                                        ldap_structurerule_free(sr);
 
3057
                                        return(NULL);
 
3058
                                }
 
3059
                                seen_nameform = 1;
 
3060
                                sr->sr_nameform = parse_woid(&ss,code);
 
3061
                                if ( !sr->sr_nameform ) {
 
3062
                                        *errp = ss;
 
3063
                                        ldap_structurerule_free(sr);
 
3064
                                        return NULL;
 
3065
                                }
 
3066
                                parse_whsp(&ss);
 
3067
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
3068
                                /* Should be parse_qdstrings */
 
3069
                                ext_vals = parse_qdescrs(&ss, code);
 
3070
                                if ( !ext_vals ) {
 
3071
                                        *errp = ss;
 
3072
                                        ldap_structurerule_free(sr);
 
3073
                                        return NULL;
 
3074
                                }
 
3075
                                if ( add_extension(&sr->sr_extensions,
 
3076
                                                    sval, ext_vals) ) {
 
3077
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
3078
                                        *errp = ss;
 
3079
                                        LDAP_FREE(sval);
 
3080
                                        ldap_structurerule_free(sr);
 
3081
                                        return NULL;
 
3082
                                }
 
3083
                        } else {
 
3084
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
3085
                                *errp = ss;
 
3086
                                LDAP_FREE(sval);
 
3087
                                ldap_structurerule_free(sr);
 
3088
                                return NULL;
 
3089
                        }
 
3090
                        break;
 
3091
                default:
 
3092
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
3093
                        *errp = ss;
 
3094
                        LDAP_FREE(sval);
 
3095
                        ldap_structurerule_free(sr);
 
3096
                        return NULL;
 
3097
                }
 
3098
        }
 
3099
}
 
3100
 
 
3101
void
 
3102
ldap_nameform_free(LDAPNameForm * nf)
 
3103
{
 
3104
        LDAP_FREE(nf->nf_oid);
 
3105
        if (nf->nf_names) LDAP_VFREE(nf->nf_names);
 
3106
        if (nf->nf_desc) LDAP_FREE(nf->nf_desc);
 
3107
        if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass);
 
3108
        if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must);
 
3109
        if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may);
 
3110
        free_extensions(nf->nf_extensions);
 
3111
        LDAP_FREE(nf);
 
3112
}
 
3113
 
 
3114
LDAPNameForm *
 
3115
ldap_str2nameform( LDAP_CONST char * s,
 
3116
        int * code,
 
3117
        LDAP_CONST char ** errp,
 
3118
        LDAP_CONST unsigned flags )
 
3119
{
 
3120
        tk_t kind;
 
3121
        const char * ss = s;
 
3122
        char * sval;
 
3123
        int seen_name = 0;
 
3124
        int seen_desc = 0;
 
3125
        int seen_obsolete = 0;
 
3126
        int seen_class = 0;
 
3127
        int seen_must = 0;
 
3128
        int seen_may = 0;
 
3129
        LDAPNameForm * nf;
 
3130
        char ** ext_vals;
 
3131
        const char * savepos;
 
3132
 
 
3133
        if ( !s ) {
 
3134
                *code = LDAP_SCHERR_EMPTY;
 
3135
                *errp = "";
 
3136
                return NULL;
 
3137
        }
 
3138
 
 
3139
        *errp = s;
 
3140
        nf = LDAP_CALLOC(1,sizeof(LDAPNameForm));
 
3141
 
 
3142
        if ( !nf ) {
 
3143
                *code = LDAP_SCHERR_OUTOFMEM;
 
3144
                return NULL;
 
3145
        }
 
3146
 
 
3147
        kind = get_token(&ss,&sval);
 
3148
        if ( kind != TK_LEFTPAREN ) {
 
3149
                *code = LDAP_SCHERR_NOLEFTPAREN;
 
3150
                LDAP_FREE(sval);
 
3151
                ldap_nameform_free(nf);
 
3152
                return NULL;
 
3153
        }
 
3154
 
 
3155
        /*
 
3156
         * Definitions MUST begin with an OID in the numericoid format.
 
3157
         * However, this routine is used by clients to parse the response
 
3158
         * from servers and very well known servers will provide an OID
 
3159
         * in the wrong format or even no OID at all.  We do our best to
 
3160
         * extract info from those servers.
 
3161
         */
 
3162
        parse_whsp(&ss);
 
3163
        savepos = ss;
 
3164
        nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0);
 
3165
        if ( !nf->nf_oid ) {
 
3166
                *errp = ss;
 
3167
                ldap_nameform_free(nf);
 
3168
                return NULL;
 
3169
        }
 
3170
        parse_whsp(&ss);
 
3171
 
 
3172
        /*
 
3173
         * Beyond this point we will be liberal an accept the items
 
3174
         * in any order.
 
3175
         */
 
3176
        while (1) {
 
3177
                kind = get_token(&ss,&sval);
 
3178
                switch (kind) {
 
3179
                case TK_EOS:
 
3180
                        *code = LDAP_SCHERR_NORIGHTPAREN;
 
3181
                        *errp = EndOfInput;
 
3182
                        ldap_nameform_free(nf);
 
3183
                        return NULL;
 
3184
                case TK_RIGHTPAREN:
 
3185
                        if( !seen_class || !seen_must ) {
 
3186
                                *code = LDAP_SCHERR_MISSING;
 
3187
                                ldap_nameform_free(nf);
 
3188
                                return NULL;
 
3189
                        }
 
3190
                        return nf;
 
3191
                case TK_BAREWORD:
 
3192
                        if ( !strcasecmp(sval,"NAME") ) {
 
3193
                                LDAP_FREE(sval);
 
3194
                                if ( seen_name ) {
 
3195
                                        *code = LDAP_SCHERR_DUPOPT;
 
3196
                                        *errp = ss;
 
3197
                                        ldap_nameform_free(nf);
 
3198
                                        return(NULL);
 
3199
                                }
 
3200
                                seen_name = 1;
 
3201
                                nf->nf_names = parse_qdescrs(&ss,code);
 
3202
                                if ( !nf->nf_names ) {
 
3203
                                        if ( *code != LDAP_SCHERR_OUTOFMEM )
 
3204
                                                *code = LDAP_SCHERR_BADNAME;
 
3205
                                        *errp = ss;
 
3206
                                        ldap_nameform_free(nf);
 
3207
                                        return NULL;
 
3208
                                }
 
3209
                        } else if ( !strcasecmp(sval,"DESC") ) {
 
3210
                                LDAP_FREE(sval);
 
3211
                                if ( seen_desc ) {
 
3212
                                        *code = LDAP_SCHERR_DUPOPT;
 
3213
                                        *errp = ss;
 
3214
                                        ldap_nameform_free(nf);
 
3215
                                        return(NULL);
 
3216
                                }
 
3217
                                seen_desc = 1;
 
3218
                                parse_whsp(&ss);
 
3219
                                kind = get_token(&ss,&sval);
 
3220
                                if ( kind != TK_QDSTRING ) {
 
3221
                                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
3222
                                        *errp = ss;
 
3223
                                        LDAP_FREE(sval);
 
3224
                                        ldap_nameform_free(nf);
 
3225
                                        return NULL;
 
3226
                                }
 
3227
                                nf->nf_desc = sval;
 
3228
                                parse_whsp(&ss);
 
3229
                        } else if ( !strcasecmp(sval,"OBSOLETE") ) {
 
3230
                                LDAP_FREE(sval);
 
3231
                                if ( seen_obsolete ) {
 
3232
                                        *code = LDAP_SCHERR_DUPOPT;
 
3233
                                        *errp = ss;
 
3234
                                        ldap_nameform_free(nf);
 
3235
                                        return(NULL);
 
3236
                                }
 
3237
                                seen_obsolete = 1;
 
3238
                                nf->nf_obsolete = LDAP_SCHEMA_YES;
 
3239
                                parse_whsp(&ss);
 
3240
                        } else if ( !strcasecmp(sval,"OC") ) {
 
3241
                                LDAP_FREE(sval);
 
3242
                                if ( seen_class ) {
 
3243
                                        *code = LDAP_SCHERR_DUPOPT;
 
3244
                                        *errp = ss;
 
3245
                                        ldap_nameform_free(nf);
 
3246
                                        return(NULL);
 
3247
                                }
 
3248
                                seen_class = 1;
 
3249
                                nf->nf_objectclass = parse_woid(&ss,code);
 
3250
                                if ( !nf->nf_objectclass ) {
 
3251
                                        *errp = ss;
 
3252
                                        ldap_nameform_free(nf);
 
3253
                                        return NULL;
 
3254
                                }
 
3255
                        } else if ( !strcasecmp(sval,"MUST") ) {
 
3256
                                LDAP_FREE(sval);
 
3257
                                if ( seen_must ) {
 
3258
                                        *code = LDAP_SCHERR_DUPOPT;
 
3259
                                        *errp = ss;
 
3260
                                        ldap_nameform_free(nf);
 
3261
                                        return(NULL);
 
3262
                                }
 
3263
                                seen_must = 1;
 
3264
                                nf->nf_at_oids_must = parse_oids(&ss,code,0);
 
3265
                                if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) {
 
3266
                                        *errp = ss;
 
3267
                                        ldap_nameform_free(nf);
 
3268
                                        return NULL;
 
3269
                                }
 
3270
                                parse_whsp(&ss);
 
3271
                        } else if ( !strcasecmp(sval,"MAY") ) {
 
3272
                                LDAP_FREE(sval);
 
3273
                                if ( seen_may ) {
 
3274
                                        *code = LDAP_SCHERR_DUPOPT;
 
3275
                                        *errp = ss;
 
3276
                                        ldap_nameform_free(nf);
 
3277
                                        return(NULL);
 
3278
                                }
 
3279
                                seen_may = 1;
 
3280
                                nf->nf_at_oids_may = parse_oids(&ss,code,0);
 
3281
                                if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) {
 
3282
                                        *errp = ss;
 
3283
                                        ldap_nameform_free(nf);
 
3284
                                        return NULL;
 
3285
                                }
 
3286
                                parse_whsp(&ss);
 
3287
                        } else if ( sval[0] == 'X' && sval[1] == '-' ) {
 
3288
                                /* Should be parse_qdstrings */
 
3289
                                ext_vals = parse_qdescrs(&ss, code);
 
3290
                                if ( !ext_vals ) {
 
3291
                                        *errp = ss;
 
3292
                                        ldap_nameform_free(nf);
 
3293
                                        return NULL;
 
3294
                                }
 
3295
                                if ( add_extension(&nf->nf_extensions,
 
3296
                                                    sval, ext_vals) ) {
 
3297
                                        *code = LDAP_SCHERR_OUTOFMEM;
 
3298
                                        *errp = ss;
 
3299
                                        LDAP_FREE(sval);
 
3300
                                        ldap_nameform_free(nf);
 
3301
                                        return NULL;
 
3302
                                }
 
3303
                        } else {
 
3304
                                *code = LDAP_SCHERR_UNEXPTOKEN;
 
3305
                                *errp = ss;
 
3306
                                LDAP_FREE(sval);
 
3307
                                ldap_nameform_free(nf);
 
3308
                                return NULL;
 
3309
                        }
 
3310
                        break;
 
3311
                default:
 
3312
                        *code = LDAP_SCHERR_UNEXPTOKEN;
 
3313
                        *errp = ss;
 
3314
                        LDAP_FREE(sval);
 
3315
                        ldap_nameform_free(nf);
 
3316
                        return NULL;
 
3317
                }
 
3318
        }
 
3319
}
 
3320
 
 
3321
static char *const err2text[] = {
 
3322
        N_("Success"),
 
3323
        N_("Out of memory"),
 
3324
        N_("Unexpected token"),
 
3325
        N_("Missing opening parenthesis"),
 
3326
        N_("Missing closing parenthesis"),
 
3327
        N_("Expecting digit"),
 
3328
        N_("Expecting a name"),
 
3329
        N_("Bad description"),
 
3330
        N_("Bad superiors"),
 
3331
        N_("Duplicate option"),
 
3332
        N_("Unexpected end of data"),
 
3333
        N_("Missing required field"),
 
3334
        N_("Out of order field")
 
3335
};
 
3336
 
 
3337
char *
 
3338
ldap_scherr2str(int code)
 
3339
{
 
3340
        if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
 
3341
                return _("Unknown error");
 
3342
        } else {
 
3343
                return _(err2text[code]);
 
3344
        }
 
3345
}