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 return (strcmp(k, ((const struct syntax *)e)->oid)); 100 } 101 102 const struct syntax * 103 syntax_lookup(const char *oid) 104 { 105 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 356