cis.c 39 KB

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