xref: /openbsd-src/usr.sbin/ldapd/syntax.c (revision 7cf58871ee65b9ef4bb7f120fab8e4b93ca5a410)
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