1*7cf58871Sjmatthew /* $OpenBSD: syntax.c,v 1.5 2017/05/28 15:48:49 jmatthew Exp $ */
27c686fcdSmartinh
37c686fcdSmartinh /*
47c686fcdSmartinh * Copyright (c) 2010 Martin Hedenfalk <martin@bzero.se>
57c686fcdSmartinh *
67c686fcdSmartinh * Permission to use, copy, modify, and distribute this software for any
77c686fcdSmartinh * purpose with or without fee is hereby granted, provided that the above
87c686fcdSmartinh * copyright notice and this permission notice appear in all copies.
97c686fcdSmartinh *
107c686fcdSmartinh * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117c686fcdSmartinh * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127c686fcdSmartinh * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137c686fcdSmartinh * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147c686fcdSmartinh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157c686fcdSmartinh * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167c686fcdSmartinh * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177c686fcdSmartinh */
187c686fcdSmartinh
197c686fcdSmartinh #include <sys/types.h>
207c686fcdSmartinh #include <sys/queue.h>
217c686fcdSmartinh #include <sys/tree.h>
227c686fcdSmartinh
237c686fcdSmartinh #include <ctype.h>
247c686fcdSmartinh #include <stdio.h>
257c686fcdSmartinh #include <stdlib.h>
267c686fcdSmartinh #include <string.h>
277c686fcdSmartinh
287c686fcdSmartinh #include "schema.h"
297c686fcdSmartinh #include "uuid.h"
307c686fcdSmartinh
317c686fcdSmartinh #define SYNTAX_DECL(TYPE) \
327c686fcdSmartinh static int syntax_is_##TYPE(struct schema *schema, char *value, size_t len)
337c686fcdSmartinh
347c686fcdSmartinh SYNTAX_DECL(bit_string);
357c686fcdSmartinh SYNTAX_DECL(boolean);
367c686fcdSmartinh SYNTAX_DECL(country);
377c686fcdSmartinh SYNTAX_DECL(directory_string);
387c686fcdSmartinh SYNTAX_DECL(dn);
397c686fcdSmartinh SYNTAX_DECL(gentime);
407c686fcdSmartinh SYNTAX_DECL(ia5_string);
417c686fcdSmartinh SYNTAX_DECL(integer);
427c686fcdSmartinh SYNTAX_DECL(numeric_string);
437c686fcdSmartinh SYNTAX_DECL(octet_string);
447c686fcdSmartinh SYNTAX_DECL(oid);
457c686fcdSmartinh SYNTAX_DECL(printable_string);
467c686fcdSmartinh SYNTAX_DECL(utctime);
477c686fcdSmartinh SYNTAX_DECL(uuid);
487c686fcdSmartinh
497c686fcdSmartinh static struct syntax syntaxes[] = {
507c686fcdSmartinh /*
517c686fcdSmartinh * Keep these sorted.
527c686fcdSmartinh */
537c686fcdSmartinh { "1.3.6.1.1.1.0.0", "NIS netgroup triple", NULL },
547c686fcdSmartinh { "1.3.6.1.1.1.0.1", "Boot parameter", NULL },
557c686fcdSmartinh { "1.3.6.1.1.16.1", "UUID", syntax_is_uuid },
567c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.11", "Country String", syntax_is_country },
577c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.12", "DN", syntax_is_dn },
587c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.14", "Delivery Method", NULL },
597c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.15", "Directory String", syntax_is_directory_string },
607c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.16", "DIT Content Rule Description", NULL },
617c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.17", "DIT Structure Rule Description", NULL },
627c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.21", "Enhanced Guide", NULL },
637c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.22", "Facsimile Telephone Number", NULL },
647c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.23", "Fax", NULL },
657c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.24", "Generalized Time", syntax_is_gentime },
667c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.25", "Guide", NULL },
677c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.26", "IA5 String", syntax_is_ia5_string },
687c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.27", "INTEGER", syntax_is_integer },
697c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.28", "JPEG", NULL },
707c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.3", "Attribute Type Description", NULL },
717c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.30", "Matching Rule Description", NULL },
727c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.31", "Matching Rule Use Description", NULL },
737c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.34", "Name And Optional UID", NULL },
747c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.35", "Name Form Description", NULL },
757c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.36", "Numeric String", syntax_is_numeric_string },
767c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.37", "Object Class Description", NULL },
777c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.38", "OID", syntax_is_oid },
787c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.39", "Other Mailbox", syntax_is_ia5_string },
797c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.40", "Octet String", syntax_is_octet_string },
807c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.41", "Postal Address", syntax_is_directory_string },
817c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.44", "Printable String", syntax_is_printable_string },
827c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.45", "Subtree Specification", NULL },
837c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.5", "Binary", NULL },
847c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.50", "Telephone Number", syntax_is_printable_string },
857c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.51", "Teletex Terminal Identifier", NULL },
867c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.52", "Telex Number", NULL },
877c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.53", "UTC Time", syntax_is_utctime },
887c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.54", "LDAP Syntax Description", NULL },
897c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.58", "Substring Assertion", NULL },
907c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.6", "Bit String", syntax_is_bit_string },
917c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.7", "Boolean", syntax_is_boolean },
927c686fcdSmartinh { "1.3.6.1.4.1.1466.115.121.1.8", "Certificate", NULL },
937c686fcdSmartinh
947c686fcdSmartinh };
957c686fcdSmartinh
967c686fcdSmartinh static int
syntax_cmp(const void * k,const void * e)977c686fcdSmartinh syntax_cmp(const void *k, const void *e)
987c686fcdSmartinh {
997c686fcdSmartinh return (strcmp(k, ((const struct syntax *)e)->oid));
1007c686fcdSmartinh }
1017c686fcdSmartinh
1027c686fcdSmartinh const struct syntax *
syntax_lookup(const char * oid)1037c686fcdSmartinh syntax_lookup(const char *oid)
1047c686fcdSmartinh {
1057c686fcdSmartinh return bsearch(oid, syntaxes, sizeof(syntaxes)/sizeof(syntaxes[0]),
1067c686fcdSmartinh sizeof(syntaxes[0]), syntax_cmp);
1077c686fcdSmartinh }
1087c686fcdSmartinh
1097c686fcdSmartinh /*
1107c686fcdSmartinh * A value of the Octet String syntax is a sequence of zero, one, or
1117c686fcdSmartinh * more arbitrary octets.
1127c686fcdSmartinh */
1137c686fcdSmartinh static int
syntax_is_octet_string(struct schema * schema,char * value,size_t len)1147c686fcdSmartinh syntax_is_octet_string(struct schema *schema, char *value, size_t len)
1157c686fcdSmartinh {
1167c686fcdSmartinh return 1;
1177c686fcdSmartinh }
1187c686fcdSmartinh
1197c686fcdSmartinh /*
1207c686fcdSmartinh * A string of one or more arbitrary UTF-8 characters.
1217c686fcdSmartinh */
1227c686fcdSmartinh static int
syntax_is_directory_string(struct schema * schema,char * value,size_t len)1237c686fcdSmartinh syntax_is_directory_string(struct schema *schema, char *value, size_t len)
1247c686fcdSmartinh {
1257c686fcdSmartinh /* FIXME: validate UTF-8 characters. */
1267c686fcdSmartinh return len >= 1 && *value != '\0';
1277c686fcdSmartinh }
1287c686fcdSmartinh
1297c686fcdSmartinh /*
1307c686fcdSmartinh * A value of the Printable String syntax is a string of one or more
1317c686fcdSmartinh * latin alphabetic, numeric, and selected punctuation characters as
1327c686fcdSmartinh * specified by the <PrintableCharacter> rule in Section 3.2.
1337c686fcdSmartinh *
1347c686fcdSmartinh * PrintableCharacter = ALPHA / DIGIT / SQUOTE / LPAREN / RPAREN /
1357c686fcdSmartinh * PLUS / COMMA / HYPHEN / DOT / EQUALS /
1367c686fcdSmartinh * SLASH / COLON / QUESTION / SPACE
1377c686fcdSmartinh */
1387c686fcdSmartinh static int
syntax_is_printable_string(struct schema * schema,char * value,size_t len)1397c686fcdSmartinh syntax_is_printable_string(struct schema *schema, char *value, size_t len)
1407c686fcdSmartinh {
1417c686fcdSmartinh static char *special = "'()+,-.=/:? ";
1427c686fcdSmartinh char *p;
1437c686fcdSmartinh
1447c686fcdSmartinh for (p = value; len > 0 && *p != '\0'; p++, len--) {
1453f9f973bSguenther if (!isalnum((unsigned char)*p) && strchr(special, *p) == NULL)
1467c686fcdSmartinh return 0;
1477c686fcdSmartinh }
1487c686fcdSmartinh
1497c686fcdSmartinh return (p != value);
1507c686fcdSmartinh }
1517c686fcdSmartinh
1527c686fcdSmartinh /*
1537c686fcdSmartinh * A value of the IA5 String syntax is a string of zero, one, or more
1547c686fcdSmartinh * characters from International Alphabet 5 (IA5).
1557c686fcdSmartinh * IA5String = *(%x00-7F)
1567c686fcdSmartinh */
1577c686fcdSmartinh static int
syntax_is_ia5_string(struct schema * schema,char * value,size_t len)1587c686fcdSmartinh syntax_is_ia5_string(struct schema *schema, char *value, size_t len)
1597c686fcdSmartinh {
1607c686fcdSmartinh char *p;
1617c686fcdSmartinh
1627c686fcdSmartinh for (p = value; *p != '\0'; p++) {
1637c686fcdSmartinh if ((unsigned char)*p > 0x7F)
1647c686fcdSmartinh return 0;
1657c686fcdSmartinh }
1667c686fcdSmartinh
1677c686fcdSmartinh return 1;
1687c686fcdSmartinh }
1697c686fcdSmartinh
1707c686fcdSmartinh /*
1717c686fcdSmartinh * A value of the Integer syntax is a whole number of unlimited magnitude.
1727c686fcdSmartinh * Integer = ( HYPHEN LDIGIT *DIGIT ) / number
1737c686fcdSmartinh * number = DIGIT / ( LDIGIT 1*DIGIT )
1747c686fcdSmartinh */
1757c686fcdSmartinh static int
syntax_is_integer(struct schema * schema,char * value,size_t len)1767c686fcdSmartinh syntax_is_integer(struct schema *schema, char *value, size_t len)
1777c686fcdSmartinh {
1787c686fcdSmartinh if (*value == '-')
1797c686fcdSmartinh value++;
1807c686fcdSmartinh if (*value == '0')
1817c686fcdSmartinh return value[1] == '\0';
1827c686fcdSmartinh for (value++; *value != '\0'; value++)
183a509009bSderaadt if (!isdigit((unsigned char)*value))
1847c686fcdSmartinh return 0;
1857c686fcdSmartinh return 1;
1867c686fcdSmartinh }
1877c686fcdSmartinh
1887c686fcdSmartinh static int
syntax_is_dn(struct schema * schema,char * value,size_t len)1897c686fcdSmartinh syntax_is_dn(struct schema *schema, char *value, size_t len)
1907c686fcdSmartinh {
1917c686fcdSmartinh if (!syntax_is_directory_string(schema, value, len))
1927c686fcdSmartinh return 0;
1937c686fcdSmartinh
1947c686fcdSmartinh /* FIXME: DN syntax not implemented */
1957c686fcdSmartinh
1967c686fcdSmartinh return 1;
1977c686fcdSmartinh }
1987c686fcdSmartinh
1997c686fcdSmartinh static int
syntax_is_oid(struct schema * schema,char * value,size_t len)2007c686fcdSmartinh syntax_is_oid(struct schema *schema, char *value, size_t len)
2017c686fcdSmartinh {
2027c686fcdSmartinh char *symoid = NULL;
2037c686fcdSmartinh
2047c686fcdSmartinh if (len == 0 || *value == '\0')
2057c686fcdSmartinh return 0;
2067c686fcdSmartinh if (is_oidstr(value))
2077c686fcdSmartinh return 1;
2087c686fcdSmartinh
2097c686fcdSmartinh /*
2107c686fcdSmartinh * Check for a symbolic OID: object class, attribute type or symoid.
2117c686fcdSmartinh */
2127c686fcdSmartinh if (lookup_object_by_name(schema, value) != NULL ||
2137c686fcdSmartinh lookup_attribute_by_name(schema, value) != NULL ||
2147c686fcdSmartinh (symoid = lookup_symbolic_oid(schema, value)) != NULL) {
2157c686fcdSmartinh free(symoid);
2167c686fcdSmartinh return 1;
2177c686fcdSmartinh }
2187c686fcdSmartinh
2197c686fcdSmartinh return 0;
2207c686fcdSmartinh }
2217c686fcdSmartinh
2227c686fcdSmartinh static int
syntax_is_uuid(struct schema * schema,char * value,size_t len)2237c686fcdSmartinh syntax_is_uuid(struct schema *schema, char *value, size_t len)
2247c686fcdSmartinh {
2257c686fcdSmartinh int i;
2267c686fcdSmartinh
2277c686fcdSmartinh if (len != 36)
2287c686fcdSmartinh return 0;
2297c686fcdSmartinh
2307c686fcdSmartinh #define IS_XDIGITS(n, c) \
2317c686fcdSmartinh do { \
2327c686fcdSmartinh for (i = 0; i < (n); i++) \
2337c686fcdSmartinh if (!isxdigit(*value++)) \
2347c686fcdSmartinh return 0; \
2357c686fcdSmartinh if (*value++ != (c)) \
2367c686fcdSmartinh return 0; \
2377c686fcdSmartinh } while(0)
2387c686fcdSmartinh
2397c686fcdSmartinh IS_XDIGITS(8, '-');
2407c686fcdSmartinh IS_XDIGITS(4, '-');
2417c686fcdSmartinh IS_XDIGITS(4, '-');
2427c686fcdSmartinh IS_XDIGITS(4, '-');
2437c686fcdSmartinh IS_XDIGITS(12, '\0');
2447c686fcdSmartinh
2457c686fcdSmartinh return 1;
2467c686fcdSmartinh }
2477c686fcdSmartinh
2487c686fcdSmartinh /*
2497c686fcdSmartinh * NumericString = 1*(DIGIT / SPACE)
2507c686fcdSmartinh */
2517c686fcdSmartinh static int
syntax_is_numeric_string(struct schema * schema,char * value,size_t len)2527c686fcdSmartinh syntax_is_numeric_string(struct schema *schema, char *value, size_t len)
2537c686fcdSmartinh {
2547c686fcdSmartinh char *p;
2557c686fcdSmartinh
2567c686fcdSmartinh for (p = value; *p != '\0'; p++)
257a509009bSderaadt if (!isdigit((unsigned char)*p) || *p != ' ')
2587c686fcdSmartinh return 0;
2597c686fcdSmartinh
2607c686fcdSmartinh return p != value;
2617c686fcdSmartinh }
2627c686fcdSmartinh
2637c686fcdSmartinh static int
syntax_is_time(struct schema * schema,char * value,size_t len,int gen)2647c686fcdSmartinh syntax_is_time(struct schema *schema, char *value, size_t len, int gen)
2657c686fcdSmartinh {
2667c686fcdSmartinh int n;
2677c686fcdSmartinh char *p = value;
2687c686fcdSmartinh
2697c686fcdSmartinh #define CHECK_RANGE(min, max) \
270dd8c3f8bSderaadt do { \
271a509009bSderaadt if (!isdigit((unsigned char)p[0]) || \
272a509009bSderaadt !isdigit((unsigned char)p[1])) \
2737c686fcdSmartinh return 0; \
2747c686fcdSmartinh n = (p[0] - '0') * 10 + (p[1] - '0'); \
2757c686fcdSmartinh if (n < min || n > max) \
2767c686fcdSmartinh return 0; \
277dd8c3f8bSderaadt p += 2; \
278dd8c3f8bSderaadt } while (0)
2797c686fcdSmartinh
2807c686fcdSmartinh if (gen)
281dd8c3f8bSderaadt CHECK_RANGE(0, 99); /* century */
282dd8c3f8bSderaadt CHECK_RANGE(0, 99); /* year */
283dd8c3f8bSderaadt CHECK_RANGE(1, 12); /* month */
284dd8c3f8bSderaadt CHECK_RANGE(1, 31); /* day */
2857c686fcdSmartinh /* FIXME: should check number of days in month */
2867c686fcdSmartinh CHECK_RANGE(0, 23); /* hour */
2877c686fcdSmartinh
288a509009bSderaadt if (!gen || isdigit((unsigned char)*p)) {
2897c686fcdSmartinh CHECK_RANGE(0, 59); /* minute */
290*7cf58871Sjmatthew if (isdigit((unsigned char)*p))
2917c686fcdSmartinh CHECK_RANGE(0, 59+gen); /* second or leap-second */
292*7cf58871Sjmatthew if (!gen && *p == '\0')
2937c686fcdSmartinh return 1;
2947c686fcdSmartinh }
2957c686fcdSmartinh /* fraction */
296a509009bSderaadt if (!gen && ((*p == ',' || *p == '.') &&
297a509009bSderaadt !isdigit((unsigned char)*++p)))
2987c686fcdSmartinh return 0;
2997c686fcdSmartinh
3007c686fcdSmartinh if (*p == '-' || *p == '+') {
3017c686fcdSmartinh ++p;
3027c686fcdSmartinh CHECK_RANGE(0, 23); /* hour */
303a509009bSderaadt if (!gen || isdigit((unsigned char)*p))
3047c686fcdSmartinh CHECK_RANGE(0, 59); /* minute */
3057c686fcdSmartinh } else if (*p++ != 'Z')
3067c686fcdSmartinh return 0;
3077c686fcdSmartinh
3087c686fcdSmartinh return *p == '\0';
3097c686fcdSmartinh }
3107c686fcdSmartinh
3117c686fcdSmartinh static int
syntax_is_gentime(struct schema * schema,char * value,size_t len)3127c686fcdSmartinh syntax_is_gentime(struct schema *schema, char *value, size_t len)
3137c686fcdSmartinh {
3147c686fcdSmartinh return syntax_is_time(schema, value, len, 1);
3157c686fcdSmartinh }
3167c686fcdSmartinh
3177c686fcdSmartinh static int
syntax_is_utctime(struct schema * schema,char * value,size_t len)3187c686fcdSmartinh syntax_is_utctime(struct schema *schema, char *value, size_t len)
3197c686fcdSmartinh {
3207c686fcdSmartinh return syntax_is_time(schema, value, len, 0);
3217c686fcdSmartinh }
3227c686fcdSmartinh
3237c686fcdSmartinh static int
syntax_is_country(struct schema * schema,char * value,size_t len)3247c686fcdSmartinh syntax_is_country(struct schema *schema, char *value, size_t len)
3257c686fcdSmartinh {
3267c686fcdSmartinh if (len != 2)
3277c686fcdSmartinh return 0;
3287c686fcdSmartinh return syntax_is_printable_string(schema, value, len);
3297c686fcdSmartinh }
3307c686fcdSmartinh
3317c686fcdSmartinh static int
syntax_is_bit_string(struct schema * schema,char * value,size_t len)3327c686fcdSmartinh syntax_is_bit_string(struct schema *schema, char *value, size_t len)
3337c686fcdSmartinh {
3347c686fcdSmartinh if (*value++ != '\'')
3357c686fcdSmartinh return 0;
3367c686fcdSmartinh
3377c686fcdSmartinh for (; *value != '\0'; value++) {
3387c686fcdSmartinh if (*value == '\'')
3397c686fcdSmartinh break;
3407c686fcdSmartinh if (*value != '0' && *value != '1')
3417c686fcdSmartinh return 0;
3427c686fcdSmartinh }
3437c686fcdSmartinh
3447c686fcdSmartinh if (++*value != 'B')
3457c686fcdSmartinh return 0;
3467c686fcdSmartinh
3477c686fcdSmartinh return *value == '\0';
3487c686fcdSmartinh }
3497c686fcdSmartinh
3507c686fcdSmartinh static int
syntax_is_boolean(struct schema * schema,char * value,size_t len)3517c686fcdSmartinh syntax_is_boolean(struct schema *schema, char *value, size_t len)
3527c686fcdSmartinh {
3537c686fcdSmartinh return strcmp(value, "TRUE") == 0 || strcmp(value, "FALSE") == 0;
3547c686fcdSmartinh }
3557c686fcdSmartinh
356