cis.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /* cis.c - caseignorestring syntax routines */
  13. /*
  14. * This file actually implements numerous syntax plugins:
  15. *
  16. * Boolean
  17. * CountryString
  18. * DirectoryString
  19. * GeneralizedTime
  20. * OID
  21. * PostalAddress
  22. * PrintableString
  23. */
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include "syntax.h"
  28. static int cis_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
  29. Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
  30. static int cis_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
  31. char *final, Slapi_Value **bvals );
  32. static int cis_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
  33. Slapi_Value ***ivals, int ftype );
  34. static int cis_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
  35. Slapi_Value ***ivals, int ftype );
  36. static int cis_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
  37. char *final, Slapi_Value ***ivals );
  38. static int cis_compare(struct berval *v1, struct berval *v2);
  39. static int dirstring_validate(struct berval *val);
  40. static int boolean_validate(struct berval *val);
  41. static int time_validate(struct berval *val);
  42. static int country_validate(struct berval *val);
  43. static int postal_validate(struct berval *val);
  44. static int oid_validate(struct berval *val);
  45. static int printable_validate(struct berval *val);
  46. static void cis_normalize(
  47. Slapi_PBlock *pb,
  48. char *s,
  49. int trim_spaces,
  50. char **alt
  51. );
  52. /*
  53. Even though the official RFC 4517 says that the postal syntax
  54. line values must contain at least 1 character (i.e. no $$), it
  55. seems that most, if not all, address book and other applications that
  56. use postal address syntax values expect to be able to store empty
  57. lines/values - so for now, allow it
  58. */
  59. static const int postal_allow_empty_lines = 1;
  60. /*
  61. * Attribute syntaxes. We treat all of these the same for now, even though
  62. * the specifications (e.g., RFC 2252) impose various constraints on the
  63. * the format for each of these.
  64. *
  65. * Note: the first name is the official one from RFC 2252.
  66. */
  67. static char *dirstring_names[] = { "DirectoryString", "cis",
  68. "caseignorestring", DIRSTRING_SYNTAX_OID, 0 };
  69. static char *boolean_names[] = { "Boolean", BOOLEAN_SYNTAX_OID, 0 };
  70. static char *time_names[] = { "GeneralizedTime", "time",
  71. GENERALIZEDTIME_SYNTAX_OID, 0 };
  72. #define GENERALIZEDTIMEMATCH_OID "2.5.13.27"
  73. #define GENERALIZEDTIMEORDERINGMATCH_OID "2.5.13.28"
  74. static char *country_names[] = { "Country String",
  75. COUNTRYSTRING_SYNTAX_OID, 0};
  76. static char *postal_names[] = { "Postal Address",
  77. POSTALADDRESS_SYNTAX_OID, 0};
  78. static char *oid_names[] = { "OID",
  79. OID_SYNTAX_OID, 0};
  80. static char *printable_names[] = { "Printable String",
  81. PRINTABLESTRING_SYNTAX_OID, 0};
  82. /*
  83. TBD (XXX)
  84. "1.3.6.1.4.1.1466.115.121.1.16 \"DIT Content Rule Description
  85. \" "
  86. "1.3.6.1.4.1.1466.115.121.1.17 \"DIT Structure Rule Descripti
  87. on\" "
  88. "1.3.6.1.4.1.1466.115.121.1.20 \"DSE Type\" "
  89. "1.3.6.1.4.1.1466.115.121.1.30 \"Matching Rule Description\"
  90. "
  91. "1.3.6.1.4.1.1466.115.121.1.31 \"Matching Rule Use Descriptio
  92. n\" "
  93. "1.3.6.1.4.1.1466.115.121.1.35 \"Name Form Description\" "
  94. "1.3.6.1.4.1.1466.115.121.1.44 \"Printable String\" "
  95. "1.3.6.1.4.1.1466.115.121.1.45 \"Subtree Specification\" "
  96. "1.3.6.1.4.1.1466.115.121.1.54 \"LDAP Syntax Description\" "
  97. "1.3.6.1.4.1.1466.115.121.1.55 \"Modify Rights\" "
  98. "1.3.6.1.4.1.1466.115.121.1.56 \"LDAP Schema Description\" "
  99. "1.3.6.1.4.1.1466.115.121.1.25 \"Guide\" "
  100. "1.3.6.1.4.1.1466.115.121.1.52 \"Telex Number\" "
  101. "1.3.6.1.4.1.1466.115.121.1.51 \"Teletex Terminal Identifier\
  102. " "
  103. "1.3.6.1.4.1.1466.115.121.1.14 \"Delivery Method\" "
  104. "1.3.6.1.4.1.1466.115.121.1.43 \"Presentation Address\" "
  105. "1.3.6.1.4.1.1466.115.121.1.21 \"Enhanced Guide\" "
  106. "1.3.6.1.4.1.1466.115.121.1.34 \"Name and Optional UID\" "
  107. "1.2.840.113556.1.4.905 \"CaseIgnoreString\" "
  108. "1.3.6.1.1.1.0.0 \"nisNetgroupTripleSyntax\" "
  109. "1.3.6.1.1.1.0.1 \"bootParameterSyntax\" ");
  110. */
  111. static Slapi_PluginDesc dirstring_pdesc = { "directorystring-syntax",
  112. VENDOR, DS_PACKAGE_VERSION,
  113. "DirectoryString attribute syntax plugin" };
  114. static Slapi_PluginDesc boolean_pdesc = { "boolean-syntax",
  115. VENDOR, DS_PACKAGE_VERSION,
  116. "Boolean attribute syntax plugin" };
  117. static Slapi_PluginDesc time_pdesc = { "time-syntax",
  118. VENDOR, DS_PACKAGE_VERSION,
  119. "GeneralizedTime attribute syntax plugin" };
  120. static Slapi_PluginDesc country_pdesc = { "countrystring-syntax",
  121. VENDOR, DS_PACKAGE_VERSION,
  122. "Country String attribute syntax plugin" };
  123. static Slapi_PluginDesc postal_pdesc = { "postaladdress-syntax",
  124. VENDOR, DS_PACKAGE_VERSION,
  125. "Postal Address attribute syntax plugin" };
  126. static Slapi_PluginDesc oid_pdesc = { "oid-syntax",
  127. VENDOR, DS_PACKAGE_VERSION,
  128. "OID attribute syntax plugin" };
  129. static Slapi_PluginDesc printable_pdesc = { "printablestring-syntax",
  130. VENDOR, DS_PACKAGE_VERSION,
  131. "Printable String attribtue syntax plugin" };
  132. static const char *generalizedTimeMatch_names[] = {"generalizedTimeMatch", GENERALIZEDTIMEMATCH_OID, NULL};
  133. static const char *generalizedTimeOrderingMatch_names[] = {"generalizedTimeOrderingMatch", GENERALIZEDTIMEORDERINGMATCH_OID, NULL};
  134. static const char *booleanMatch_names[] = {"booleanMatch", "2.5.13.13", NULL};
  135. static const char *caseIgnoreIA5Match_names[] = {"caseIgnoreIA5Match", "1.3.6.1.4.1.1466.109.114.2", NULL};
  136. static const char *caseIgnoreIA5SubstringsMatch_names[] = {"caseIgnoreIA5SubstringsMatch", "1.3.6.1.4.1.1466.109.114.3", NULL};
  137. static const char *caseIgnoreListMatch_names[] = {"caseIgnoreListMatch", "2.5.13.11", NULL};
  138. static const char *caseIgnoreListSubstringsMatch_names[] = {"caseIgnoreListSubstringsMatch", "2.5.13.12", NULL};
  139. static const char *caseIgnoreMatch_names[] = {"caseIgnoreMatch", "2.5.13.2", NULL};
  140. static const char *caseIgnoreOrderingMatch_names[] = {"caseIgnoreOrderingMatch", "2.5.13.3", NULL};
  141. static const char *caseIgnoreSubstringsMatch_names[] = {"caseIgnoreSubstringsMatch", "2.5.13.4", NULL};
  142. static const char *directoryStringFirstComponentMatch_names[] = {"directoryStringFirstComponentMatch", "2.5.13.31", NULL};
  143. static const char *objectIdentifierMatch_names[] = {"objectIdentifierMatch", "2.5.13.0", NULL};
  144. static const char *objectIdentifierFirstComponentMatch_names[] = {"objectIdentifierFirstComponentMatch", "2.5.13.30", NULL};
  145. static char *dirString_syntaxes[] = {COUNTRYSTRING_SYNTAX_OID,
  146. DIRSTRING_SYNTAX_OID,
  147. PRINTABLESTRING_SYNTAX_OID,NULL};
  148. static char *dirStringCompat_syntaxes[] = {COUNTRYSTRING_SYNTAX_OID,
  149. PRINTABLESTRING_SYNTAX_OID,NULL};
  150. static char *caseIgnoreIA5SubstringsMatch_syntaxes[] = {IA5STRING_SYNTAX_OID,NULL};
  151. static char *caseIgnoreListSubstringsMatch_syntaxes[] = {POSTALADDRESS_SYNTAX_OID,NULL};
  152. static char *objectIdentifierFirstComponentMatch_syntaxes[] = {DIRSTRING_SYNTAX_OID, NULL};
  153. static struct mr_plugin_def mr_plugin_table[] = {
  154. {{GENERALIZEDTIMEMATCH_OID, NULL /* no alias? */,
  155. "generalizedTimeMatch", "The rule evaluates to TRUE if and only if the attribute value represents the same universal coordinated time as the assertion value.",
  156. GENERALIZEDTIME_SYNTAX_OID, 0 /* not obsolete */, NULL /* no other syntaxes supported */ },
  157. {"generalizedTimeMatch-mr", VENDOR, DS_PACKAGE_VERSION, "generalizedTimeMatch matching rule plugin"}, /* plugin desc */
  158. generalizedTimeMatch_names, /* matching rule name/oid/aliases */
  159. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  160. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  161. {{GENERALIZEDTIMEORDERINGMATCH_OID, NULL /* no alias? */,
  162. "generalizedTimeOrderingMatch", "The rule evaluates to TRUE if and only if the attribute value represents a universal coordinated time that is earlier than the universal coordinated time represented by the assertion value.",
  163. GENERALIZEDTIME_SYNTAX_OID, 0 /* not obsolete */, NULL /* no other syntaxes supported */ },
  164. {"generalizedTimeOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "generalizedTimeOrderingMatch matching rule plugin"}, /* plugin desc */
  165. generalizedTimeOrderingMatch_names, /* matching rule name/oid/aliases */
  166. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  167. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  168. /* strictly speaking, boolean is case sensitive */
  169. {{"2.5.13.13", NULL, "booleanMatch", "The booleanMatch rule compares an assertion value of the Boolean "
  170. "syntax to an attribute value of a syntax (e.g., the Boolean syntax) "
  171. "whose corresponding ASN.1 type is BOOLEAN. "
  172. "The rule evaluates to TRUE if and only if the attribute value and the "
  173. "assertion value are both TRUE or both FALSE.", BOOLEAN_SYNTAX_OID, 0, NULL /* no other syntaxes supported */}, /* matching rule desc */
  174. {"booleanMatch-mr", VENDOR, DS_PACKAGE_VERSION, "booleanMatch matching rule plugin"}, /* plugin desc */
  175. booleanMatch_names, /* matching rule name/oid/aliases */
  176. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  177. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  178. {{"1.3.6.1.4.1.1466.109.114.2", NULL, "caseIgnoreIA5Match", "The caseIgnoreIA5Match rule compares an assertion value of the IA5 "
  179. "String syntax to an attribute value of a syntax (e.g., the IA5 String "
  180. "syntax) whose corresponding ASN.1 type is IA5String. "
  181. "The rule evaluates to TRUE if and only if the prepared attribute "
  182. "value character string and the prepared assertion value character "
  183. "string have the same number of characters and corresponding "
  184. "characters have the same code point. "
  185. "In preparing the attribute value and assertion value for comparison, "
  186. "characters are case folded in the Map preparation step, and only "
  187. "Insignificant Space Handling is applied in the Insignificant "
  188. "Character Handling step.", IA5STRING_SYNTAX_OID, 0, NULL /* no other syntaxes supported */}, /* matching rule desc */
  189. {"caseIgnoreIA5Match-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreIA5Match matching rule plugin"}, /* plugin desc */
  190. caseIgnoreIA5Match_names, /* matching rule name/oid/aliases */
  191. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  192. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  193. {{"1.3.6.1.4.1.1466.109.114.3", NULL, "caseIgnoreIA5SubstringsMatch", "The caseIgnoreIA5SubstringsMatch rule compares an assertion value of "
  194. "the Substring Assertion syntax to an attribute value of a syntax "
  195. "(e.g., the IA5 String syntax) whose corresponding ASN.1 type is "
  196. "IA5String. "
  197. "The rule evaluates to TRUE if and only if (1) the prepared substrings "
  198. "of the assertion value match disjoint portions of the prepared "
  199. "attribute value character string in the order of the substrings in "
  200. "the assertion value, (2) an <initial> substring, if present, matches "
  201. "the beginning of the prepared attribute value character string, and "
  202. "(3) a <final> substring, if present, matches the end of the prepared "
  203. "attribute value character string. A prepared substring matches a "
  204. "portion of the prepared attribute value character string if "
  205. "corresponding characters have the same code point. "
  206. "In preparing the attribute value and assertion value substrings for "
  207. "comparison, characters are case folded in the Map preparation step, "
  208. "and only Insignificant Space Handling is applied in the Insignificant "
  209. "Character Handling step.", "1.3.6.1.4.1.1466.115.121.1.58", 0, caseIgnoreIA5SubstringsMatch_syntaxes}, /* matching rule desc */
  210. {"caseIgnoreIA5SubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreIA5SubstringsMatch matching rule plugin"}, /* plugin desc */
  211. caseIgnoreIA5SubstringsMatch_names, /* matching rule name/oid/aliases */
  212. NULL, NULL, NULL, cis_filter_sub, cis_values2keys,
  213. NULL, cis_assertion2keys_sub, NULL, cis_normalize},
  214. {{"2.5.13.2", NULL, "caseIgnoreMatch", "The caseIgnoreMatch rule compares an assertion value of the Directory "
  215. "String syntax to an attribute value of a syntax (e.g., the Directory "
  216. "String, Printable String, Country String, or Telephone Number syntax) "
  217. "whose corresponding ASN.1 type is DirectoryString or one of its "
  218. "alternative string types. "
  219. "The rule evaluates to TRUE if and only if the prepared attribute "
  220. "value character string and the prepared assertion value character "
  221. "string have the same number of characters and corresponding "
  222. "characters have the same code point. "
  223. "In preparing the attribute value and assertion value for comparison, "
  224. "characters are case folded in the Map preparation step, and only "
  225. "Insignificant Space Handling is applied in the Insignificant "
  226. "Character Handling step.", DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
  227. {"caseIgnoreMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreMatch matching rule plugin"}, /* plugin desc */
  228. caseIgnoreMatch_names, /* matching rule name/oid/aliases */
  229. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  230. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  231. {{"2.5.13.3", NULL, "caseIgnoreOrderingMatch", "The caseIgnoreOrderingMatch rule compares an assertion value of the "
  232. "Directory String syntax to an attribute value of a syntax (e.g., the "
  233. "Directory String, Printable String, Country String, or Telephone "
  234. "Number syntax) whose corresponding ASN.1 type is DirectoryString or "
  235. "one of its alternative string types. "
  236. "The rule evaluates to TRUE if and only if, in the code point "
  237. "collation order, the prepared attribute value character string "
  238. "appears earlier than the prepared assertion value character string; "
  239. "i.e., the attribute value is \"less than\" the assertion value. "
  240. "In preparing the attribute value and assertion value for comparison, "
  241. "characters are case folded in the Map preparation step, and only "
  242. "Insignificant Space Handling is applied in the Insignificant "
  243. "Character Handling step.", DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
  244. {"caseIgnoreOrderingMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreOrderingMatch matching rule plugin"}, /* plugin desc */
  245. caseIgnoreOrderingMatch_names, /* matching rule name/oid/aliases */
  246. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  247. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  248. {{"2.5.13.4", NULL, "caseIgnoreSubstringsMatch", "The caseIgnoreSubstringsMatch rule compares an assertion value of the "
  249. "Substring Assertion syntax to an attribute value of a syntax (e.g., "
  250. "the Directory String, Printable String, Country String, or Telephone "
  251. "Number syntax) whose corresponding ASN.1 type is DirectoryString or "
  252. "one of its alternative string types. "
  253. "The rule evaluates to TRUE if and only if (1) the prepared substrings "
  254. "of the assertion value match disjoint portions of the prepared "
  255. "attribute value character string in the order of the substrings in "
  256. "the assertion value, (2) an <initial> substring, if present, matches "
  257. "the beginning of the prepared attribute value character string, and "
  258. "(3) a <final> substring, if present, matches the end of the prepared "
  259. "attribute value character string. A prepared substring matches a "
  260. "portion of the prepared attribute value character string if "
  261. "corresponding characters have the same code point. "
  262. "In preparing the attribute value and assertion value substrings for "
  263. "comparison, characters are case folded in the Map preparation step, "
  264. "and only Insignificant Space Handling is applied in the Insignificant "
  265. "Character Handling step.", "1.3.6.1.4.1.1466.115.121.1.58", 0, dirString_syntaxes}, /* matching rule desc */
  266. {"caseIgnoreSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreSubstringsMatch matching rule plugin"}, /* plugin desc */
  267. caseIgnoreSubstringsMatch_names, /* matching rule name/oid/aliases */
  268. NULL, NULL, NULL, cis_filter_sub, cis_values2keys,
  269. NULL, cis_assertion2keys_sub, cis_compare, cis_normalize},
  270. {{"2.5.13.11", NULL, "caseIgnoreListMatch", "The caseIgnoreListMatch rule compares an assertion value that is a "
  271. "sequence of strings to an attribute value of a syntax (e.g., the "
  272. "Postal Address syntax) whose corresponding ASN.1 type is a SEQUENCE "
  273. "OF the DirectoryString ASN.1 type. "
  274. "The rule evaluates to TRUE if and only if the attribute value and the "
  275. "assertion value have the same number of strings and corresponding "
  276. "strings (by position) match according to the caseIgnoreMatch matching "
  277. "rule. "
  278. "In [X.520], the assertion syntax for this matching rule is defined to "
  279. "be: "
  280. " SEQUENCE OF DirectoryString {ub-match} "
  281. "That is, it is different from the corresponding type for the Postal "
  282. "Address syntax. The choice of the Postal Address syntax for the "
  283. "assertion syntax of the caseIgnoreListMatch in LDAP should not be "
  284. "seen as limiting the matching rule to apply only to attributes with "
  285. "the Postal Address syntax.", POSTALADDRESS_SYNTAX_OID, 0, NULL /* postal syntax only */}, /* matching rule desc */
  286. {"caseIgnoreListMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreListMatch matching rule plugin"}, /* plugin desc */
  287. caseIgnoreListMatch_names, /* matching rule name/oid/aliases */
  288. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  289. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  290. {{"2.5.13.12", NULL, "caseIgnoreListSubstringsMatch", "The caseIgnoreListSubstringsMatch rule compares an assertion value of "
  291. "the Substring Assertion syntax to an attribute value of a syntax "
  292. "(e.g., the Postal Address syntax) whose corresponding ASN.1 type is a "
  293. "SEQUENCE OF the DirectoryString ASN.1 type. "
  294. "The rule evaluates to TRUE if and only if the assertion value "
  295. "matches, per the caseIgnoreSubstringsMatch rule, the character string "
  296. "formed by concatenating the strings of the attribute value, except "
  297. "that none of the <initial>, <any>, or <final> substrings of the "
  298. "assertion value are considered to match a substring of the "
  299. "concatenated string which spans more than one of the original strings "
  300. "of the attribute value. "
  301. "Note that, in terms of the LDAP-specific encoding of the Postal "
  302. "Address syntax, the concatenated string omits the <DOLLAR> line "
  303. "separator and the escaping of \"\\\" and \"$\" characters.",
  304. "1.3.6.1.4.1.1466.115.121.1.58", 0, caseIgnoreListSubstringsMatch_syntaxes}, /* matching rule desc */
  305. {"caseIgnoreListSubstringsMatch-mr", VENDOR, DS_PACKAGE_VERSION, "caseIgnoreListSubstringsMatch matching rule plugin"}, /* plugin desc */
  306. caseIgnoreListSubstringsMatch_names, /* matching rule name/oid/aliases */
  307. NULL, NULL, NULL, cis_filter_sub, cis_values2keys,
  308. NULL, cis_assertion2keys_sub, cis_compare, cis_normalize},
  309. {{"2.5.13.0", NULL, "objectIdentifierMatch", "The objectIdentifierMatch rule compares an assertion value of the OID "
  310. "syntax to an attribute value of a syntax (e.g., the OID syntax) whose "
  311. "corresponding ASN.1 type is OBJECT IDENTIFIER. "
  312. "The rule evaluates to TRUE if and only if the assertion value and the "
  313. "attribute value represent the same object identifier; that is, the "
  314. "same sequence of integers, whether represented explicitly in the "
  315. "<numericoid> form of <oid> or implicitly in the <descr> form (see "
  316. "[RFC4512]). "
  317. "If an LDAP client supplies an assertion value in the <descr> form and "
  318. "the chosen descriptor is not recognized by the server, then the "
  319. "objectIdentifierMatch rule evaluates to Undefined.",
  320. OID_SYNTAX_OID, 0, NULL /* OID syntax only for now */}, /* matching rule desc */
  321. {"objectIdentifierMatch-mr", VENDOR, DS_PACKAGE_VERSION, "objectIdentifierMatch matching rule plugin"}, /* plugin desc */
  322. objectIdentifierMatch_names, /* matching rule name/oid/aliases */
  323. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  324. cis_assertion2keys_ava, NULL, cis_compare, cis_normalize},
  325. {{"2.5.13.31", NULL, "directoryStringFirstComponentMatch", "The directoryStringFirstComponentMatch rule compares an assertion "
  326. "value of the Directory String syntax to an attribute value of a "
  327. "syntax whose corresponding ASN.1 type is a SEQUENCE with a mandatory "
  328. "first component of the DirectoryString ASN.1 type. "
  329. "Note that the assertion syntax of this matching rule differs from the "
  330. "attribute syntax of attributes for which this is the equality "
  331. "matching rule. "
  332. "The rule evaluates to TRUE if and only if the assertion value matches "
  333. "the first component of the attribute value using the rules of "
  334. "caseIgnoreMatch.", DIRSTRING_SYNTAX_OID, 0, dirStringCompat_syntaxes}, /* matching rule desc */
  335. {"directoryStringFirstComponentMatch-mr", VENDOR, DS_PACKAGE_VERSION, "directoryStringFirstComponentMatch matching rule plugin"}, /* plugin desc */
  336. directoryStringFirstComponentMatch_names, /* matching rule name/oid/aliases */
  337. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  338. cis_assertion2keys_ava, NULL, NULL, cis_normalize},
  339. {{"2.5.13.30", NULL, "objectIdentifierFirstComponentMatch",
  340. "The objectIdentifierFirstComponentMatch rule compares an assertion "
  341. "value of the OID syntax to an attribute value of a syntax (e.g., the "
  342. "Attribute Type Description, DIT Content Rule Description, LDAP Syntax "
  343. "Description, Matching Rule Description, Matching Rule Use "
  344. "Description, Name Form Description, or Object Class Description "
  345. "syntax) whose corresponding ASN.1 type is a SEQUENCE with a mandatory "
  346. "first component of the OBJECT IDENTIFIER ASN.1 type. "
  347. "Note that the assertion syntax of this matching rule differs from the "
  348. "attribute syntax of attributes for which this is the equality "
  349. "matching rule. "
  350. "The rule evaluates to TRUE if and only if the assertion value matches "
  351. "the first component of the attribute value using the rules of "
  352. "objectIdentifierMatch.", OID_SYNTAX_OID, 0, objectIdentifierFirstComponentMatch_syntaxes}, /* matching rule desc */
  353. {"objectIdentifierFirstComponentMatch-mr", VENDOR, DS_PACKAGE_VERSION, "objectIdentifierFirstComponentMatch matching rule plugin"}, /* plugin desc */
  354. objectIdentifierFirstComponentMatch_names, /* matching rule name/oid/aliases */
  355. NULL, NULL, cis_filter_ava, NULL, cis_values2keys,
  356. cis_assertion2keys_ava, NULL, NULL, cis_normalize}
  357. };
  358. static size_t mr_plugin_table_size = sizeof(mr_plugin_table)/sizeof(mr_plugin_table[0]);
  359. static int
  360. matching_rule_plugin_init(Slapi_PBlock *pb)
  361. {
  362. return syntax_matching_rule_plugin_init(pb, mr_plugin_table, mr_plugin_table_size);
  363. }
  364. static int
  365. register_matching_rule_plugins()
  366. {
  367. return syntax_register_matching_rule_plugins(mr_plugin_table, mr_plugin_table_size, matching_rule_plugin_init);
  368. }
  369. /*
  370. * register_cis_like_plugin(): register all items for a cis-like plugin.
  371. */
  372. static int
  373. register_cis_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
  374. char **names, char *oid, void *validate_fn )
  375. {
  376. int rc, flags;
  377. rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
  378. (void *) SLAPI_PLUGIN_VERSION_01 );
  379. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
  380. (void *) pdescp );
  381. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
  382. (void *) cis_filter_ava );
  383. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_SUB,
  384. (void *) cis_filter_sub );
  385. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
  386. (void *) cis_values2keys );
  387. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
  388. (void *) cis_assertion2keys_ava );
  389. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB,
  390. (void *) cis_assertion2keys_sub );
  391. flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
  392. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
  393. (void *) &flags );
  394. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
  395. (void *) names );
  396. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
  397. (void *) oid );
  398. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
  399. (void *) cis_compare );
  400. if (validate_fn != NULL) {
  401. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALIDATE,
  402. (void *)validate_fn );
  403. }
  404. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NORMALIZE,
  405. (void *) cis_normalize );
  406. return( rc );
  407. }
  408. int
  409. cis_init( Slapi_PBlock *pb )
  410. {
  411. int rc;
  412. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> cis_init\n", 0, 0, 0 );
  413. rc = register_cis_like_plugin( pb, &dirstring_pdesc, dirstring_names,
  414. DIRSTRING_SYNTAX_OID, dirstring_validate );
  415. rc |= register_matching_rule_plugins();
  416. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= cis_init %d\n", rc, 0, 0 );
  417. return( rc );
  418. }
  419. int
  420. boolean_init( Slapi_PBlock *pb )
  421. {
  422. int rc;
  423. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> boolean_init\n", 0, 0, 0 );
  424. rc = register_cis_like_plugin( pb, &boolean_pdesc, boolean_names,
  425. BOOLEAN_SYNTAX_OID, boolean_validate );
  426. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= boolean_init %d\n", rc, 0, 0 );
  427. return( rc );
  428. }
  429. int
  430. time_init( Slapi_PBlock *pb )
  431. {
  432. int rc;
  433. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> time_init\n", 0, 0, 0 );
  434. rc = register_cis_like_plugin( pb, &time_pdesc, time_names,
  435. GENERALIZEDTIME_SYNTAX_OID, time_validate );
  436. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= time_init %d\n", rc, 0, 0 );
  437. return( rc );
  438. }
  439. int
  440. country_init( Slapi_PBlock *pb )
  441. {
  442. int rc;
  443. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> country_init\n", 0, 0, 0 );
  444. rc = register_cis_like_plugin( pb, &country_pdesc, country_names,
  445. COUNTRYSTRING_SYNTAX_OID, country_validate );
  446. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= country_init %d\n", rc, 0, 0 );
  447. return( rc );
  448. }
  449. int
  450. postal_init( Slapi_PBlock *pb )
  451. {
  452. int rc;
  453. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> postal_init\n", 0, 0, 0 );
  454. rc = register_cis_like_plugin( pb, &postal_pdesc, postal_names,
  455. POSTALADDRESS_SYNTAX_OID, postal_validate );
  456. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= postal_init %d\n", rc, 0, 0 );
  457. return( rc );
  458. }
  459. int
  460. oid_init( Slapi_PBlock *pb )
  461. {
  462. int rc;
  463. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> oid_init\n", 0, 0, 0 );
  464. rc = register_cis_like_plugin( pb, &oid_pdesc, oid_names, OID_SYNTAX_OID, oid_validate );
  465. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= oid_init %d\n", rc, 0, 0 );
  466. return( rc );
  467. }
  468. int
  469. printable_init( Slapi_PBlock *pb )
  470. {
  471. int rc;
  472. LDAPDebug( LDAP_DEBUG_PLUGIN, "=> printable_init\n", 0, 0, 0 );
  473. rc = register_cis_like_plugin( pb, &printable_pdesc, printable_names,
  474. PRINTABLESTRING_SYNTAX_OID, printable_validate );
  475. LDAPDebug( LDAP_DEBUG_PLUGIN, "<= printable_init %d\n", rc, 0, 0 );
  476. return( rc );
  477. }
  478. static int
  479. cis_filter_ava(
  480. Slapi_PBlock *pb,
  481. struct berval *bvfilter,
  482. Slapi_Value **bvals,
  483. int ftype,
  484. Slapi_Value **retVal
  485. )
  486. {
  487. int filter_normalized = 0;
  488. int syntax = SYNTAX_CIS;
  489. if (pb) {
  490. slapi_pblock_get( pb, SLAPI_PLUGIN_SYNTAX_FILTER_NORMALIZED,
  491. &filter_normalized );
  492. if (filter_normalized) {
  493. syntax |= SYNTAX_NORM_FILT;
  494. }
  495. }
  496. return( string_filter_ava( bvfilter, bvals, syntax, ftype,
  497. retVal ) );
  498. }
  499. static int
  500. cis_filter_sub(
  501. Slapi_PBlock *pb,
  502. char *initial,
  503. char **any,
  504. char *final,
  505. Slapi_Value **bvals
  506. )
  507. {
  508. return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_CIS ) );
  509. }
  510. static int
  511. cis_values2keys(
  512. Slapi_PBlock *pb,
  513. Slapi_Value **vals,
  514. Slapi_Value ***ivals,
  515. int ftype
  516. )
  517. {
  518. return( string_values2keys( pb, vals, ivals, SYNTAX_CIS, ftype ) );
  519. }
  520. static int
  521. cis_assertion2keys_ava(
  522. Slapi_PBlock *pb,
  523. Slapi_Value *val,
  524. Slapi_Value ***ivals,
  525. int ftype
  526. )
  527. {
  528. return(string_assertion2keys_ava( pb, val, ivals, SYNTAX_CIS, ftype ));
  529. }
  530. static int
  531. cis_assertion2keys_sub(
  532. Slapi_PBlock *pb,
  533. char *initial,
  534. char **any,
  535. char *final,
  536. Slapi_Value ***ivals
  537. )
  538. {
  539. return( string_assertion2keys_sub( pb, initial, any, final, ivals,
  540. SYNTAX_CIS ) );
  541. }
  542. static int cis_compare(
  543. struct berval *v1,
  544. struct berval *v2
  545. )
  546. {
  547. return value_cmp(v1,v2,SYNTAX_CIS,3 /* Normalise both values */);
  548. }
  549. static int dirstring_validate(
  550. struct berval *val
  551. )
  552. {
  553. int rc = 0; /* assume the value is valid */
  554. char *p = NULL;
  555. char *end = NULL;
  556. /* Per RFC4517:
  557. *
  558. * DirectoryString = 1*UTF8
  559. */
  560. if ((val != NULL) && (val->bv_len > 0)) {
  561. p = val->bv_val;
  562. end = &(val->bv_val[val->bv_len - 1]);
  563. rc = utf8string_validate(p, end, NULL);
  564. } else {
  565. rc = 1;
  566. goto exit;
  567. }
  568. exit:
  569. return( rc );
  570. }
  571. static int boolean_validate(
  572. struct berval *val
  573. )
  574. {
  575. int rc = 0; /* assume the value is valid */
  576. /* Per RFC4517:
  577. *
  578. * Boolean = "TRUE" / "FALSE"
  579. */
  580. if (val != NULL) {
  581. if (val->bv_len == 4) {
  582. if (strncmp(val->bv_val, "TRUE", 4) != 0) {
  583. rc = 1;
  584. goto exit;
  585. }
  586. } else if (val->bv_len == 5) {
  587. if (strncmp(val->bv_val, "FALSE", 5) != 0) {
  588. rc = 1;
  589. goto exit;
  590. }
  591. } else {
  592. rc = 1;
  593. goto exit;
  594. }
  595. } else {
  596. rc = 1;
  597. }
  598. exit:
  599. return(rc);
  600. }
  601. static int time_validate(
  602. struct berval *val
  603. )
  604. {
  605. int rc = 0; /* assume the value is valid */
  606. int i = 0;
  607. const char *p = NULL;
  608. char *end = NULL;
  609. /* Per RFC4517:
  610. *
  611. * GeneralizedTime = century year month day hour
  612. * [ minute [ second / leap-second ] ]
  613. * [ fraction ]
  614. * g-time-zone
  615. *
  616. * century = 2(%x30-39) ; "00" to "99"
  617. * year = 2(%x30-39) ; "00" to "99"
  618. * month = ( %x30 %x31-39 ) ; "01" (January) to "09"
  619. * / ( %x31 %x30-32 ) ; "10 to "12"
  620. * day = ( %x30 %x31-39 ) ; "01" to "09"
  621. * / ( %x31-x32 %x30-39 ) ; "10" to "29"
  622. * / ( %x33 %x30-31 ) ; "30" to "31"
  623. * hour = ( %x30-31 %x30-39 ) / ( %x32 %x30-33 ) ; "00" to "23"
  624. * minute = %x30-35 %x30-39 ; "00" to "59"
  625. *
  626. * second = ( %x30-35 - %x30-39 ) ; "00" to "59"
  627. * leap-second = ( %x36 %x30 ) ; "60"
  628. *
  629. * fraction = ( DOT / COMMA ) 1*(%x30-39)
  630. * g-time-zone = %x5A ; "Z"
  631. * / g-differential
  632. * g-differential = ( MINUS / PLUS ) hour [ minute ]
  633. */
  634. if (val != NULL) {
  635. /* A valid GeneralizedTime should be at least 11 characters. There
  636. * is no upper bound due to the variable length of "fraction". */
  637. if (val->bv_len < 11) {
  638. rc = 1;
  639. goto exit;
  640. }
  641. /* We're guaranteed that the value is at least 11 characters, so we
  642. * don't need to bother checking if we're at the end of the value
  643. * until we start processing the "minute" part of the value. */
  644. p = val->bv_val;
  645. end = &(val->bv_val[val->bv_len - 1]);
  646. /* Process "century year". First 4 characters can be any valid digit. */
  647. for (i=0; i<4; i++) {
  648. if (!isdigit(*p)) {
  649. rc = 1;
  650. goto exit;
  651. }
  652. p++;
  653. }
  654. /* Process "month". Next character can be "0" or "1". */
  655. if (*p == '0') {
  656. p++;
  657. /* any LDIGIT is valid now */
  658. if (!IS_LDIGIT(*p)) {
  659. rc = 1;
  660. goto exit;
  661. }
  662. p++;
  663. } else if (*p == '1') {
  664. p++;
  665. /* only "0"-"2" are valid now */
  666. if ((*p < '0') || (*p > '2')) {
  667. rc = 1;
  668. goto exit;
  669. }
  670. p++;
  671. } else {
  672. rc = 1;
  673. goto exit;
  674. }
  675. /* Process "day". Next character can be "0"-"3". */
  676. if (*p == '0') {
  677. p++;
  678. /* any LDIGIT is valid now */
  679. if (!IS_LDIGIT(*p)) {
  680. rc = 1;
  681. goto exit;
  682. }
  683. p++;
  684. } else if ((*p == '1') || (*p == '2')) {
  685. p++;
  686. /* any digit is valid now */
  687. if (!isdigit(*p)) {
  688. rc = 1;
  689. goto exit;
  690. }
  691. p++;
  692. } else if (*p == '3') {
  693. p++;
  694. /* only "0"-"1" are valid now */
  695. if ((*p != '0') && (*p != '1')) {
  696. rc = 1;
  697. goto exit;
  698. }
  699. p++;
  700. } else {
  701. rc = 1;
  702. goto exit;
  703. }
  704. /* Process "hour". Next character can be "0"-"2". */
  705. if ((*p == '0') || (*p == '1')) {
  706. p++;
  707. /* any digit is valid now */
  708. if (!isdigit(*p)) {
  709. rc = 1;
  710. goto exit;
  711. }
  712. p++;
  713. } else if (*p == '2') {
  714. p++;
  715. /* only "0"-"3" are valid now */
  716. if ((*p < '0') || (*p > '3')) {
  717. rc = 1;
  718. goto exit;
  719. }
  720. p++;
  721. } else {
  722. rc = 1;
  723. goto exit;
  724. }
  725. /* Time for the optional stuff. We know we have at least one character here, but
  726. * we need to start checking for the end of the string afterwards.
  727. *
  728. * See if a "minute" was specified. */
  729. if ((*p >= '0') && (*p <= '5')) {
  730. p++;
  731. /* any digit is valid for the second char of a minute */
  732. if ((p > end) || (!isdigit(*p))) {
  733. rc = 1;
  734. goto exit;
  735. }
  736. p++;
  737. /* At this point, there has to at least be a "g-time-zone" left.
  738. * Make sure we're not at the end of the string. */
  739. if (p > end) {
  740. rc = 1;
  741. goto exit;
  742. }
  743. /* See if a "second" or "leap-second" was specified. */
  744. if ((*p >= '0') && (*p <= '5')) {
  745. p++;
  746. /* any digit is valid now */
  747. if ((p > end) || (!isdigit(*p))) {
  748. rc = 1;
  749. goto exit;
  750. }
  751. p++;
  752. } else if (*p == '6') {
  753. p++;
  754. /* only a '0' is valid now */
  755. if ((p > end) || (*p != '0')) {
  756. rc = 1;
  757. goto exit;
  758. }
  759. p++;
  760. }
  761. /* At this point, there has to at least be a "g-time-zone" left.
  762. * Make sure we're not at the end of the string. */
  763. if (p > end) {
  764. rc = 1;
  765. goto exit;
  766. }
  767. }
  768. /* See if a fraction was specified. */
  769. if ((*p == '.') || (*p == ',')) {
  770. p++;
  771. /* An arbitrary length string of digit chars is allowed here.
  772. * Ensure we have at least one digit character. */
  773. if ((p >= end) || (!isdigit(*p))) {
  774. rc = 1;
  775. goto exit;
  776. }
  777. /* Just loop through the rest of the fraction until we encounter a non-digit */
  778. p++;
  779. while ((p < end) && (isdigit(*p))) {
  780. p++;
  781. }
  782. }
  783. /* Process "g-time-zone". We either end with 'Z', or have a differential. */
  784. if (p == end) {
  785. if (*p != 'Z') {
  786. rc = 1;
  787. goto exit;
  788. }
  789. } else if (p < end) {
  790. if ((*p != '-') && (*p != '+')) {
  791. rc = 1;
  792. goto exit;
  793. } else {
  794. /* A "g-differential" was specified. An "hour" must be present now. */
  795. p++;
  796. if ((*p == '0') || (*p == '1')) {
  797. p++;
  798. /* any digit is valid now */
  799. if ((p > end) || !isdigit(*p)) {
  800. rc = 1;
  801. goto exit;
  802. }
  803. p++;
  804. } else if (*p == '2') {
  805. p++;
  806. /* only "0"-"3" are valid now */
  807. if ((p > end) || (*p < '0') || (*p > '3')) {
  808. rc = 1;
  809. goto exit;
  810. }
  811. p++;
  812. } else {
  813. rc = 1;
  814. goto exit;
  815. }
  816. /* See if an optional minute is present ("00"-"59"). */
  817. if (p <= end) {
  818. /* "0"-"5" are valid now */
  819. if ((*p < '0') || (*p > '5')) {
  820. rc = 1;
  821. goto exit;
  822. }
  823. p++;
  824. /* We should be at the last character of the string
  825. * now, which must be a valid digit. */
  826. if ((p != end) || !isdigit(*p)) {
  827. rc = 1;
  828. goto exit;
  829. }
  830. }
  831. }
  832. } else {
  833. /* Premature end of string */
  834. rc = 1;
  835. goto exit;
  836. }
  837. } else {
  838. rc = 1;
  839. goto exit;
  840. }
  841. exit:
  842. return( rc );
  843. }
  844. static int country_validate(
  845. struct berval *val
  846. )
  847. {
  848. int rc = 0; /* assume the value is valid */
  849. /* Per RFC4517:
  850. *
  851. * CountryString = 2(PrintableCharacter)
  852. */
  853. if (val != NULL) {
  854. if ((val->bv_len != 2) || !IS_PRINTABLE(val->bv_val[0]) || !IS_PRINTABLE(val->bv_val[1])) {
  855. rc = 1;
  856. goto exit;
  857. }
  858. } else {
  859. rc = 1;
  860. }
  861. exit:
  862. return(rc);
  863. }
  864. static int postal_validate(
  865. struct berval *val
  866. )
  867. {
  868. int rc = 0; /* assume the value is valid */
  869. const char *p = NULL;
  870. const char *start = NULL;
  871. char *end = NULL;
  872. /* Per RFC4517:
  873. * PostalAddress = line *( DOLLAR line )
  874. * line = 1*line-char
  875. * line-char = %x00-23
  876. * / (%x5C "24") ; escaped "$"
  877. * / %x25-5B
  878. * / (%x5C "5C") ; escaped "\"
  879. * / %x5D-7F
  880. * / UTFMB
  881. */
  882. if ((val != NULL) && (val->bv_val != NULL) && (val->bv_len > 0)) {
  883. start = val->bv_val;
  884. end = &(val->bv_val[val->bv_len - 1]);
  885. for (p = start; p <= end; p++) {
  886. /* look for a '\' and make sure it's only used to escape a '$' or a '\' */
  887. if (*p == '\\') {
  888. p++;
  889. /* ensure that we're not at the end of the value */
  890. if ((p > end) || ((strncmp(p, "24", 2) != 0) && (strncasecmp(p, "5C", 2) != 0))) {
  891. rc = 1;
  892. goto exit;
  893. } else {
  894. /* advance the pointer to point to the end
  895. * of the hex code for the escaped character */
  896. p++;
  897. }
  898. } else if ((*p == '$') || (p == end)) {
  899. /* This signifies the end of a line. We need
  900. * to ensure that the line is not empty. */
  901. /* make sure the value doesn't end with a '$' */
  902. if ((p == start) || ((*p == '$') && (p == end))) {
  903. if (!postal_allow_empty_lines) {
  904. rc = 1;
  905. goto exit;
  906. } /* else allow it */
  907. } else if ((rc = utf8string_validate(start, p, NULL)) != 0) {
  908. /* Make sure the line (start to p) is valid UTF-8. */
  909. goto exit;
  910. }
  911. /* make the start pointer point to the
  912. * beginning of the next line */
  913. start = p + 1;
  914. }
  915. }
  916. } else {
  917. rc = 1;
  918. }
  919. exit:
  920. return(rc);
  921. }
  922. static int oid_validate(
  923. struct berval *val
  924. )
  925. {
  926. int rc = 0; /* assume the value is valid */
  927. const char *p = NULL;
  928. const char *end = NULL;
  929. /* Per RFC4512:
  930. *
  931. * oid = descr / numericoid
  932. * descr = keystring
  933. */
  934. if ((val != NULL) && (val->bv_len > 0)) {
  935. p = val->bv_val;
  936. end = &(val->bv_val[val->bv_len - 1]);
  937. /* check if the value matches the descr form */
  938. if (IS_LEADKEYCHAR(*p)) {
  939. rc = keystring_validate(p, end);
  940. /* check if the value matches the numericoid form */
  941. } else if (isdigit(*p)) {
  942. rc = numericoid_validate(p, end);
  943. } else {
  944. rc = 1;
  945. goto exit;
  946. }
  947. } else {
  948. rc = 1;
  949. }
  950. exit:
  951. return( rc );
  952. }
  953. static int printable_validate(
  954. struct berval *val
  955. )
  956. {
  957. int rc = 0; /* assume the value is valid */
  958. int i = 0;
  959. /* Per RFC4517:
  960. *
  961. * PrintableString = 1*PrintableCharacter
  962. */
  963. if ((val != NULL) && (val->bv_len > 0)) {
  964. /* Make sure all chars are a PrintableCharacter */
  965. for (i=0; i < val->bv_len; i++) {
  966. if (!IS_PRINTABLE(val->bv_val[i])) {
  967. rc = 1;
  968. goto exit;
  969. }
  970. }
  971. } else {
  972. rc = 1;
  973. }
  974. exit:
  975. return( rc );
  976. }
  977. static void cis_normalize(
  978. Slapi_PBlock *pb,
  979. char *s,
  980. int trim_spaces,
  981. char **alt
  982. )
  983. {
  984. value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt);
  985. return;
  986. }