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 34SYNTAX_DECL(bit_string); 35SYNTAX_DECL(boolean); 36SYNTAX_DECL(country); 37SYNTAX_DECL(directory_string); 38SYNTAX_DECL(dn); 39SYNTAX_DECL(gentime); 40SYNTAX_DECL(ia5_string); 41SYNTAX_DECL(integer); 42SYNTAX_DECL(numeric_string); 43SYNTAX_DECL(octet_string); 44SYNTAX_DECL(oid); 45SYNTAX_DECL(printable_string); 46SYNTAX_DECL(utctime); 47SYNTAX_DECL(uuid); 48 49static 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 96static int 97syntax_cmp(const void *k, const void *e) 98{ 99 return (strcmp(k, ((const struct syntax *)e)->oid)); 100} 101 102const struct syntax * 103syntax_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 */ 113static int 114syntax_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 */ 122static int 123syntax_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 */ 138static int 139syntax_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 */ 157static int 158syntax_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 */ 175static int 176syntax_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 188static int 189syntax_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 199static int 200syntax_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 222static int 223syntax_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 */ 251static int 252syntax_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 263static int 264syntax_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 311static int 312syntax_is_gentime(struct schema *schema, char *value, size_t len) 313{ 314 return syntax_is_time(schema, value, len, 1); 315} 316 317static int 318syntax_is_utctime(struct schema *schema, char *value, size_t len) 319{ 320 return syntax_is_time(schema, value, len, 0); 321} 322 323static int 324syntax_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 331static int 332syntax_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 350static int 351syntax_is_boolean(struct schema *schema, char *value, size_t len) 352{ 353 return strcmp(value, "TRUE") == 0 || strcmp(value, "FALSE") == 0; 354} 355 356