cis.c 39 KB

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