cis.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize},
  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, cis_normalize}
  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. if (pb) {
  519. slapi_pblock_get( pb, SLAPI_PLUGIN_SYNTAX_FILTER_NORMALIZED,
  520. &filter_normalized );
  521. if (filter_normalized) {
  522. syntax |= SYNTAX_NORM_FILT;
  523. }
  524. }
  525. return( string_filter_ava( bvfilter, bvals, syntax, ftype,
  526. retVal ) );
  527. }
  528. static int
  529. cis_filter_sub(
  530. Slapi_PBlock *pb,
  531. char *initial,
  532. char **any,
  533. char *final,
  534. Slapi_Value **bvals
  535. )
  536. {
  537. return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_CIS ) );
  538. }
  539. static int
  540. cis_values2keys(
  541. Slapi_PBlock *pb,
  542. Slapi_Value **vals,
  543. Slapi_Value ***ivals,
  544. int ftype
  545. )
  546. {
  547. return( string_values2keys( pb, vals, ivals, SYNTAX_CIS, ftype ) );
  548. }
  549. static int
  550. cis_assertion2keys_ava(
  551. Slapi_PBlock *pb,
  552. Slapi_Value *val,
  553. Slapi_Value ***ivals,
  554. int ftype
  555. )
  556. {
  557. return(string_assertion2keys_ava( pb, val, ivals, SYNTAX_CIS, ftype ));
  558. }
  559. static int
  560. cis_assertion2keys_sub(
  561. Slapi_PBlock *pb,
  562. char *initial,
  563. char **any,
  564. char *final,
  565. Slapi_Value ***ivals
  566. )
  567. {
  568. return( string_assertion2keys_sub( pb, initial, any, final, ivals,
  569. SYNTAX_CIS ) );
  570. }
  571. static int cis_compare(
  572. struct berval *v1,
  573. struct berval *v2
  574. )
  575. {
  576. return value_cmp(v1,v2,SYNTAX_CIS,3 /* Normalise both values */);
  577. }
  578. static int dirstring_validate(
  579. struct berval *val
  580. )
  581. {
  582. int rc = 0; /* assume the value is valid */
  583. char *p = NULL;
  584. char *end = NULL;
  585. /* Per RFC4517:
  586. *
  587. * DirectoryString = 1*UTF8
  588. */
  589. if ((val != NULL) && (val->bv_len > 0)) {
  590. p = val->bv_val;
  591. end = &(val->bv_val[val->bv_len - 1]);
  592. rc = utf8string_validate(p, end, NULL);
  593. } else {
  594. rc = 1;
  595. goto exit;
  596. }
  597. exit:
  598. return( rc );
  599. }
  600. static int boolean_validate(
  601. struct berval *val
  602. )
  603. {
  604. int rc = 0; /* assume the value is valid */
  605. /* Per RFC4517:
  606. *
  607. * Boolean = "TRUE" / "FALSE"
  608. */
  609. if (val != NULL) {
  610. if (val->bv_len == 4) {
  611. if (strncmp(val->bv_val, "TRUE", 4) != 0) {
  612. rc = 1;
  613. goto exit;
  614. }
  615. } else if (val->bv_len == 5) {
  616. if (strncmp(val->bv_val, "FALSE", 5) != 0) {
  617. rc = 1;
  618. goto exit;
  619. }
  620. } else {
  621. rc = 1;
  622. goto exit;
  623. }
  624. } else {
  625. rc = 1;
  626. }
  627. exit:
  628. return(rc);
  629. }
  630. static int time_validate(
  631. struct berval *val
  632. )
  633. {
  634. int rc = 0; /* assume the value is valid */
  635. int i = 0;
  636. const char *p = NULL;
  637. char *end = NULL;
  638. /* Per RFC4517:
  639. *
  640. * GeneralizedTime = century year month day hour
  641. * [ minute [ second / leap-second ] ]
  642. * [ fraction ]
  643. * g-time-zone
  644. *
  645. * century = 2(%x30-39) ; "00" to "99"
  646. * year = 2(%x30-39) ; "00" to "99"
  647. * month = ( %x30 %x31-39 ) ; "01" (January) to "09"
  648. * / ( %x31 %x30-32 ) ; "10 to "12"
  649. * day = ( %x30 %x31-39 ) ; "01" to "09"
  650. * / ( %x31-x32 %x30-39 ) ; "10" to "29"
  651. * / ( %x33 %x30-31 ) ; "30" to "31"
  652. * hour = ( %x30-31 %x30-39 ) / ( %x32 %x30-33 ) ; "00" to "23"
  653. * minute = %x30-35 %x30-39 ; "00" to "59"
  654. *
  655. * second = ( %x30-35 - %x30-39 ) ; "00" to "59"
  656. * leap-second = ( %x36 %x30 ) ; "60"
  657. *
  658. * fraction = ( DOT / COMMA ) 1*(%x30-39)
  659. * g-time-zone = %x5A ; "Z"
  660. * / g-differential
  661. * g-differential = ( MINUS / PLUS ) hour [ minute ]
  662. */
  663. if (val != NULL) {
  664. /* A valid GeneralizedTime should be at least 11 characters. There
  665. * is no upper bound due to the variable length of "fraction". */
  666. if (val->bv_len < 11) {
  667. rc = 1;
  668. goto exit;
  669. }
  670. /* We're guaranteed that the value is at least 11 characters, so we
  671. * don't need to bother checking if we're at the end of the value
  672. * until we start processing the "minute" part of the value. */
  673. p = val->bv_val;
  674. end = &(val->bv_val[val->bv_len - 1]);
  675. /* Process "century year". First 4 characters can be any valid digit. */
  676. for (i=0; i<4; i++) {
  677. if (!isdigit(*p)) {
  678. rc = 1;
  679. goto exit;
  680. }
  681. p++;
  682. }
  683. /* Process "month". Next character can be "0" or "1". */
  684. if (*p == '0') {
  685. p++;
  686. /* any LDIGIT is valid now */
  687. if (!IS_LDIGIT(*p)) {
  688. rc = 1;
  689. goto exit;
  690. }
  691. p++;
  692. } else if (*p == '1') {
  693. p++;
  694. /* only "0"-"2" are valid now */
  695. if ((*p < '0') || (*p > '2')) {
  696. rc = 1;
  697. goto exit;
  698. }
  699. p++;
  700. } else {
  701. rc = 1;
  702. goto exit;
  703. }
  704. /* Process "day". Next character can be "0"-"3". */
  705. if (*p == '0') {
  706. p++;
  707. /* any LDIGIT is valid now */
  708. if (!IS_LDIGIT(*p)) {
  709. rc = 1;
  710. goto exit;
  711. }
  712. p++;
  713. } else if ((*p == '1') || (*p == '2')) {
  714. p++;
  715. /* any digit is valid now */
  716. if (!isdigit(*p)) {
  717. rc = 1;
  718. goto exit;
  719. }
  720. p++;
  721. } else if (*p == '3') {
  722. p++;
  723. /* only "0"-"1" are valid now */
  724. if ((*p != '0') && (*p != '1')) {
  725. rc = 1;
  726. goto exit;
  727. }
  728. p++;
  729. } else {
  730. rc = 1;
  731. goto exit;
  732. }
  733. /* Process "hour". Next character can be "0"-"2". */
  734. if ((*p == '0') || (*p == '1')) {
  735. p++;
  736. /* any digit is valid now */
  737. if (!isdigit(*p)) {
  738. rc = 1;
  739. goto exit;
  740. }
  741. p++;
  742. } else if (*p == '2') {
  743. p++;
  744. /* only "0"-"3" are valid now */
  745. if ((*p < '0') || (*p > '3')) {
  746. rc = 1;
  747. goto exit;
  748. }
  749. p++;
  750. } else {
  751. rc = 1;
  752. goto exit;
  753. }
  754. /* Time for the optional stuff. We know we have at least one character here, but
  755. * we need to start checking for the end of the string afterwards.
  756. *
  757. * See if a "minute" was specified. */
  758. if ((*p >= '0') && (*p <= '5')) {
  759. p++;
  760. /* any digit is valid for the second char of a minute */
  761. if ((p > end) || (!isdigit(*p))) {
  762. rc = 1;
  763. goto exit;
  764. }
  765. p++;
  766. /* At this point, there has to at least be a "g-time-zone" left.
  767. * Make sure we're not at the end of the string. */
  768. if (p > end) {
  769. rc = 1;
  770. goto exit;
  771. }
  772. /* See if a "second" or "leap-second" was specified. */
  773. if ((*p >= '0') && (*p <= '5')) {
  774. p++;
  775. /* any digit is valid now */
  776. if ((p > end) || (!isdigit(*p))) {
  777. rc = 1;
  778. goto exit;
  779. }
  780. p++;
  781. } else if (*p == '6') {
  782. p++;
  783. /* only a '0' is valid now */
  784. if ((p > end) || (*p != '0')) {
  785. rc = 1;
  786. goto exit;
  787. }
  788. p++;
  789. }
  790. /* At this point, there has to at least be a "g-time-zone" left.
  791. * Make sure we're not at the end of the string. */
  792. if (p > end) {
  793. rc = 1;
  794. goto exit;
  795. }
  796. }
  797. /* See if a fraction was specified. */
  798. if ((*p == '.') || (*p == ',')) {
  799. p++;
  800. /* An arbitrary length string of digit chars is allowed here.
  801. * Ensure we have at least one digit character. */
  802. if ((p >= end) || (!isdigit(*p))) {
  803. rc = 1;
  804. goto exit;
  805. }
  806. /* Just loop through the rest of the fraction until we encounter a non-digit */
  807. p++;
  808. while ((p < end) && (isdigit(*p))) {
  809. p++;
  810. }
  811. }
  812. /* Process "g-time-zone". We either end with 'Z', or have a differential. */
  813. if (p == end) {
  814. if (*p != 'Z') {
  815. rc = 1;
  816. goto exit;
  817. }
  818. } else if (p < end) {
  819. if ((*p != '-') && (*p != '+')) {
  820. rc = 1;
  821. goto exit;
  822. } else {
  823. /* A "g-differential" was specified. An "hour" must be present now. */
  824. p++;
  825. if ((*p == '0') || (*p == '1')) {
  826. p++;
  827. /* any digit is valid now */
  828. if ((p > end) || !isdigit(*p)) {
  829. rc = 1;
  830. goto exit;
  831. }
  832. p++;
  833. } else if (*p == '2') {
  834. p++;
  835. /* only "0"-"3" are valid now */
  836. if ((p > end) || (*p < '0') || (*p > '3')) {
  837. rc = 1;
  838. goto exit;
  839. }
  840. p++;
  841. } else {
  842. rc = 1;
  843. goto exit;
  844. }
  845. /* See if an optional minute is present ("00"-"59"). */
  846. if (p <= end) {
  847. /* "0"-"5" are valid now */
  848. if ((*p < '0') || (*p > '5')) {
  849. rc = 1;
  850. goto exit;
  851. }
  852. p++;
  853. /* We should be at the last character of the string
  854. * now, which must be a valid digit. */
  855. if ((p != end) || !isdigit(*p)) {
  856. rc = 1;
  857. goto exit;
  858. }
  859. }
  860. }
  861. } else {
  862. /* Premature end of string */
  863. rc = 1;
  864. goto exit;
  865. }
  866. } else {
  867. rc = 1;
  868. goto exit;
  869. }
  870. exit:
  871. return( rc );
  872. }
  873. static int country_validate(
  874. struct berval *val
  875. )
  876. {
  877. int rc = 0; /* assume the value is valid */
  878. /* Per RFC4517:
  879. *
  880. * CountryString = 2(PrintableCharacter)
  881. */
  882. if (val != NULL) {
  883. if ((val->bv_len != 2) || !IS_PRINTABLE(val->bv_val[0]) || !IS_PRINTABLE(val->bv_val[1])) {
  884. rc = 1;
  885. goto exit;
  886. }
  887. } else {
  888. rc = 1;
  889. }
  890. exit:
  891. return(rc);
  892. }
  893. static int postal_validate(
  894. struct berval *val
  895. )
  896. {
  897. int rc = 0; /* assume the value is valid */
  898. const char *p = NULL;
  899. const char *start = NULL;
  900. char *end = NULL;
  901. /* Per RFC4517:
  902. * PostalAddress = line *( DOLLAR line )
  903. * line = 1*line-char
  904. * line-char = %x00-23
  905. * / (%x5C "24") ; escaped "$"
  906. * / %x25-5B
  907. * / (%x5C "5C") ; escaped "\"
  908. * / %x5D-7F
  909. * / UTFMB
  910. */
  911. if ((val != NULL) && (val->bv_val != NULL) && (val->bv_len > 0)) {
  912. start = val->bv_val;
  913. end = &(val->bv_val[val->bv_len - 1]);
  914. for (p = start; p <= end; p++) {
  915. /* look for a '\' and make sure it's only used to escape a '$' or a '\' */
  916. if (*p == '\\') {
  917. p++;
  918. /* ensure that we're not at the end of the value */
  919. if ((p > end) || ((strncmp(p, "24", 2) != 0) && (strncasecmp(p, "5C", 2) != 0))) {
  920. rc = 1;
  921. goto exit;
  922. } else {
  923. /* advance the pointer to point to the end
  924. * of the hex code for the escaped character */
  925. p++;
  926. }
  927. } else if ((*p == '$') || (p == end)) {
  928. /* This signifies the end of a line. We need
  929. * to ensure that the line is not empty. */
  930. /* make sure the value doesn't end with a '$' */
  931. if ((p == start) || ((*p == '$') && (p == end))) {
  932. if (!postal_allow_empty_lines) {
  933. rc = 1;
  934. goto exit;
  935. } /* else allow it */
  936. } else if ((rc = utf8string_validate(start, p, NULL)) != 0) {
  937. /* Make sure the line (start to p) is valid UTF-8. */
  938. goto exit;
  939. }
  940. /* make the start pointer point to the
  941. * beginning of the next line */
  942. start = p + 1;
  943. }
  944. }
  945. } else {
  946. rc = 1;
  947. }
  948. exit:
  949. return(rc);
  950. }
  951. static int oid_validate(
  952. struct berval *val
  953. )
  954. {
  955. int rc = 0; /* assume the value is valid */
  956. const char *p = NULL;
  957. const char *end = NULL;
  958. /* Per RFC4512:
  959. *
  960. * oid = descr / numericoid
  961. * descr = keystring
  962. */
  963. if ((val != NULL) && (val->bv_len > 0)) {
  964. p = val->bv_val;
  965. end = &(val->bv_val[val->bv_len - 1]);
  966. /* check if the value matches the descr form */
  967. if (IS_LEADKEYCHAR(*p)) {
  968. rc = keystring_validate(p, end);
  969. /* check if the value matches the numericoid form */
  970. } else if (isdigit(*p)) {
  971. rc = numericoid_validate(p, end);
  972. } else {
  973. rc = 1;
  974. goto exit;
  975. }
  976. } else {
  977. rc = 1;
  978. }
  979. exit:
  980. return( rc );
  981. }
  982. static int printable_validate(
  983. struct berval *val
  984. )
  985. {
  986. int rc = 0; /* assume the value is valid */
  987. int i = 0;
  988. /* Per RFC4517:
  989. *
  990. * PrintableString = 1*PrintableCharacter
  991. */
  992. if ((val != NULL) && (val->bv_len > 0)) {
  993. /* Make sure all chars are a PrintableCharacter */
  994. for (i=0; i < val->bv_len; i++) {
  995. if (!IS_PRINTABLE(val->bv_val[i])) {
  996. rc = 1;
  997. goto exit;
  998. }
  999. }
  1000. } else {
  1001. rc = 1;
  1002. }
  1003. exit:
  1004. return( rc );
  1005. }
  1006. static void cis_normalize(
  1007. Slapi_PBlock *pb,
  1008. char *s,
  1009. int trim_spaces,
  1010. char **alt
  1011. )
  1012. {
  1013. value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt);
  1014. return;
  1015. }