1 |
|
|
/* $OpenBSD: syntax.c,v 1.5 2017/05/28 15:48:49 jmatthew Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2010 Martin Hedenfalk <martin@bzero.se> |
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 |
|
|
#include <sys/queue.h> |
21 |
|
|
#include <sys/tree.h> |
22 |
|
|
|
23 |
|
|
#include <ctype.h> |
24 |
|
|
#include <stdio.h> |
25 |
|
|
#include <stdlib.h> |
26 |
|
|
#include <string.h> |
27 |
|
|
|
28 |
|
|
#include "schema.h" |
29 |
|
|
#include "uuid.h" |
30 |
|
|
|
31 |
|
|
#define SYNTAX_DECL(TYPE) \ |
32 |
|
|
static int syntax_is_##TYPE(struct schema *schema, char *value, size_t len) |
33 |
|
|
|
34 |
|
|
SYNTAX_DECL(bit_string); |
35 |
|
|
SYNTAX_DECL(boolean); |
36 |
|
|
SYNTAX_DECL(country); |
37 |
|
|
SYNTAX_DECL(directory_string); |
38 |
|
|
SYNTAX_DECL(dn); |
39 |
|
|
SYNTAX_DECL(gentime); |
40 |
|
|
SYNTAX_DECL(ia5_string); |
41 |
|
|
SYNTAX_DECL(integer); |
42 |
|
|
SYNTAX_DECL(numeric_string); |
43 |
|
|
SYNTAX_DECL(octet_string); |
44 |
|
|
SYNTAX_DECL(oid); |
45 |
|
|
SYNTAX_DECL(printable_string); |
46 |
|
|
SYNTAX_DECL(utctime); |
47 |
|
|
SYNTAX_DECL(uuid); |
48 |
|
|
|
49 |
|
|
static struct syntax syntaxes[] = { |
50 |
|
|
/* |
51 |
|
|
* Keep these sorted. |
52 |
|
|
*/ |
53 |
|
|
{ "1.3.6.1.1.1.0.0", "NIS netgroup triple", NULL }, |
54 |
|
|
{ "1.3.6.1.1.1.0.1", "Boot parameter", NULL }, |
55 |
|
|
{ "1.3.6.1.1.16.1", "UUID", syntax_is_uuid }, |
56 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.11", "Country String", syntax_is_country }, |
57 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.12", "DN", syntax_is_dn }, |
58 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.14", "Delivery Method", NULL }, |
59 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.15", "Directory String", syntax_is_directory_string }, |
60 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.16", "DIT Content Rule Description", NULL }, |
61 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.17", "DIT Structure Rule Description", NULL }, |
62 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.21", "Enhanced Guide", NULL }, |
63 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.22", "Facsimile Telephone Number", NULL }, |
64 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.23", "Fax", NULL }, |
65 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.24", "Generalized Time", syntax_is_gentime }, |
66 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.25", "Guide", NULL }, |
67 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.26", "IA5 String", syntax_is_ia5_string }, |
68 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.27", "INTEGER", syntax_is_integer }, |
69 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.28", "JPEG", NULL }, |
70 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.3", "Attribute Type Description", NULL }, |
71 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.30", "Matching Rule Description", NULL }, |
72 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.31", "Matching Rule Use Description", NULL }, |
73 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.34", "Name And Optional UID", NULL }, |
74 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.35", "Name Form Description", NULL }, |
75 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.36", "Numeric String", syntax_is_numeric_string }, |
76 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.37", "Object Class Description", NULL }, |
77 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.38", "OID", syntax_is_oid }, |
78 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.39", "Other Mailbox", syntax_is_ia5_string }, |
79 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.40", "Octet String", syntax_is_octet_string }, |
80 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.41", "Postal Address", syntax_is_directory_string }, |
81 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.44", "Printable String", syntax_is_printable_string }, |
82 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.45", "Subtree Specification", NULL }, |
83 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.5", "Binary", NULL }, |
84 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.50", "Telephone Number", syntax_is_printable_string }, |
85 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.51", "Teletex Terminal Identifier", NULL }, |
86 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.52", "Telex Number", NULL }, |
87 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.53", "UTC Time", syntax_is_utctime }, |
88 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.54", "LDAP Syntax Description", NULL }, |
89 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.58", "Substring Assertion", NULL }, |
90 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.6", "Bit String", syntax_is_bit_string }, |
91 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.7", "Boolean", syntax_is_boolean }, |
92 |
|
|
{ "1.3.6.1.4.1.1466.115.121.1.8", "Certificate", NULL }, |
93 |
|
|
|
94 |
|
|
}; |
95 |
|
|
|
96 |
|
|
static int |
97 |
|
|
syntax_cmp(const void *k, const void *e) |
98 |
|
|
{ |
99 |
|
37440 |
return (strcmp(k, ((const struct syntax *)e)->oid)); |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
const struct syntax * |
103 |
|
|
syntax_lookup(const char *oid) |
104 |
|
|
{ |
105 |
|
7616 |
return bsearch(oid, syntaxes, sizeof(syntaxes)/sizeof(syntaxes[0]), |
106 |
|
|
sizeof(syntaxes[0]), syntax_cmp); |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
/* |
110 |
|
|
* A value of the Octet String syntax is a sequence of zero, one, or |
111 |
|
|
* more arbitrary octets. |
112 |
|
|
*/ |
113 |
|
|
static int |
114 |
|
|
syntax_is_octet_string(struct schema *schema, char *value, size_t len) |
115 |
|
|
{ |
116 |
|
|
return 1; |
117 |
|
|
} |
118 |
|
|
|
119 |
|
|
/* |
120 |
|
|
* A string of one or more arbitrary UTF-8 characters. |
121 |
|
|
*/ |
122 |
|
|
static int |
123 |
|
|
syntax_is_directory_string(struct schema *schema, char *value, size_t len) |
124 |
|
|
{ |
125 |
|
|
/* FIXME: validate UTF-8 characters. */ |
126 |
|
|
return len >= 1 && *value != '\0'; |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
/* |
130 |
|
|
* A value of the Printable String syntax is a string of one or more |
131 |
|
|
* latin alphabetic, numeric, and selected punctuation characters as |
132 |
|
|
* specified by the <PrintableCharacter> rule in Section 3.2. |
133 |
|
|
* |
134 |
|
|
* PrintableCharacter = ALPHA / DIGIT / SQUOTE / LPAREN / RPAREN / |
135 |
|
|
* PLUS / COMMA / HYPHEN / DOT / EQUALS / |
136 |
|
|
* SLASH / COLON / QUESTION / SPACE |
137 |
|
|
*/ |
138 |
|
|
static int |
139 |
|
|
syntax_is_printable_string(struct schema *schema, char *value, size_t len) |
140 |
|
|
{ |
141 |
|
|
static char *special = "'()+,-.=/:? "; |
142 |
|
|
char *p; |
143 |
|
|
|
144 |
|
|
for (p = value; len > 0 && *p != '\0'; p++, len--) { |
145 |
|
|
if (!isalnum((unsigned char)*p) && strchr(special, *p) == NULL) |
146 |
|
|
return 0; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
return (p != value); |
150 |
|
|
} |
151 |
|
|
|
152 |
|
|
/* |
153 |
|
|
* A value of the IA5 String syntax is a string of zero, one, or more |
154 |
|
|
* characters from International Alphabet 5 (IA5). |
155 |
|
|
* IA5String = *(%x00-7F) |
156 |
|
|
*/ |
157 |
|
|
static int |
158 |
|
|
syntax_is_ia5_string(struct schema *schema, char *value, size_t len) |
159 |
|
|
{ |
160 |
|
|
char *p; |
161 |
|
|
|
162 |
|
|
for (p = value; *p != '\0'; p++) { |
163 |
|
|
if ((unsigned char)*p > 0x7F) |
164 |
|
|
return 0; |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
return 1; |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
/* |
171 |
|
|
* A value of the Integer syntax is a whole number of unlimited magnitude. |
172 |
|
|
* Integer = ( HYPHEN LDIGIT *DIGIT ) / number |
173 |
|
|
* number = DIGIT / ( LDIGIT 1*DIGIT ) |
174 |
|
|
*/ |
175 |
|
|
static int |
176 |
|
|
syntax_is_integer(struct schema *schema, char *value, size_t len) |
177 |
|
|
{ |
178 |
|
|
if (*value == '-') |
179 |
|
|
value++; |
180 |
|
|
if (*value == '0') |
181 |
|
|
return value[1] == '\0'; |
182 |
|
|
for (value++; *value != '\0'; value++) |
183 |
|
|
if (!isdigit((unsigned char)*value)) |
184 |
|
|
return 0; |
185 |
|
|
return 1; |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
static int |
189 |
|
|
syntax_is_dn(struct schema *schema, char *value, size_t len) |
190 |
|
|
{ |
191 |
|
|
if (!syntax_is_directory_string(schema, value, len)) |
192 |
|
|
return 0; |
193 |
|
|
|
194 |
|
|
/* FIXME: DN syntax not implemented */ |
195 |
|
|
|
196 |
|
|
return 1; |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
static int |
200 |
|
|
syntax_is_oid(struct schema *schema, char *value, size_t len) |
201 |
|
|
{ |
202 |
|
|
char *symoid = NULL; |
203 |
|
|
|
204 |
|
|
if (len == 0 || *value == '\0') |
205 |
|
|
return 0; |
206 |
|
|
if (is_oidstr(value)) |
207 |
|
|
return 1; |
208 |
|
|
|
209 |
|
|
/* |
210 |
|
|
* Check for a symbolic OID: object class, attribute type or symoid. |
211 |
|
|
*/ |
212 |
|
|
if (lookup_object_by_name(schema, value) != NULL || |
213 |
|
|
lookup_attribute_by_name(schema, value) != NULL || |
214 |
|
|
(symoid = lookup_symbolic_oid(schema, value)) != NULL) { |
215 |
|
|
free(symoid); |
216 |
|
|
return 1; |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
return 0; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
static int |
223 |
|
|
syntax_is_uuid(struct schema *schema, char *value, size_t len) |
224 |
|
|
{ |
225 |
|
|
int i; |
226 |
|
|
|
227 |
|
|
if (len != 36) |
228 |
|
|
return 0; |
229 |
|
|
|
230 |
|
|
#define IS_XDIGITS(n, c) \ |
231 |
|
|
do { \ |
232 |
|
|
for (i = 0; i < (n); i++) \ |
233 |
|
|
if (!isxdigit(*value++)) \ |
234 |
|
|
return 0; \ |
235 |
|
|
if (*value++ != (c)) \ |
236 |
|
|
return 0; \ |
237 |
|
|
} while(0) |
238 |
|
|
|
239 |
|
|
IS_XDIGITS(8, '-'); |
240 |
|
|
IS_XDIGITS(4, '-'); |
241 |
|
|
IS_XDIGITS(4, '-'); |
242 |
|
|
IS_XDIGITS(4, '-'); |
243 |
|
|
IS_XDIGITS(12, '\0'); |
244 |
|
|
|
245 |
|
|
return 1; |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
/* |
249 |
|
|
* NumericString = 1*(DIGIT / SPACE) |
250 |
|
|
*/ |
251 |
|
|
static int |
252 |
|
|
syntax_is_numeric_string(struct schema *schema, char *value, size_t len) |
253 |
|
|
{ |
254 |
|
|
char *p; |
255 |
|
|
|
256 |
|
|
for (p = value; *p != '\0'; p++) |
257 |
|
|
if (!isdigit((unsigned char)*p) || *p != ' ') |
258 |
|
|
return 0; |
259 |
|
|
|
260 |
|
|
return p != value; |
261 |
|
|
} |
262 |
|
|
|
263 |
|
|
static int |
264 |
|
|
syntax_is_time(struct schema *schema, char *value, size_t len, int gen) |
265 |
|
|
{ |
266 |
|
|
int n; |
267 |
|
|
char *p = value; |
268 |
|
|
|
269 |
|
|
#define CHECK_RANGE(min, max) \ |
270 |
|
|
do { \ |
271 |
|
|
if (!isdigit((unsigned char)p[0]) || \ |
272 |
|
|
!isdigit((unsigned char)p[1])) \ |
273 |
|
|
return 0; \ |
274 |
|
|
n = (p[0] - '0') * 10 + (p[1] - '0'); \ |
275 |
|
|
if (n < min || n > max) \ |
276 |
|
|
return 0; \ |
277 |
|
|
p += 2; \ |
278 |
|
|
} while (0) |
279 |
|
|
|
280 |
|
|
if (gen) |
281 |
|
|
CHECK_RANGE(0, 99); /* century */ |
282 |
|
|
CHECK_RANGE(0, 99); /* year */ |
283 |
|
|
CHECK_RANGE(1, 12); /* month */ |
284 |
|
|
CHECK_RANGE(1, 31); /* day */ |
285 |
|
|
/* FIXME: should check number of days in month */ |
286 |
|
|
CHECK_RANGE(0, 23); /* hour */ |
287 |
|
|
|
288 |
|
|
if (!gen || isdigit((unsigned char)*p)) { |
289 |
|
|
CHECK_RANGE(0, 59); /* minute */ |
290 |
|
|
if (isdigit((unsigned char)*p)) |
291 |
|
|
CHECK_RANGE(0, 59+gen); /* second or leap-second */ |
292 |
|
|
if (!gen && *p == '\0') |
293 |
|
|
return 1; |
294 |
|
|
} |
295 |
|
|
/* fraction */ |
296 |
|
|
if (!gen && ((*p == ',' || *p == '.') && |
297 |
|
|
!isdigit((unsigned char)*++p))) |
298 |
|
|
return 0; |
299 |
|
|
|
300 |
|
|
if (*p == '-' || *p == '+') { |
301 |
|
|
++p; |
302 |
|
|
CHECK_RANGE(0, 23); /* hour */ |
303 |
|
|
if (!gen || isdigit((unsigned char)*p)) |
304 |
|
|
CHECK_RANGE(0, 59); /* minute */ |
305 |
|
|
} else if (*p++ != 'Z') |
306 |
|
|
return 0; |
307 |
|
|
|
308 |
|
|
return *p == '\0'; |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
static int |
312 |
|
|
syntax_is_gentime(struct schema *schema, char *value, size_t len) |
313 |
|
|
{ |
314 |
|
|
return syntax_is_time(schema, value, len, 1); |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
static int |
318 |
|
|
syntax_is_utctime(struct schema *schema, char *value, size_t len) |
319 |
|
|
{ |
320 |
|
|
return syntax_is_time(schema, value, len, 0); |
321 |
|
|
} |
322 |
|
|
|
323 |
|
|
static int |
324 |
|
|
syntax_is_country(struct schema *schema, char *value, size_t len) |
325 |
|
|
{ |
326 |
|
|
if (len != 2) |
327 |
|
|
return 0; |
328 |
|
|
return syntax_is_printable_string(schema, value, len); |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
static int |
332 |
|
|
syntax_is_bit_string(struct schema *schema, char *value, size_t len) |
333 |
|
|
{ |
334 |
|
|
if (*value++ != '\'') |
335 |
|
|
return 0; |
336 |
|
|
|
337 |
|
|
for (; *value != '\0'; value++) { |
338 |
|
|
if (*value == '\'') |
339 |
|
|
break; |
340 |
|
|
if (*value != '0' && *value != '1') |
341 |
|
|
return 0; |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
if (++*value != 'B') |
345 |
|
|
return 0; |
346 |
|
|
|
347 |
|
|
return *value == '\0'; |
348 |
|
|
} |
349 |
|
|
|
350 |
|
|
static int |
351 |
|
|
syntax_is_boolean(struct schema *schema, char *value, size_t len) |
352 |
|
|
{ |
353 |
|
|
return strcmp(value, "TRUE") == 0 || strcmp(value, "FALSE") == 0; |
354 |
|
|
} |
355 |
|
|
|