GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: schema.c,v 1.17 2017/01/20 11:55:08 benno Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 2010 Martin Hedenfalk <martinh@openbsd.org> |
||
5 |
* |
||
6 |
* Permission to use, copy, modify, and distribute this software for any |
||
7 |
* purpose with or without fee is hereby granted, provided that the above |
||
8 |
* copyright notice and this permission notice appear in all copies. |
||
9 |
* |
||
10 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||
11 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
12 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||
13 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
14 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||
15 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||
16 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
17 |
*/ |
||
18 |
|||
19 |
#include <sys/types.h> |
||
20 |
|||
21 |
#include <ctype.h> |
||
22 |
#include <stdlib.h> |
||
23 |
#include <string.h> |
||
24 |
#include <syslog.h> |
||
25 |
|||
26 |
#include "ldapd.h" |
||
27 |
#include "log.h" |
||
28 |
|||
29 |
#define ERROR -1 |
||
30 |
#define STRING 1 |
||
31 |
|||
32 |
static int |
||
33 |
attr_oid_cmp(struct attr_type *a, struct attr_type *b) |
||
34 |
{ |
||
35 |
62016 |
return strcasecmp(a->oid, b->oid); |
|
36 |
} |
||
37 |
|||
38 |
static int |
||
39 |
obj_oid_cmp(struct object *a, struct object *b) |
||
40 |
{ |
||
41 |
12800 |
return strcasecmp(a->oid, b->oid); |
|
42 |
} |
||
43 |
|||
44 |
static int |
||
45 |
oidname_cmp(struct oidname *a, struct oidname *b) |
||
46 |
{ |
||
47 |
207040 |
return strcasecmp(a->on_name, b->on_name); |
|
48 |
} |
||
49 |
|||
50 |
static int |
||
51 |
symoid_cmp(struct symoid *a, struct symoid *b) |
||
52 |
{ |
||
53 |
return strcasecmp(a->name, b->name); |
||
54 |
} |
||
55 |
|||
56 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✗ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✗✓✓ ✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✓✗✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
246720 |
RB_GENERATE(attr_type_tree, attr_type, link, attr_oid_cmp); |
57 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✗✓✓✗ ✓✓✓✗ ✓✓✓✓ ✓✓✓✗ ✓✗✓✓ ✓✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✓✗✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
58656 |
RB_GENERATE(object_tree, object, link, obj_oid_cmp); |
58 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✗ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✗✓✓ ✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✓✗✓✓ ✓✗✓✓ ✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ |
620224 |
RB_GENERATE(oidname_tree, oidname, link, oidname_cmp); |
59 |
RB_GENERATE(symoid_tree, symoid, link, symoid_cmp); |
||
60 |
|||
61 |
static struct attr_list *push_attr(struct attr_list *alist, struct attr_type *a); |
||
62 |
static struct obj_list *push_obj(struct obj_list *olist, struct object *obj); |
||
63 |
static struct name_list *push_name(struct name_list *nl, char *name); |
||
64 |
int is_oidstr(const char *oidstr); |
||
65 |
|||
66 |
struct attr_type * |
||
67 |
lookup_attribute_by_name(struct schema *schema, char *name) |
||
68 |
{ |
||
69 |
21760 |
struct oidname *on, find; |
|
70 |
|||
71 |
10880 |
find.on_name = name; |
|
72 |
10880 |
on = RB_FIND(oidname_tree, &schema->attr_names, &find); |
|
73 |
|||
74 |
✓✗ | 10880 |
if (on) |
75 |
10880 |
return on->on_attr_type; |
|
76 |
return NULL; |
||
77 |
10880 |
} |
|
78 |
|||
79 |
struct attr_type * |
||
80 |
lookup_attribute_by_oid(struct schema *schema, char *oid) |
||
81 |
{ |
||
82 |
struct attr_type find; |
||
83 |
|||
84 |
find.oid = oid; |
||
85 |
return RB_FIND(attr_type_tree, &schema->attr_types, &find); |
||
86 |
} |
||
87 |
|||
88 |
struct attr_type * |
||
89 |
lookup_attribute(struct schema *schema, char *oid_or_name) |
||
90 |
{ |
||
91 |
✗✓ | 21760 |
if (is_oidstr(oid_or_name)) |
92 |
return lookup_attribute_by_oid(schema, oid_or_name); |
||
93 |
10880 |
return lookup_attribute_by_name(schema, oid_or_name); |
|
94 |
10880 |
} |
|
95 |
|||
96 |
struct object * |
||
97 |
lookup_object_by_oid(struct schema *schema, char *oid) |
||
98 |
{ |
||
99 |
struct object find; |
||
100 |
|||
101 |
find.oid = oid; |
||
102 |
return RB_FIND(object_tree, &schema->objects, &find); |
||
103 |
} |
||
104 |
|||
105 |
struct object * |
||
106 |
lookup_object_by_name(struct schema *schema, char *name) |
||
107 |
{ |
||
108 |
2624 |
struct oidname *on, find; |
|
109 |
|||
110 |
1312 |
find.on_name = name; |
|
111 |
1312 |
on = RB_FIND(oidname_tree, &schema->object_names, &find); |
|
112 |
|||
113 |
✓✗ | 1312 |
if (on) |
114 |
1312 |
return on->on_object; |
|
115 |
return NULL; |
||
116 |
1312 |
} |
|
117 |
|||
118 |
struct object * |
||
119 |
lookup_object(struct schema *schema, char *oid_or_name) |
||
120 |
{ |
||
121 |
✗✓ | 2624 |
if (is_oidstr(oid_or_name)) |
122 |
return lookup_object_by_oid(schema, oid_or_name); |
||
123 |
1312 |
return lookup_object_by_name(schema, oid_or_name); |
|
124 |
1312 |
} |
|
125 |
|||
126 |
/* |
||
127 |
* Looks up a symbolic OID, optionally with a suffix OID, so if |
||
128 |
* SYMBOL = 1.2.3.4 |
||
129 |
* then |
||
130 |
* SYMBOL:5.6 = 1.2.3.4.5.6 |
||
131 |
* |
||
132 |
* Returned string must be freed by the caller. |
||
133 |
* Modifies the name argument. |
||
134 |
*/ |
||
135 |
char * |
||
136 |
lookup_symbolic_oid(struct schema *schema, char *name) |
||
137 |
{ |
||
138 |
struct symoid *symoid, find; |
||
139 |
char *colon, *oid; |
||
140 |
size_t sz; |
||
141 |
|||
142 |
colon = strchr(name, ':'); |
||
143 |
if (colon != NULL) { |
||
144 |
if (!is_oidstr(colon + 1)) { |
||
145 |
log_warnx("invalid OID after colon: %s", colon + 1); |
||
146 |
return NULL; |
||
147 |
} |
||
148 |
*colon = '\0'; |
||
149 |
} |
||
150 |
|||
151 |
find.name = name; |
||
152 |
symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find); |
||
153 |
if (symoid == NULL) |
||
154 |
return NULL; |
||
155 |
|||
156 |
if (colon == NULL) |
||
157 |
return strdup(symoid->oid); |
||
158 |
|||
159 |
/* Expand SYMBOL:OID. */ |
||
160 |
sz = strlen(symoid->oid) + 1 + strlen(colon + 1) + 1; |
||
161 |
if ((oid = malloc(sz)) == NULL) { |
||
162 |
log_warnx("malloc"); |
||
163 |
return NULL; |
||
164 |
} |
||
165 |
|||
166 |
strlcpy(oid, symoid->oid, sz); |
||
167 |
strlcat(oid, ".", sz); |
||
168 |
strlcat(oid, colon + 1, sz); |
||
169 |
|||
170 |
return oid; |
||
171 |
} |
||
172 |
|||
173 |
/* |
||
174 |
* Push a symbol-OID pair on the tree. Name and OID must be valid pointers |
||
175 |
* during the lifetime of the tree. |
||
176 |
*/ |
||
177 |
static struct symoid * |
||
178 |
push_symbolic_oid(struct schema *schema, char *name, char *oid) |
||
179 |
{ |
||
180 |
struct symoid *symoid, find; |
||
181 |
|||
182 |
find.name = name; |
||
183 |
symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find); |
||
184 |
|||
185 |
if (symoid == NULL) { |
||
186 |
symoid = calloc(1, sizeof(*symoid)); |
||
187 |
if (symoid == NULL) { |
||
188 |
log_warnx("calloc"); |
||
189 |
return NULL; |
||
190 |
} |
||
191 |
|||
192 |
symoid->name = name; |
||
193 |
RB_INSERT(symoid_tree, &schema->symbolic_oids, symoid); |
||
194 |
} |
||
195 |
|||
196 |
free(symoid->oid); |
||
197 |
symoid->oid = oid; |
||
198 |
|||
199 |
return symoid; |
||
200 |
} |
||
201 |
|||
202 |
static struct attr_list * |
||
203 |
push_attr(struct attr_list *alist, struct attr_type *a) |
||
204 |
{ |
||
205 |
struct attr_ptr *aptr; |
||
206 |
|||
207 |
✓✓ | 20608 |
if (alist == NULL) { |
208 |
✗✓ | 2176 |
if ((alist = calloc(1, sizeof(*alist))) == NULL) { |
209 |
log_warn("calloc"); |
||
210 |
return NULL; |
||
211 |
} |
||
212 |
2176 |
SLIST_INIT(alist); |
|
213 |
2176 |
} |
|
214 |
|||
215 |
✗✓ | 10304 |
if ((aptr = calloc(1, sizeof(*aptr))) == NULL) { |
216 |
log_warn("calloc"); |
||
217 |
free(alist); |
||
218 |
return NULL; |
||
219 |
} |
||
220 |
10304 |
aptr->attr_type = a; |
|
221 |
10304 |
SLIST_INSERT_HEAD(alist, aptr, next); |
|
222 |
|||
223 |
10304 |
return alist; |
|
224 |
10304 |
} |
|
225 |
|||
226 |
static struct obj_list * |
||
227 |
push_obj(struct obj_list *olist, struct object *obj) |
||
228 |
{ |
||
229 |
struct obj_ptr *optr; |
||
230 |
|||
231 |
✓✗ | 2624 |
if (olist == NULL) { |
232 |
✗✓ | 1312 |
if ((olist = calloc(1, sizeof(*olist))) == NULL) { |
233 |
log_warn("calloc"); |
||
234 |
return NULL; |
||
235 |
} |
||
236 |
1312 |
SLIST_INIT(olist); |
|
237 |
1312 |
} |
|
238 |
|||
239 |
✗✓ | 1312 |
if ((optr = calloc(1, sizeof(*optr))) == NULL) { |
240 |
log_warn("calloc"); |
||
241 |
free(olist); |
||
242 |
return NULL; |
||
243 |
} |
||
244 |
1312 |
optr->object = obj; |
|
245 |
1312 |
SLIST_INSERT_HEAD(olist, optr, next); |
|
246 |
|||
247 |
1312 |
return olist; |
|
248 |
1312 |
} |
|
249 |
|||
250 |
int |
||
251 |
is_oidstr(const char *oidstr) |
||
252 |
{ |
||
253 |
43392 |
struct ber_oid oid; |
|
254 |
43392 |
return (ber_string2oid(oidstr, &oid) == 0); |
|
255 |
21696 |
} |
|
256 |
|||
257 |
static struct name_list * |
||
258 |
push_name(struct name_list *nl, char *name) |
||
259 |
{ |
||
260 |
struct name *n; |
||
261 |
|||
262 |
✓✗ | 11392 |
if (nl == NULL) { |
263 |
✗✓ | 5696 |
if ((nl = calloc(1, sizeof(*nl))) == NULL) { |
264 |
log_warn("calloc"); |
||
265 |
return NULL; |
||
266 |
} |
||
267 |
5696 |
SLIST_INIT(nl); |
|
268 |
5696 |
} |
|
269 |
✗✓ | 5696 |
if ((n = calloc(1, sizeof(*n))) == NULL) { |
270 |
log_warn("calloc"); |
||
271 |
free(nl); |
||
272 |
return NULL; |
||
273 |
} |
||
274 |
5696 |
n->name = name; |
|
275 |
5696 |
SLIST_INSERT_HEAD(nl, n, next); |
|
276 |
|||
277 |
5696 |
return nl; |
|
278 |
5696 |
} |
|
279 |
|||
280 |
static int |
||
281 |
schema_getc(struct schema *schema, int quotec) |
||
282 |
{ |
||
283 |
int c, next; |
||
284 |
|||
285 |
✓✓ | 2030144 |
if (schema->pushback_index) |
286 |
60160 |
return (schema->pushback_buffer[--schema->pushback_index]); |
|
287 |
|||
288 |
✓✓ | 954912 |
if (quotec) { |
289 |
✓✗✗✓ ✗✓ |
610816 |
if ((c = getc(schema->fp)) == EOF) { |
290 |
log_warnx("reached end of file while parsing " |
||
291 |
"quoted string"); |
||
292 |
return EOF; |
||
293 |
} |
||
294 |
152704 |
return (c); |
|
295 |
} |
||
296 |
|||
297 |
✓✗✓✓ ✗✓ |
4011040 |
while ((c = getc(schema->fp)) == '\\') { |
298 |
next = getc(schema->fp); |
||
299 |
if (next != '\n') { |
||
300 |
c = next; |
||
301 |
break; |
||
302 |
} |
||
303 |
schema->lineno++; |
||
304 |
} |
||
305 |
|||
306 |
802208 |
return (c); |
|
307 |
1015072 |
} |
|
308 |
|||
309 |
static int |
||
310 |
schema_ungetc(struct schema *schema, int c) |
||
311 |
{ |
||
312 |
✗✓ | 120320 |
if (c == EOF) |
313 |
return EOF; |
||
314 |
|||
315 |
✓✗ | 60160 |
if (schema->pushback_index < SCHEMA_MAXPUSHBACK-1) |
316 |
60160 |
return (schema->pushback_buffer[schema->pushback_index++] = c); |
|
317 |
else |
||
318 |
return (EOF); |
||
319 |
60160 |
} |
|
320 |
|||
321 |
static int |
||
322 |
findeol(struct schema *schema) |
||
323 |
{ |
||
324 |
int c; |
||
325 |
|||
326 |
/* skip to either EOF or the first real EOL */ |
||
327 |
while (1) { |
||
328 |
if (schema->pushback_index) |
||
329 |
c = schema->pushback_buffer[--schema->pushback_index]; |
||
330 |
else |
||
331 |
c = schema_getc(schema, 0); |
||
332 |
if (c == '\n') { |
||
333 |
schema->lineno++; |
||
334 |
break; |
||
335 |
} |
||
336 |
if (c == EOF) |
||
337 |
break; |
||
338 |
} |
||
339 |
return (ERROR); |
||
340 |
} |
||
341 |
|||
342 |
static int |
||
343 |
schema_lex(struct schema *schema, char **kw) |
||
344 |
{ |
||
345 |
173376 |
char buf[8096]; |
|
346 |
char *p; |
||
347 |
int quotec, next, c; |
||
348 |
|||
349 |
✓✓ | 173376 |
if (kw) |
350 |
79712 |
*kw = NULL; |
|
351 |
|||
352 |
top: |
||
353 |
118368 |
p = buf; |
|
354 |
✓✓ | 400128 |
while ((c = schema_getc(schema, 0)) == ' ' || c == '\t') |
355 |
; /* nothing */ |
||
356 |
|||
357 |
✓✓ | 118368 |
if (c == '#') |
358 |
✓✓ | 33792 |
while ((c = schema_getc(schema, 0)) != '\n' && c != EOF) |
359 |
; /* nothing */ |
||
360 |
|||
361 |
✗✓✓ | 118368 |
switch (c) { |
362 |
case '\'': |
||
363 |
case '"': |
||
364 |
quotec = c; |
||
365 |
152096 |
while (1) { |
|
366 |
✗✓ | 152704 |
if ((c = schema_getc(schema, quotec)) == EOF) |
367 |
return (0); |
||
368 |
✓✓ | 152704 |
if (c == '\n') { |
369 |
608 |
schema->lineno++; |
|
370 |
608 |
continue; |
|
371 |
✗✓ | 152096 |
} else if (c == '\\') { |
372 |
if ((next = schema_getc(schema, quotec)) == EOF) |
||
373 |
return (0); |
||
374 |
if (next == quotec || c == ' ' || c == '\t') |
||
375 |
c = next; |
||
376 |
else if (next == '\n') |
||
377 |
continue; |
||
378 |
else |
||
379 |
schema_ungetc(schema, next); |
||
380 |
✓✓ | 152096 |
} else if (c == quotec) { |
381 |
6880 |
*p = '\0'; |
|
382 |
break; |
||
383 |
} |
||
384 |
✗✓ | 145216 |
if (p + 1 >= buf + sizeof(buf) - 1) { |
385 |
log_warnx("string too long"); |
||
386 |
return (findeol(schema)); |
||
387 |
} |
||
388 |
145216 |
*p++ = (char)c; |
|
389 |
} |
||
390 |
✓✗✗✓ |
13760 |
if (kw != NULL && (*kw = strdup(buf)) == NULL) |
391 |
fatal("schema_lex: strdup"); |
||
392 |
6880 |
return (STRING); |
|
393 |
} |
||
394 |
|||
395 |
#define allowed_in_string(x) \ |
||
396 |
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ |
||
397 |
x != '{' && x != '}' && x != '<' && x != '>' && \ |
||
398 |
x != '!' && x != '=' && x != '/' && x != '#' && \ |
||
399 |
x != ',')) |
||
400 |
|||
401 |
✓✓ | 111488 |
if (isalnum(c) || c == ':' || c == '_' || c == '*') { |
402 |
56992 |
do { |
|
403 |
641600 |
*p++ = c; |
|
404 |
✗✓ | 641600 |
if ((unsigned)(p-buf) >= sizeof(buf)) { |
405 |
log_warnx("string too long"); |
||
406 |
return (findeol(schema)); |
||
407 |
} |
||
408 |
✓✗✓✓ ✓✓ |
1409248 |
} while ((c = schema_getc(schema, 0)) != EOF && (allowed_in_string(c))); |
409 |
56992 |
schema_ungetc(schema, c); |
|
410 |
56992 |
*p = '\0'; |
|
411 |
✓✓✗✓ |
113344 |
if (kw != NULL && (*kw = strdup(buf)) == NULL) |
412 |
fatal("schema_lex: strdup"); |
||
413 |
56992 |
return STRING; |
|
414 |
} |
||
415 |
✓✓ | 54496 |
if (c == '\n') { |
416 |
31680 |
schema->lineno++; |
|
417 |
31680 |
goto top; |
|
418 |
} |
||
419 |
✓✓ | 22816 |
if (c == EOF) |
420 |
96 |
return (0); |
|
421 |
22720 |
return (c); |
|
422 |
86688 |
} |
|
423 |
|||
424 |
struct schema * |
||
425 |
schema_new(void) |
||
426 |
{ |
||
427 |
struct schema *schema; |
||
428 |
|||
429 |
✗✓ | 64 |
if ((schema = calloc(1, sizeof(*schema))) == NULL) |
430 |
return NULL; |
||
431 |
|||
432 |
32 |
RB_INIT(&schema->attr_types); |
|
433 |
32 |
RB_INIT(&schema->attr_names); |
|
434 |
32 |
RB_INIT(&schema->objects); |
|
435 |
32 |
RB_INIT(&schema->object_names); |
|
436 |
32 |
RB_INIT(&schema->symbolic_oids); |
|
437 |
|||
438 |
32 |
return schema; |
|
439 |
32 |
} |
|
440 |
|||
441 |
static void |
||
442 |
schema_err(struct schema *schema, const char *fmt, ...) |
||
443 |
{ |
||
444 |
va_list ap; |
||
445 |
char *msg; |
||
446 |
|||
447 |
va_start(ap, fmt); |
||
448 |
if (vasprintf(&msg, fmt, ap) == -1) |
||
449 |
fatal("vasprintf"); |
||
450 |
va_end(ap); |
||
451 |
logit(LOG_CRIT, "%s:%d: %s", schema->filename, schema->lineno, msg); |
||
452 |
free(msg); |
||
453 |
|||
454 |
schema->error++; |
||
455 |
} |
||
456 |
|||
457 |
static int |
||
458 |
schema_link_attr_name(struct schema *schema, const char *name, struct attr_type *attr) |
||
459 |
{ |
||
460 |
struct oidname *oidname, *prev; |
||
461 |
|||
462 |
✗✓ | 8640 |
if ((oidname = calloc(1, sizeof(*oidname))) == NULL) { |
463 |
log_warn("calloc"); |
||
464 |
return -1; |
||
465 |
} |
||
466 |
|||
467 |
4320 |
oidname->on_name = name; |
|
468 |
4320 |
oidname->on_attr_type = attr; |
|
469 |
4320 |
prev = RB_INSERT(oidname_tree, &schema->attr_names, oidname); |
|
470 |
✗✓ | 4320 |
if (prev != NULL) { |
471 |
schema_err(schema, "attribute type name '%s'" |
||
472 |
" already defined for oid %s", |
||
473 |
name, prev->on_attr_type->oid); |
||
474 |
free(oidname); |
||
475 |
return -1; |
||
476 |
} |
||
477 |
|||
478 |
4320 |
return 0; |
|
479 |
4320 |
} |
|
480 |
|||
481 |
static int |
||
482 |
schema_link_attr_names(struct schema *schema, struct attr_type *attr) |
||
483 |
{ |
||
484 |
struct name *name; |
||
485 |
|||
486 |
✓✓ | 21600 |
SLIST_FOREACH(name, attr->names, next) { |
487 |
✗✓ | 4320 |
if (schema_link_attr_name(schema, name->name, attr) != 0) |
488 |
return -1; |
||
489 |
} |
||
490 |
4320 |
return 0; |
|
491 |
4320 |
} |
|
492 |
|||
493 |
static int |
||
494 |
schema_link_obj_name(struct schema *schema, const char *name, struct object *obj) |
||
495 |
{ |
||
496 |
struct oidname *oidname, *prev; |
||
497 |
|||
498 |
✗✓ | 2752 |
if ((oidname = calloc(1, sizeof(*oidname))) == NULL) { |
499 |
log_warn("calloc"); |
||
500 |
return -1; |
||
501 |
} |
||
502 |
|||
503 |
1376 |
oidname->on_name = name; |
|
504 |
1376 |
oidname->on_object = obj; |
|
505 |
1376 |
prev = RB_INSERT(oidname_tree, &schema->object_names, oidname); |
|
506 |
✗✓ | 1376 |
if (prev != NULL) { |
507 |
schema_err(schema, "object class name '%s'" |
||
508 |
" already defined for oid %s", |
||
509 |
name, prev->on_object->oid); |
||
510 |
free(oidname); |
||
511 |
return -1; |
||
512 |
} |
||
513 |
|||
514 |
1376 |
return 0; |
|
515 |
1376 |
} |
|
516 |
|||
517 |
static int |
||
518 |
schema_link_obj_names(struct schema *schema, struct object *obj) |
||
519 |
{ |
||
520 |
struct name *name; |
||
521 |
|||
522 |
✓✓ | 6880 |
SLIST_FOREACH(name, obj->names, next) { |
523 |
✗✓ | 1376 |
if (schema_link_obj_name(schema, name->name, obj) != 0) |
524 |
return -1; |
||
525 |
} |
||
526 |
1376 |
return 0; |
|
527 |
1376 |
} |
|
528 |
|||
529 |
static struct name_list * |
||
530 |
schema_parse_names(struct schema *schema) |
||
531 |
{ |
||
532 |
struct name_list *nlist = NULL; |
||
533 |
11392 |
char *kw; |
|
534 |
int token; |
||
535 |
|||
536 |
5696 |
token = schema_lex(schema, &kw); |
|
537 |
✓✗ | 5696 |
if (token == STRING) |
538 |
5696 |
return push_name(NULL, kw); |
|
539 |
|||
540 |
if (token != '(') |
||
541 |
goto fail; |
||
542 |
|||
543 |
for (;;) { |
||
544 |
token = schema_lex(schema, &kw); |
||
545 |
if (token == ')') |
||
546 |
break; |
||
547 |
if (token != STRING) |
||
548 |
goto fail; |
||
549 |
nlist = push_name(nlist, kw); |
||
550 |
} |
||
551 |
|||
552 |
return nlist; |
||
553 |
|||
554 |
fail: |
||
555 |
free(kw); |
||
556 |
/* FIXME: leaks nlist here */ |
||
557 |
return NULL; |
||
558 |
5696 |
} |
|
559 |
|||
560 |
static void |
||
561 |
schema_free_name_list(struct name_list *nlist) |
||
562 |
{ |
||
563 |
struct name *name; |
||
564 |
|||
565 |
while ((name = SLIST_FIRST(nlist)) != NULL) { |
||
566 |
SLIST_REMOVE_HEAD(nlist, next); |
||
567 |
free(name->name); |
||
568 |
free(name); |
||
569 |
} |
||
570 |
free(nlist); |
||
571 |
} |
||
572 |
|||
573 |
static struct attr_list * |
||
574 |
schema_parse_attrlist(struct schema *schema) |
||
575 |
{ |
||
576 |
struct attr_list *alist = NULL; |
||
577 |
struct attr_type *attr; |
||
578 |
4352 |
char *kw; |
|
579 |
int token, want_dollar = 0; |
||
580 |
|||
581 |
2176 |
token = schema_lex(schema, &kw); |
|
582 |
✓✓ | 2176 |
if (token == STRING) { |
583 |
✗✓ | 896 |
if ((attr = lookup_attribute(schema, kw)) == NULL) { |
584 |
schema_err(schema, "undeclared attribute type '%s'", kw); |
||
585 |
goto fail; |
||
586 |
} |
||
587 |
896 |
free(kw); |
|
588 |
896 |
return push_attr(NULL, attr); |
|
589 |
} |
||
590 |
|||
591 |
✓✗ | 1280 |
if (token != '(') |
592 |
goto fail; |
||
593 |
|||
594 |
10688 |
for (;;) { |
|
595 |
18816 |
token = schema_lex(schema, &kw); |
|
596 |
✓✓ | 18816 |
if (token == ')') |
597 |
break; |
||
598 |
✓✓ | 17536 |
if (token == '$') { |
599 |
✓✗ | 8128 |
if (!want_dollar) |
600 |
goto fail; |
||
601 |
want_dollar = 0; |
||
602 |
8128 |
continue; |
|
603 |
} |
||
604 |
✓✗ | 9408 |
if (token != STRING) |
605 |
goto fail; |
||
606 |
✗✓ | 9408 |
if ((attr = lookup_attribute(schema, kw)) == NULL) { |
607 |
schema_err(schema, "%s: no such attribute", kw); |
||
608 |
goto fail; |
||
609 |
} |
||
610 |
9408 |
alist = push_attr(alist, attr); |
|
611 |
9408 |
free(kw); |
|
612 |
want_dollar = 1; |
||
613 |
} |
||
614 |
|||
615 |
1280 |
return alist; |
|
616 |
|||
617 |
fail: |
||
618 |
free(kw); |
||
619 |
/* FIXME: leaks alist here */ |
||
620 |
return NULL; |
||
621 |
2176 |
} |
|
622 |
|||
623 |
static struct obj_list * |
||
624 |
schema_parse_objlist(struct schema *schema) |
||
625 |
{ |
||
626 |
struct obj_list *olist = NULL; |
||
627 |
struct object *obj; |
||
628 |
2624 |
char *kw; |
|
629 |
int token, want_dollar = 0; |
||
630 |
|||
631 |
1312 |
token = schema_lex(schema, &kw); |
|
632 |
✓✗ | 1312 |
if (token == STRING) { |
633 |
✗✓ | 1312 |
if ((obj = lookup_object(schema, kw)) == NULL) { |
634 |
schema_err(schema, "undeclared object class '%s'", kw); |
||
635 |
goto fail; |
||
636 |
} |
||
637 |
1312 |
free(kw); |
|
638 |
1312 |
return push_obj(NULL, obj); |
|
639 |
} |
||
640 |
|||
641 |
if (token != '(') |
||
642 |
goto fail; |
||
643 |
|||
644 |
for (;;) { |
||
645 |
token = schema_lex(schema, &kw); |
||
646 |
if (token == ')') |
||
647 |
break; |
||
648 |
if (token == '$') { |
||
649 |
if (!want_dollar) |
||
650 |
goto fail; |
||
651 |
want_dollar = 0; |
||
652 |
continue; |
||
653 |
} |
||
654 |
if (token != STRING) |
||
655 |
goto fail; |
||
656 |
if ((obj = lookup_object(schema, kw)) == NULL) |
||
657 |
goto fail; |
||
658 |
olist = push_obj(olist, obj); |
||
659 |
want_dollar = 1; |
||
660 |
} |
||
661 |
|||
662 |
return olist; |
||
663 |
|||
664 |
fail: |
||
665 |
free(kw); |
||
666 |
/* FIXME: leaks olist here */ |
||
667 |
return NULL; |
||
668 |
1312 |
} |
|
669 |
|||
670 |
static int |
||
671 |
schema_validate_match_rule(struct schema *schema, struct attr_type *at, |
||
672 |
const struct match_rule *mrule, enum match_rule_type type) |
||
673 |
{ |
||
674 |
int i; |
||
675 |
|||
676 |
✓✓ | 25920 |
if (mrule == NULL) |
677 |
7104 |
return 0; |
|
678 |
|||
679 |
✗✓ | 5856 |
if ((mrule->type & type) != type) { |
680 |
schema_err(schema, "%s: bad matching rule '%s'", |
||
681 |
ATTR_NAME(at), mrule->name); |
||
682 |
return -1; |
||
683 |
} |
||
684 |
|||
685 |
/* Is this matching rule compatible with the attribute syntax? */ |
||
686 |
✓✓ | 5856 |
if (strcmp(mrule->syntax_oid, at->syntax->oid) == 0) |
687 |
3456 |
return 0; |
|
688 |
|||
689 |
/* Check any alternative syntaxes for compatibility. */ |
||
690 |
✓✗✓✗ |
11424 |
for (i = 0; mrule->alt_syntax_oids && mrule->alt_syntax_oids[i]; i++) |
691 |
✓✓ | 3808 |
if (strcmp(mrule->alt_syntax_oids[i], at->syntax->oid) == 0) |
692 |
2400 |
return 0; |
|
693 |
|||
694 |
schema_err(schema, "%s: inappropriate matching rule '%s' for syntax [%s]", |
||
695 |
ATTR_NAME(at), mrule->name, at->syntax->oid); |
||
696 |
return -1; |
||
697 |
12960 |
} |
|
698 |
|||
699 |
static int |
||
700 |
schema_parse_attributetype(struct schema *schema) |
||
701 |
{ |
||
702 |
struct attr_type *attr = NULL, *prev, *sup; |
||
703 |
struct name_list *xnames; |
||
704 |
8640 |
char *kw = NULL, *arg = NULL; |
|
705 |
int token, ret = 0, c; |
||
706 |
|||
707 |
✓✗ | 4320 |
if (schema_lex(schema, NULL) != '(') |
708 |
goto fail; |
||
709 |
|||
710 |
✓✗ | 4320 |
if (schema_lex(schema, &kw) != STRING) |
711 |
goto fail; |
||
712 |
|||
713 |
✗✓ | 4320 |
if ((attr = calloc(1, sizeof(*attr))) == NULL) { |
714 |
log_warn("calloc"); |
||
715 |
goto fail; |
||
716 |
} |
||
717 |
4320 |
attr->usage = USAGE_USER_APP; |
|
718 |
|||
719 |
✓✗ | 4320 |
if (is_oidstr(kw)) |
720 |
4320 |
attr->oid = kw; |
|
721 |
else { |
||
722 |
attr->oid = lookup_symbolic_oid(schema, kw); |
||
723 |
if (attr->oid == NULL) |
||
724 |
goto fail; |
||
725 |
free(kw); |
||
726 |
} |
||
727 |
4320 |
kw = NULL; |
|
728 |
|||
729 |
4320 |
prev = RB_INSERT(attr_type_tree, &schema->attr_types, attr); |
|
730 |
✗✓ | 4320 |
if (prev != NULL) { |
731 |
schema_err(schema, "attribute type %s already defined", attr->oid); |
||
732 |
goto fail; |
||
733 |
} |
||
734 |
|||
735 |
✓✗ | 41856 |
while (ret == 0) { |
736 |
20928 |
token = schema_lex(schema, &kw); |
|
737 |
✓✓ | 20928 |
if (token == ')') |
738 |
break; |
||
739 |
✓✗ | 16608 |
else if (token != STRING) |
740 |
goto fail; |
||
741 |
✓✓ | 16608 |
if (strcasecmp(kw, "NAME") == 0) { |
742 |
4320 |
attr->names = schema_parse_names(schema); |
|
743 |
✓✗ | 4320 |
if (attr->names == NULL) |
744 |
goto fail; |
||
745 |
4320 |
schema_link_attr_names(schema, attr); |
|
746 |
✓✓ | 16608 |
} else if (strcasecmp(kw, "DESC") == 0) { |
747 |
✓✗ | 736 |
if (schema_lex(schema, &attr->desc) != STRING) |
748 |
goto fail; |
||
749 |
✗✓ | 11552 |
} else if (strcasecmp(kw, "OBSOLETE") == 0) { |
750 |
attr->obsolete = 1; |
||
751 |
✓✓ | 11552 |
} else if (strcasecmp(kw, "SUP") == 0) { |
752 |
✓✗ | 576 |
if (schema_lex(schema, &arg) != STRING) |
753 |
goto fail; |
||
754 |
✗✓ | 576 |
if ((attr->sup = lookup_attribute(schema, arg)) == NULL) { |
755 |
schema_err(schema, "%s: no such attribute", arg); |
||
756 |
goto fail; |
||
757 |
} |
||
758 |
576 |
free(arg); |
|
759 |
✓✓ | 11552 |
} else if (strcasecmp(kw, "EQUALITY") == 0) { |
760 |
✓✗ | 3168 |
if (schema_lex(schema, &arg) != STRING) |
761 |
goto fail; |
||
762 |
✗✓ | 3168 |
if ((attr->equality = match_rule_lookup(arg)) == NULL) { |
763 |
schema_err(schema, "%s: unknown matching rule", |
||
764 |
arg); |
||
765 |
goto fail; |
||
766 |
} |
||
767 |
3168 |
free(arg); |
|
768 |
✓✓ | 10976 |
} else if (strcasecmp(kw, "ORDERING") == 0) { |
769 |
✓✗ | 128 |
if (schema_lex(schema, &arg) != STRING) |
770 |
goto fail; |
||
771 |
✗✓ | 128 |
if ((attr->ordering = match_rule_lookup(arg)) == NULL) { |
772 |
schema_err(schema, "%s: unknown matching rule", |
||
773 |
arg); |
||
774 |
goto fail; |
||
775 |
} |
||
776 |
128 |
free(arg); |
|
777 |
✓✓ | 7808 |
} else if (strcasecmp(kw, "SUBSTR") == 0) { |
778 |
✓✗ | 1536 |
if (schema_lex(schema, &arg) != STRING) |
779 |
goto fail; |
||
780 |
✗✓ | 1536 |
if ((attr->substr = match_rule_lookup(arg)) == NULL) { |
781 |
schema_err(schema, "%s: unknown matching rule", |
||
782 |
arg); |
||
783 |
goto fail; |
||
784 |
} |
||
785 |
1536 |
free(arg); |
|
786 |
✓✓ | 7680 |
} else if (strcasecmp(kw, "SYNTAX") == 0) { |
787 |
✓✗✓✗ |
7616 |
if (schema_lex(schema, &arg) != STRING || |
788 |
3808 |
!is_oidstr(arg)) |
|
789 |
goto fail; |
||
790 |
|||
791 |
✗✓ | 3808 |
if ((attr->syntax = syntax_lookup(arg)) == NULL) { |
792 |
schema_err(schema, "syntax not supported: %s", |
||
793 |
arg); |
||
794 |
goto fail; |
||
795 |
} |
||
796 |
|||
797 |
✓✓ | 3808 |
if ((c = schema_getc(schema, 0)) == '{') { |
798 |
✓✗✓✗ |
1280 |
if (schema_lex(schema, NULL) != STRING || |
799 |
640 |
schema_lex(schema, NULL) != '}') |
|
800 |
goto fail; |
||
801 |
} else |
||
802 |
3168 |
schema_ungetc(schema, c); |
|
803 |
3808 |
free(arg); |
|
804 |
✓✓ | 6144 |
} else if (strcasecmp(kw, "SINGLE-VALUE") == 0) { |
805 |
1152 |
attr->single = 1; |
|
806 |
✗✓ | 2336 |
} else if (strcasecmp(kw, "COLLECTIVE") == 0) { |
807 |
attr->collective = 1; |
||
808 |
✓✓ | 1184 |
} else if (strcasecmp(kw, "NO-USER-MODIFICATION") == 0) { |
809 |
320 |
attr->immutable = 1; |
|
810 |
✓✗ | 1184 |
} else if (strcasecmp(kw, "USAGE") == 0) { |
811 |
✓✗ | 864 |
if (schema_lex(schema, &arg) != STRING) |
812 |
goto fail; |
||
813 |
✓✓ | 864 |
if (strcasecmp(arg, "dSAOperation") == 0) |
814 |
288 |
attr->usage = USAGE_DSA_OP; |
|
815 |
✓✗ | 576 |
else if (strcasecmp(arg, "directoryOperation") == 0) |
816 |
576 |
attr->usage = USAGE_DIR_OP; |
|
817 |
else if (strcasecmp(arg, "distributedOperation") == 0) |
||
818 |
attr->usage = USAGE_DIST_OP; |
||
819 |
else if (strcasecmp(arg, "userApplications") == 0) |
||
820 |
attr->usage = USAGE_USER_APP; |
||
821 |
else { |
||
822 |
schema_err(schema, "invalid usage '%s'", arg); |
||
823 |
goto fail; |
||
824 |
} |
||
825 |
864 |
free(arg); |
|
826 |
✗✗ | 864 |
} else if (strncmp(kw, "X-", 2) == 0) { |
827 |
/* unknown extension, eat argument(s) */ |
||
828 |
xnames = schema_parse_names(schema); |
||
829 |
if (xnames == NULL) |
||
830 |
goto fail; |
||
831 |
schema_free_name_list(xnames); |
||
832 |
} else { |
||
833 |
schema_err(schema, "syntax error at token '%s'", kw); |
||
834 |
goto fail; |
||
835 |
} |
||
836 |
16608 |
free(kw); |
|
837 |
} |
||
838 |
|||
839 |
/* Check that a syntax is defined, either directly or |
||
840 |
* indirectly via a superior attribute type. |
||
841 |
*/ |
||
842 |
4320 |
sup = attr->sup; |
|
843 |
✓✓ | 9664 |
while (attr->syntax == NULL && sup != NULL) { |
844 |
512 |
attr->syntax = sup->syntax; |
|
845 |
512 |
sup = sup->sup; |
|
846 |
} |
||
847 |
✗✓ | 4320 |
if (attr->syntax == NULL) { |
848 |
schema_err(schema, "%s: no syntax defined", ATTR_NAME(attr)); |
||
849 |
goto fail; |
||
850 |
} |
||
851 |
|||
852 |
/* If the attribute type doesn't explicitly define equality, check |
||
853 |
* if any superior attribute type does. |
||
854 |
*/ |
||
855 |
4320 |
sup = attr->sup; |
|
856 |
✓✓ | 9792 |
while (attr->equality == NULL && sup != NULL) { |
857 |
576 |
attr->equality = sup->equality; |
|
858 |
576 |
sup = sup->sup; |
|
859 |
} |
||
860 |
/* Same thing with ordering matching rule. */ |
||
861 |
4320 |
sup = attr->sup; |
|
862 |
✓✓ | 9792 |
while (attr->ordering == NULL && sup != NULL) { |
863 |
576 |
attr->ordering = sup->ordering; |
|
864 |
576 |
sup = sup->sup; |
|
865 |
} |
||
866 |
/* ...and substring matching rule. */ |
||
867 |
4320 |
sup = attr->sup; |
|
868 |
✓✓ | 9792 |
while (attr->substr == NULL && sup != NULL) { |
869 |
576 |
attr->substr = sup->substr; |
|
870 |
576 |
sup = sup->sup; |
|
871 |
} |
||
872 |
|||
873 |
✓✗✓✗ |
8640 |
if (schema_validate_match_rule(schema, attr, attr->equality, MATCH_EQUALITY) != 0 || |
874 |
✓✗ | 4320 |
schema_validate_match_rule(schema, attr, attr->ordering, MATCH_ORDERING) != 0 || |
875 |
4320 |
schema_validate_match_rule(schema, attr, attr->substr, MATCH_SUBSTR) != 0) |
|
876 |
goto fail; |
||
877 |
|||
878 |
4320 |
return 0; |
|
879 |
|||
880 |
fail: |
||
881 |
free(kw); |
||
882 |
if (attr != NULL) { |
||
883 |
if (attr->oid != NULL) { |
||
884 |
RB_REMOVE(attr_type_tree, &schema->attr_types, attr); |
||
885 |
free(attr->oid); |
||
886 |
} |
||
887 |
free(attr->desc); |
||
888 |
free(attr); |
||
889 |
} |
||
890 |
return -1; |
||
891 |
4320 |
} |
|
892 |
|||
893 |
static int |
||
894 |
schema_parse_objectclass(struct schema *schema) |
||
895 |
{ |
||
896 |
struct object *obj = NULL, *prev; |
||
897 |
struct obj_ptr *optr; |
||
898 |
struct name_list *xnames; |
||
899 |
2752 |
char *kw = NULL; |
|
900 |
int token, ret = 0; |
||
901 |
|||
902 |
✓✗ | 1376 |
if (schema_lex(schema, NULL) != '(') |
903 |
goto fail; |
||
904 |
|||
905 |
✓✗ | 1376 |
if (schema_lex(schema, &kw) != STRING) |
906 |
goto fail; |
||
907 |
|||
908 |
✗✓ | 1376 |
if ((obj = calloc(1, sizeof(*obj))) == NULL) { |
909 |
log_warn("calloc"); |
||
910 |
goto fail; |
||
911 |
} |
||
912 |
1376 |
obj->kind = KIND_STRUCTURAL; |
|
913 |
|||
914 |
✓✗ | 1376 |
if (is_oidstr(kw)) |
915 |
1376 |
obj->oid = kw; |
|
916 |
else { |
||
917 |
obj->oid = lookup_symbolic_oid(schema, kw); |
||
918 |
if (obj->oid == NULL) |
||
919 |
goto fail; |
||
920 |
free(kw); |
||
921 |
} |
||
922 |
1376 |
kw = NULL; |
|
923 |
|||
924 |
1376 |
prev = RB_INSERT(object_tree, &schema->objects, obj); |
|
925 |
✗✓ | 1376 |
if (prev != NULL) { |
926 |
schema_err(schema, "object class %s already defined", obj->oid); |
||
927 |
goto fail; |
||
928 |
} |
||
929 |
|||
930 |
✓✗ | 16064 |
while (ret == 0) { |
931 |
8032 |
token = schema_lex(schema, &kw); |
|
932 |
✓✓ | 8032 |
if (token == ')') |
933 |
break; |
||
934 |
✓✗ | 6656 |
else if (token != STRING) |
935 |
goto fail; |
||
936 |
✓✓ | 6656 |
if (strcasecmp(kw, "NAME") == 0) { |
937 |
1376 |
obj->names = schema_parse_names(schema); |
|
938 |
✓✗ | 1376 |
if (obj->names == NULL) |
939 |
goto fail; |
||
940 |
1376 |
schema_link_obj_names(schema, obj); |
|
941 |
✓✓ | 6656 |
} else if (strcasecmp(kw, "DESC") == 0) { |
942 |
✓✗ | 448 |
if (schema_lex(schema, &obj->desc) != STRING) |
943 |
goto fail; |
||
944 |
✗✓ | 4832 |
} else if (strcasecmp(kw, "OBSOLETE") == 0) { |
945 |
obj->obsolete = 1; |
||
946 |
✓✓ | 4832 |
} else if (strcasecmp(kw, "SUP") == 0) { |
947 |
1312 |
obj->sup = schema_parse_objlist(schema); |
|
948 |
✓✗ | 1312 |
if (obj->sup == NULL) |
949 |
goto fail; |
||
950 |
✓✓ | 3520 |
} else if (strcasecmp(kw, "ABSTRACT") == 0) { |
951 |
32 |
obj->kind = KIND_ABSTRACT; |
|
952 |
✓✓ | 3520 |
} else if (strcasecmp(kw, "STRUCTURAL") == 0) { |
953 |
960 |
obj->kind = KIND_STRUCTURAL; |
|
954 |
✓✓ | 3488 |
} else if (strcasecmp(kw, "AUXILIARY") == 0) { |
955 |
352 |
obj->kind = KIND_AUXILIARY; |
|
956 |
✓✓ | 2528 |
} else if (strcasecmp(kw, "MUST") == 0) { |
957 |
1088 |
obj->must = schema_parse_attrlist(schema); |
|
958 |
✓✗ | 1088 |
if (obj->must == NULL) |
959 |
goto fail; |
||
960 |
✓✗ | 1088 |
} else if (strcasecmp(kw, "MAY") == 0) { |
961 |
1088 |
obj->may = schema_parse_attrlist(schema); |
|
962 |
✓✗ | 1088 |
if (obj->may == NULL) |
963 |
goto fail; |
||
964 |
} else if (strncasecmp(kw, "X-", 2) == 0) { |
||
965 |
/* unknown extension, eat argument(s) */ |
||
966 |
xnames = schema_parse_names(schema); |
||
967 |
if (xnames == NULL) |
||
968 |
goto fail; |
||
969 |
schema_free_name_list(xnames); |
||
970 |
} else { |
||
971 |
schema_err(schema, "syntax error at token '%s'", kw); |
||
972 |
goto fail; |
||
973 |
} |
||
974 |
6656 |
free(kw); |
|
975 |
} |
||
976 |
|||
977 |
/* Verify the subclassing is allowed. |
||
978 |
* |
||
979 |
* Structural object classes cannot subclass auxiliary object classes. |
||
980 |
* Auxiliary object classes cannot subclass structural object classes. |
||
981 |
* Abstract object classes cannot derive from structural or auxiliary |
||
982 |
* object classes. |
||
983 |
*/ |
||
984 |
✓✓ | 1376 |
if (obj->sup != NULL) { |
985 |
✓✓ | 5248 |
SLIST_FOREACH(optr, obj->sup, next) { |
986 |
✓✓✗✓ |
2304 |
if (obj->kind == KIND_STRUCTURAL && |
987 |
992 |
optr->object->kind == KIND_AUXILIARY) { |
|
988 |
log_warnx("structural object class '%s' cannot" |
||
989 |
" subclass auxiliary object class '%s'", |
||
990 |
OBJ_NAME(obj), OBJ_NAME(optr->object)); |
||
991 |
goto fail; |
||
992 |
} |
||
993 |
|||
994 |
✓✓✗✓ |
1632 |
if (obj->kind == KIND_AUXILIARY && |
995 |
320 |
optr->object->kind == KIND_STRUCTURAL) { |
|
996 |
log_warnx("auxiliary object class '%s' cannot" |
||
997 |
" subclass structural object class '%s'", |
||
998 |
OBJ_NAME(obj), OBJ_NAME(optr->object)); |
||
999 |
goto fail; |
||
1000 |
} |
||
1001 |
|||
1002 |
✗✓✗✗ |
1312 |
if (obj->kind == KIND_ABSTRACT && |
1003 |
optr->object->kind != KIND_ABSTRACT) { |
||
1004 |
log_warnx("abstract object class '%s' cannot" |
||
1005 |
" subclass non-abstract object class '%s'", |
||
1006 |
OBJ_NAME(obj), OBJ_NAME(optr->object)); |
||
1007 |
goto fail; |
||
1008 |
} |
||
1009 |
} |
||
1010 |
} |
||
1011 |
|||
1012 |
1376 |
return 0; |
|
1013 |
|||
1014 |
fail: |
||
1015 |
free(kw); |
||
1016 |
if (obj != NULL) { |
||
1017 |
if (obj->oid != NULL) { |
||
1018 |
RB_REMOVE(object_tree, &schema->objects, obj); |
||
1019 |
free(obj->oid); |
||
1020 |
} |
||
1021 |
free(obj->desc); |
||
1022 |
free(obj); |
||
1023 |
} |
||
1024 |
return -1; |
||
1025 |
1376 |
} |
|
1026 |
|||
1027 |
static int |
||
1028 |
schema_parse_objectidentifier(struct schema *schema) |
||
1029 |
{ |
||
1030 |
char *symname = NULL, *symoid = NULL; |
||
1031 |
char *oid = NULL; |
||
1032 |
|||
1033 |
if (schema_lex(schema, &symname) != STRING) |
||
1034 |
goto fail; |
||
1035 |
if (schema_lex(schema, &symoid) != STRING) |
||
1036 |
goto fail; |
||
1037 |
|||
1038 |
if (is_oidstr(symoid)) { |
||
1039 |
oid = symoid; |
||
1040 |
symoid = NULL; |
||
1041 |
} else if ((oid = lookup_symbolic_oid(schema, symoid)) == NULL) |
||
1042 |
goto fail; |
||
1043 |
|||
1044 |
if (push_symbolic_oid(schema, symname, oid) == NULL) |
||
1045 |
goto fail; |
||
1046 |
|||
1047 |
free(symoid); |
||
1048 |
return 0; |
||
1049 |
|||
1050 |
fail: |
||
1051 |
free(symname); |
||
1052 |
free(symoid); |
||
1053 |
free(oid); |
||
1054 |
return -1; |
||
1055 |
} |
||
1056 |
|||
1057 |
int |
||
1058 |
schema_parse(struct schema *schema, const char *filename) |
||
1059 |
{ |
||
1060 |
192 |
char *kw; |
|
1061 |
int token, ret = 0; |
||
1062 |
|||
1063 |
96 |
log_debug("parsing schema file '%s'", filename); |
|
1064 |
|||
1065 |
✗✓ | 96 |
if ((schema->fp = fopen(filename, "r")) == NULL) { |
1066 |
log_warn("%s", filename); |
||
1067 |
return -1; |
||
1068 |
} |
||
1069 |
96 |
schema->filename = filename; |
|
1070 |
96 |
schema->lineno = 1; |
|
1071 |
|||
1072 |
✓✗ | 11584 |
while (ret == 0) { |
1073 |
5792 |
token = schema_lex(schema, &kw); |
|
1074 |
✓✓ | 5792 |
if (token == STRING) { |
1075 |
✓✓ | 5696 |
if (strcasecmp(kw, "attributetype") == 0) |
1076 |
4320 |
ret = schema_parse_attributetype(schema); |
|
1077 |
✓✗ | 1376 |
else if (strcasecmp(kw, "objectclass") == 0) |
1078 |
1376 |
ret = schema_parse_objectclass(schema); |
|
1079 |
else if (strcasecmp(kw, "objectidentifier") == 0) |
||
1080 |
ret = schema_parse_objectidentifier(schema); |
||
1081 |
else { |
||
1082 |
schema_err(schema, "syntax error at '%s'", kw); |
||
1083 |
ret = -1; |
||
1084 |
} |
||
1085 |
✗✓✗✗ |
5696 |
if (ret == -1 && schema->error == 0) |
1086 |
schema_err(schema, "syntax error"); |
||
1087 |
5696 |
free(kw); |
|
1088 |
✗✓ | 5792 |
} else if (token == 0) { /* EOF */ |
1089 |
break; |
||
1090 |
} else { |
||
1091 |
schema_err(schema, "syntax error"); |
||
1092 |
ret = -1; |
||
1093 |
} |
||
1094 |
} |
||
1095 |
|||
1096 |
96 |
fclose(schema->fp); |
|
1097 |
96 |
schema->fp = NULL; |
|
1098 |
96 |
schema->filename = NULL; |
|
1099 |
|||
1100 |
96 |
return ret; |
|
1101 |
96 |
} |
|
1102 |
|||
1103 |
static int |
||
1104 |
schema_dump_names(const char *desc, struct name_list *nlist, |
||
1105 |
char *buf, size_t size) |
||
1106 |
{ |
||
1107 |
struct name *name; |
||
1108 |
|||
1109 |
if (nlist == NULL || SLIST_EMPTY(nlist)) |
||
1110 |
return 0; |
||
1111 |
|||
1112 |
if (strlcat(buf, " ", size) >= size || |
||
1113 |
strlcat(buf, desc, size) >= size) |
||
1114 |
return -1; |
||
1115 |
|||
1116 |
name = SLIST_FIRST(nlist); |
||
1117 |
if (SLIST_NEXT(name, next) == NULL) { |
||
1118 |
/* single name, no parenthesis */ |
||
1119 |
if (strlcat(buf, " '", size) >= size || |
||
1120 |
strlcat(buf, name->name, size) >= size || |
||
1121 |
strlcat(buf, "'", size) >= size) |
||
1122 |
return -1; |
||
1123 |
} else { |
||
1124 |
if (strlcat(buf, " ( ", size) >= size) |
||
1125 |
return -1; |
||
1126 |
SLIST_FOREACH(name, nlist, next) |
||
1127 |
if (strlcat(buf, "'", size) >= size || |
||
1128 |
strlcat(buf, name->name, size) >= size || |
||
1129 |
strlcat(buf, "' ", size) >= size) |
||
1130 |
return -1; |
||
1131 |
if (strlcat(buf, ")", size) >= size) |
||
1132 |
return -1; |
||
1133 |
} |
||
1134 |
|||
1135 |
return 0; |
||
1136 |
} |
||
1137 |
|||
1138 |
static int |
||
1139 |
schema_dump_attrlist(const char *desc, struct attr_list *alist, |
||
1140 |
char *buf, size_t size) |
||
1141 |
{ |
||
1142 |
struct attr_ptr *aptr; |
||
1143 |
|||
1144 |
if (alist == NULL || SLIST_EMPTY(alist)) |
||
1145 |
return 0; |
||
1146 |
|||
1147 |
if (strlcat(buf, " ", size) >= size || |
||
1148 |
strlcat(buf, desc, size) >= size) |
||
1149 |
return -1; |
||
1150 |
|||
1151 |
aptr = SLIST_FIRST(alist); |
||
1152 |
if (SLIST_NEXT(aptr, next) == NULL) { |
||
1153 |
/* single attribute, no parenthesis */ |
||
1154 |
if (strlcat(buf, " ", size) >= size || |
||
1155 |
strlcat(buf, ATTR_NAME(aptr->attr_type), size) >= size) |
||
1156 |
return -1; |
||
1157 |
} else { |
||
1158 |
if (strlcat(buf, " ( ", size) >= size) |
||
1159 |
return -1; |
||
1160 |
SLIST_FOREACH(aptr, alist, next) { |
||
1161 |
if (strlcat(buf, ATTR_NAME(aptr->attr_type), |
||
1162 |
size) >= size || |
||
1163 |
strlcat(buf, " ", size) >= size) |
||
1164 |
return -1; |
||
1165 |
if (SLIST_NEXT(aptr, next) != NULL && |
||
1166 |
strlcat(buf, "$ ", size) >= size) |
||
1167 |
return -1; |
||
1168 |
} |
||
1169 |
if (strlcat(buf, ")", size) >= size) |
||
1170 |
return -1; |
||
1171 |
} |
||
1172 |
|||
1173 |
return 0; |
||
1174 |
} |
||
1175 |
|||
1176 |
static int |
||
1177 |
schema_dump_objlist(const char *desc, struct obj_list *olist, |
||
1178 |
char *buf, size_t size) |
||
1179 |
{ |
||
1180 |
struct obj_ptr *optr; |
||
1181 |
|||
1182 |
if (olist == NULL || SLIST_EMPTY(olist)) |
||
1183 |
return 0; |
||
1184 |
|||
1185 |
if (strlcat(buf, " ", size) >= size || |
||
1186 |
strlcat(buf, desc, size) >= size) |
||
1187 |
return -1; |
||
1188 |
|||
1189 |
optr = SLIST_FIRST(olist); |
||
1190 |
if (SLIST_NEXT(optr, next) == NULL) { |
||
1191 |
/* single attribute, no parenthesis */ |
||
1192 |
if (strlcat(buf, " ", size) >= size || |
||
1193 |
strlcat(buf, OBJ_NAME(optr->object), size) >= size) |
||
1194 |
return -1; |
||
1195 |
} else { |
||
1196 |
if (strlcat(buf, " ( ", size) >= size) |
||
1197 |
return -1; |
||
1198 |
SLIST_FOREACH(optr, olist, next) { |
||
1199 |
if (strlcat(buf, OBJ_NAME(optr->object), size) >= size || |
||
1200 |
strlcat(buf, " ", size) >= size) |
||
1201 |
return -1; |
||
1202 |
if (SLIST_NEXT(optr, next) != NULL && |
||
1203 |
strlcat(buf, "$ ", size) >= size) |
||
1204 |
return -1; |
||
1205 |
} |
||
1206 |
if (strlcat(buf, ")", size) >= size) |
||
1207 |
return -1; |
||
1208 |
} |
||
1209 |
|||
1210 |
return 0; |
||
1211 |
} |
||
1212 |
|||
1213 |
int |
||
1214 |
schema_dump_object(struct object *obj, char *buf, size_t size) |
||
1215 |
{ |
||
1216 |
if (strlcpy(buf, "( ", size) >= size || |
||
1217 |
strlcat(buf, obj->oid, size) >= size) |
||
1218 |
return -1; |
||
1219 |
|||
1220 |
if (schema_dump_names("NAME", obj->names, buf, size) != 0) |
||
1221 |
return -1; |
||
1222 |
|||
1223 |
if (obj->desc != NULL) |
||
1224 |
if (strlcat(buf, " DESC '", size) >= size || |
||
1225 |
strlcat(buf, obj->desc, size) >= size || |
||
1226 |
strlcat(buf, "'", size) >= size) |
||
1227 |
return -1; |
||
1228 |
|||
1229 |
switch (obj->kind) { |
||
1230 |
case KIND_STRUCTURAL: |
||
1231 |
if (strlcat(buf, " STRUCTURAL", size) >= size) |
||
1232 |
return -1; |
||
1233 |
break; |
||
1234 |
case KIND_ABSTRACT: |
||
1235 |
if (strlcat(buf, " ABSTRACT", size) >= size) |
||
1236 |
return -1; |
||
1237 |
break; |
||
1238 |
case KIND_AUXILIARY: |
||
1239 |
if (strlcat(buf, " AUXILIARY", size) >= size) |
||
1240 |
return -1; |
||
1241 |
break; |
||
1242 |
} |
||
1243 |
|||
1244 |
if (schema_dump_objlist("SUP", obj->sup, buf, size) != 0) |
||
1245 |
return -1; |
||
1246 |
|||
1247 |
if (obj->obsolete && strlcat(buf, " OBSOLETE", size) >= size) |
||
1248 |
return -1; |
||
1249 |
|||
1250 |
if (schema_dump_attrlist("MUST", obj->must, buf, size) != 0) |
||
1251 |
return -1; |
||
1252 |
|||
1253 |
if (schema_dump_attrlist("MAY", obj->may, buf, size) != 0) |
||
1254 |
return -1; |
||
1255 |
|||
1256 |
if (strlcat(buf, " )", size) >= size) |
||
1257 |
return -1; |
||
1258 |
|||
1259 |
return 0; |
||
1260 |
} |
||
1261 |
|||
1262 |
int |
||
1263 |
schema_dump_attribute(struct attr_type *at, char *buf, size_t size) |
||
1264 |
{ |
||
1265 |
if (strlcpy(buf, "( ", size) >= size || |
||
1266 |
strlcat(buf, at->oid, size) >= size) |
||
1267 |
return -1; |
||
1268 |
|||
1269 |
if (schema_dump_names("NAME", at->names, buf, size) != 0) |
||
1270 |
return -1; |
||
1271 |
|||
1272 |
if (at->desc != NULL) |
||
1273 |
if (strlcat(buf, " DESC '", size) >= size || |
||
1274 |
strlcat(buf, at->desc, size) >= size || |
||
1275 |
strlcat(buf, "'", size) >= size) |
||
1276 |
return -1; |
||
1277 |
|||
1278 |
if (at->obsolete && strlcat(buf, " OBSOLETE", size) >= size) |
||
1279 |
return -1; |
||
1280 |
|||
1281 |
if (at->sup != NULL) |
||
1282 |
if (strlcat(buf, " SUP ", size) >= size || |
||
1283 |
strlcat(buf, ATTR_NAME(at->sup), size) >= size) |
||
1284 |
return -1; |
||
1285 |
|||
1286 |
if (at->equality != NULL) |
||
1287 |
if (strlcat(buf, " EQUALITY ", size) >= size || |
||
1288 |
strlcat(buf, at->equality->name, size) >= size) |
||
1289 |
return -1; |
||
1290 |
|||
1291 |
if (at->ordering != NULL) |
||
1292 |
if (strlcat(buf, " ORDERING ", size) >= size || |
||
1293 |
strlcat(buf, at->ordering->name, size) >= size) |
||
1294 |
return -1; |
||
1295 |
|||
1296 |
if (at->substr != NULL) |
||
1297 |
if (strlcat(buf, " SUBSTR ", size) >= size || |
||
1298 |
strlcat(buf, at->substr->name, size) >= size) |
||
1299 |
return -1; |
||
1300 |
|||
1301 |
if (at->syntax != NULL) |
||
1302 |
if (strlcat(buf, " SYNTAX ", size) >= size || |
||
1303 |
strlcat(buf, at->syntax->oid, size) >= size) |
||
1304 |
return -1; |
||
1305 |
|||
1306 |
if (at->single && strlcat(buf, " SINGLE-VALUE", size) >= size) |
||
1307 |
return -1; |
||
1308 |
|||
1309 |
if (at->collective && strlcat(buf, " COLLECTIVE", size) >= size) |
||
1310 |
return -1; |
||
1311 |
|||
1312 |
if (at->immutable && strlcat(buf, " NO-USER-MODIFICATION", size) >= size) |
||
1313 |
return -1; |
||
1314 |
|||
1315 |
switch (at->usage) { |
||
1316 |
case USAGE_USER_APP: |
||
1317 |
/* User application usage is the default. */ |
||
1318 |
break; |
||
1319 |
case USAGE_DIR_OP: |
||
1320 |
if (strlcat(buf, " USAGE directoryOperation", size) >= size) |
||
1321 |
return -1; |
||
1322 |
break; |
||
1323 |
case USAGE_DIST_OP: |
||
1324 |
if (strlcat(buf, " USAGE distributedOperation", size) >= size) |
||
1325 |
return -1; |
||
1326 |
break; |
||
1327 |
case USAGE_DSA_OP: |
||
1328 |
if (strlcat(buf, " USAGE dSAOperation", size) >= size) |
||
1329 |
return -1; |
||
1330 |
break; |
||
1331 |
} |
||
1332 |
|||
1333 |
if (strlcat(buf, " )", size) >= size) |
||
1334 |
return -1; |
||
1335 |
|||
1336 |
return 0; |
||
1337 |
} |
||
1338 |
|||
1339 |
int |
||
1340 |
schema_dump_match_rule(struct match_rule *mr, char *buf, size_t size) |
||
1341 |
{ |
||
1342 |
if (strlcpy(buf, "( ", size) >= size || |
||
1343 |
strlcat(buf, mr->oid, size) >= size || |
||
1344 |
strlcat(buf, " NAME '", size) >= size || |
||
1345 |
strlcat(buf, mr->name, size) >= size || |
||
1346 |
strlcat(buf, "' SYNTAX ", size) >= size || |
||
1347 |
strlcat(buf, mr->syntax_oid, size) >= size || |
||
1348 |
strlcat(buf, " )", size) >= size) |
||
1349 |
return -1; |
||
1350 |
|||
1351 |
return 0; |
||
1352 |
} |
||
1353 |
Generated by: GCOVR (Version 3.3) |