sortctrl.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /* $OpenLDAP$ */
  2. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  3. *
  4. * Copyright 1998-2024 The OpenLDAP Foundation.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted only as authorized by the OpenLDAP
  9. * Public License.
  10. *
  11. * A copy of this license is available in the file LICENSE in the
  12. * top-level directory of the distribution or, alternatively, at
  13. * <http://www.OpenLDAP.org/license.html>.
  14. */
  15. /* Portions Copyright (C) 1999, 2000 Novell, Inc. All Rights Reserved.
  16. *
  17. * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
  18. * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
  19. * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
  20. * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
  21. * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
  22. * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
  23. * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
  24. * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
  25. */
  26. /* Note: A verbatim copy of version 2.0.1 of the OpenLDAP Public License
  27. * can be found in the file "build/LICENSE-2.0.1" in this distribution
  28. * of OpenLDAP Software.
  29. */
  30. #include "portable.h"
  31. #include <stdio.h>
  32. #include <ac/stdlib.h>
  33. #include <ac/string.h>
  34. #include <ac/time.h>
  35. #include "ldap-int.h"
  36. #define LDAP_MATCHRULE_IDENTIFIER 0x80L
  37. #define LDAP_REVERSEORDER_IDENTIFIER 0x81L
  38. #define LDAP_ATTRTYPES_IDENTIFIER 0x80L
  39. /* ---------------------------------------------------------------------------
  40. countKeys
  41. Internal function to determine the number of keys in the string.
  42. keyString (IN) String of items separated by whitespace.
  43. ---------------------------------------------------------------------------*/
  44. static int countKeys(char *keyString)
  45. {
  46. char *p = keyString;
  47. int count = 0;
  48. for (;;)
  49. {
  50. while (LDAP_SPACE(*p)) /* Skip leading whitespace */
  51. p++;
  52. if (*p == '\0') /* End of string? */
  53. return count;
  54. count++; /* Found start of a key */
  55. while (!LDAP_SPACE(*p)) /* Skip till next space or end of string. */
  56. if (*p++ == '\0')
  57. return count;
  58. }
  59. }
  60. /* ---------------------------------------------------------------------------
  61. readNextKey
  62. Internal function to parse the next sort key in the string.
  63. Allocate an LDAPSortKey structure and initialize it with
  64. attribute name, reverse flag, and matching rule OID.
  65. Each sort key in the string has the format:
  66. [whitespace][-]attribute[:[OID]]
  67. pNextKey (IN/OUT) Points to the next key in the sortkey string to parse.
  68. The pointer is updated to point to the next character
  69. after the sortkey being parsed.
  70. key (OUT) Points to the address of an LDAPSortKey structure
  71. which has been allocated by this routine and
  72. initialized with information from the next sortkey.
  73. ---------------------------------------------------------------------------*/
  74. static int readNextKey( char **pNextKey, LDAPSortKey **key)
  75. {
  76. char *p = *pNextKey;
  77. int rev = 0;
  78. char *attrStart;
  79. int attrLen;
  80. char *oidStart = NULL;
  81. int oidLen = 0;
  82. /* Skip leading white space. */
  83. while (LDAP_SPACE(*p))
  84. p++;
  85. if (*p == '-') /* Check if the reverse flag is present. */
  86. {
  87. rev=1;
  88. p++;
  89. }
  90. /* We're now positioned at the start of the attribute. */
  91. attrStart = p;
  92. /* Get the length of the attribute until the next whitespace or ":". */
  93. attrLen = strcspn(p, " \t:");
  94. p += attrLen;
  95. if (attrLen == 0) /* If no attribute name was present, quit. */
  96. return LDAP_PARAM_ERROR;
  97. if (*p == ':')
  98. {
  99. oidStart = ++p; /* Start of the OID, after the colon */
  100. oidLen = strcspn(p, " \t"); /* Get length of OID till next whitespace */
  101. p += oidLen;
  102. }
  103. *pNextKey = p; /* Update argument to point to next key */
  104. /* Allocate an LDAPSortKey structure */
  105. *key = LDAP_MALLOC(sizeof(LDAPSortKey));
  106. if (*key == NULL) return LDAP_NO_MEMORY;
  107. /* Allocate memory for the attribute and copy to it. */
  108. (*key)->attributeType = LDAP_MALLOC(attrLen+1);
  109. if ((*key)->attributeType == NULL) {
  110. LDAP_FREE(*key);
  111. return LDAP_NO_MEMORY;
  112. }
  113. strncpy((*key)->attributeType, attrStart, attrLen);
  114. (*key)->attributeType[attrLen] = 0;
  115. /* If present, allocate memory for the OID and copy to it. */
  116. if (oidLen) {
  117. (*key)->orderingRule = LDAP_MALLOC(oidLen+1);
  118. if ((*key)->orderingRule == NULL) {
  119. LDAP_FREE((*key)->attributeType);
  120. LDAP_FREE(*key);
  121. return LDAP_NO_MEMORY;
  122. }
  123. strncpy((*key)->orderingRule, oidStart, oidLen);
  124. (*key)->orderingRule[oidLen] = 0;
  125. } else {
  126. (*key)->orderingRule = NULL;
  127. }
  128. (*key)->reverseOrder = rev;
  129. return LDAP_SUCCESS;
  130. }
  131. /* ---------------------------------------------------------------------------
  132. ldap_create_sort_keylist
  133. Create an array of pointers to LDAPSortKey structures, containing the
  134. information specified by the string representation of one or more
  135. sort keys.
  136. sortKeyList (OUT) Points to a null-terminated array of pointers to
  137. LDAPSortKey structures allocated by this routine.
  138. This memory SHOULD be freed by the calling program
  139. using ldap_free_sort_keylist().
  140. keyString (IN) Points to a string of one or more sort keys.
  141. ---------------------------------------------------------------------------*/
  142. int
  143. ldap_create_sort_keylist ( LDAPSortKey ***sortKeyList, char *keyString )
  144. {
  145. int numKeys, rc, i;
  146. char *nextKey;
  147. LDAPSortKey **keyList = NULL;
  148. assert( sortKeyList != NULL );
  149. assert( keyString != NULL );
  150. *sortKeyList = NULL;
  151. /* Determine the number of sort keys so we can allocate memory. */
  152. if (( numKeys = countKeys(keyString)) == 0) {
  153. return LDAP_PARAM_ERROR;
  154. }
  155. /* Allocate the array of pointers. Initialize to NULL. */
  156. keyList=(LDAPSortKey**)LBER_CALLOC(numKeys+1, sizeof(LDAPSortKey*));
  157. if ( keyList == NULL) return LDAP_NO_MEMORY;
  158. /* For each sort key in the string, create an LDAPSortKey structure
  159. and add it to the list.
  160. */
  161. nextKey = keyString; /* Points to the next key in the string */
  162. for (i=0; i < numKeys; i++) {
  163. rc = readNextKey(&nextKey, &keyList[i]);
  164. if (rc != LDAP_SUCCESS) {
  165. ldap_free_sort_keylist(keyList);
  166. return rc;
  167. }
  168. }
  169. *sortKeyList = keyList;
  170. return LDAP_SUCCESS;
  171. }
  172. /* ---------------------------------------------------------------------------
  173. ldap_free_sort_keylist
  174. Frees the sort key structures created by ldap_create_sort_keylist().
  175. Frees the memory referenced by the LDAPSortKey structures,
  176. the LDAPSortKey structures themselves, and the array of pointers
  177. to the structures.
  178. keyList (IN) Points to an array of pointers to LDAPSortKey structures.
  179. ---------------------------------------------------------------------------*/
  180. void
  181. ldap_free_sort_keylist ( LDAPSortKey **keyList )
  182. {
  183. int i;
  184. LDAPSortKey *nextKeyp;
  185. if (keyList == NULL) return;
  186. i=0;
  187. while ( 0 != (nextKeyp = keyList[i++]) ) {
  188. if (nextKeyp->attributeType) {
  189. LBER_FREE(nextKeyp->attributeType);
  190. }
  191. if (nextKeyp->orderingRule != NULL) {
  192. LBER_FREE(nextKeyp->orderingRule);
  193. }
  194. LBER_FREE(nextKeyp);
  195. }
  196. LBER_FREE(keyList);
  197. }
  198. /* ---------------------------------------------------------------------------
  199. ldap_create_sort_control_value
  200. Create and encode the value of the server-side sort control.
  201. ld (IN) An LDAP session handle, as obtained from a call to
  202. ldap_init().
  203. keyList (IN) Points to a null-terminated array of pointers to
  204. LDAPSortKey structures, containing a description of
  205. each of the sort keys to be used. The description
  206. consists of an attribute name, ascending/descending flag,
  207. and an optional matching rule (OID) to use.
  208. value (OUT) Contains the control value; the bv_val member of the berval structure
  209. SHOULD be freed by calling ldap_memfree() when done.
  210. Ber encoding
  211. SortKeyList ::= SEQUENCE OF SEQUENCE {
  212. attributeType AttributeDescription,
  213. orderingRule [0] MatchingRuleId OPTIONAL,
  214. reverseOrder [1] BOOLEAN DEFAULT FALSE }
  215. ---------------------------------------------------------------------------*/
  216. int
  217. ldap_create_sort_control_value(
  218. LDAP *ld,
  219. LDAPSortKey **keyList,
  220. struct berval *value )
  221. {
  222. int i;
  223. BerElement *ber = NULL;
  224. ber_tag_t tag;
  225. assert( ld != NULL );
  226. assert( LDAP_VALID( ld ) );
  227. if ( ld == NULL ) return LDAP_PARAM_ERROR;
  228. if ( keyList == NULL || value == NULL ) {
  229. ld->ld_errno = LDAP_PARAM_ERROR;
  230. return LDAP_PARAM_ERROR;
  231. }
  232. value->bv_val = NULL;
  233. value->bv_len = 0;
  234. ld->ld_errno = LDAP_SUCCESS;
  235. ber = ldap_alloc_ber_with_options( ld );
  236. if ( ber == NULL) {
  237. ld->ld_errno = LDAP_NO_MEMORY;
  238. return ld->ld_errno;
  239. }
  240. tag = ber_printf( ber, "{" /*}*/ );
  241. if ( tag == LBER_ERROR ) {
  242. goto error_return;
  243. }
  244. for ( i = 0; keyList[i] != NULL; i++ ) {
  245. tag = ber_printf( ber, "{s" /*}*/, keyList[i]->attributeType );
  246. if ( tag == LBER_ERROR ) {
  247. goto error_return;
  248. }
  249. if ( keyList[i]->orderingRule != NULL ) {
  250. tag = ber_printf( ber, "ts",
  251. LDAP_MATCHRULE_IDENTIFIER,
  252. keyList[i]->orderingRule );
  253. if ( tag == LBER_ERROR ) {
  254. goto error_return;
  255. }
  256. }
  257. if ( keyList[i]->reverseOrder ) {
  258. tag = ber_printf( ber, "tb",
  259. LDAP_REVERSEORDER_IDENTIFIER,
  260. keyList[i]->reverseOrder );
  261. if ( tag == LBER_ERROR ) {
  262. goto error_return;
  263. }
  264. }
  265. tag = ber_printf( ber, /*{*/ "N}" );
  266. if ( tag == LBER_ERROR ) {
  267. goto error_return;
  268. }
  269. }
  270. tag = ber_printf( ber, /*{*/ "N}" );
  271. if ( tag == LBER_ERROR ) {
  272. goto error_return;
  273. }
  274. if ( ber_flatten2( ber, value, 1 ) == -1 ) {
  275. ld->ld_errno = LDAP_NO_MEMORY;
  276. }
  277. if ( 0 ) {
  278. error_return:;
  279. ld->ld_errno = LDAP_ENCODING_ERROR;
  280. }
  281. if ( ber != NULL ) {
  282. ber_free( ber, 1 );
  283. }
  284. return ld->ld_errno;
  285. }
  286. /* ---------------------------------------------------------------------------
  287. ldap_create_sort_control
  288. Create and encode the server-side sort control.
  289. ld (IN) An LDAP session handle, as obtained from a call to
  290. ldap_init().
  291. keyList (IN) Points to a null-terminated array of pointers to
  292. LDAPSortKey structures, containing a description of
  293. each of the sort keys to be used. The description
  294. consists of an attribute name, ascending/descending flag,
  295. and an optional matching rule (OID) to use.
  296. isCritical (IN) 0 - Indicates the control is not critical to the operation.
  297. non-zero - The control is critical to the operation.
  298. ctrlp (OUT) Returns a pointer to the LDAPControl created. This control
  299. SHOULD be freed by calling ldap_control_free() when done.
  300. Ber encoding
  301. SortKeyList ::= SEQUENCE OF SEQUENCE {
  302. attributeType AttributeDescription,
  303. orderingRule [0] MatchingRuleId OPTIONAL,
  304. reverseOrder [1] BOOLEAN DEFAULT FALSE }
  305. ---------------------------------------------------------------------------*/
  306. int
  307. ldap_create_sort_control(
  308. LDAP *ld,
  309. LDAPSortKey **keyList,
  310. int isCritical,
  311. LDAPControl **ctrlp )
  312. {
  313. struct berval value;
  314. assert( ld != NULL );
  315. assert( LDAP_VALID( ld ) );
  316. if ( ld == NULL ) {
  317. return LDAP_PARAM_ERROR;
  318. }
  319. if ( ctrlp == NULL ) {
  320. ld->ld_errno = LDAP_PARAM_ERROR;
  321. return ld->ld_errno;
  322. }
  323. ld->ld_errno = ldap_create_sort_control_value( ld, keyList, &value );
  324. if ( ld->ld_errno == LDAP_SUCCESS ) {
  325. ld->ld_errno = ldap_control_create( LDAP_CONTROL_SORTREQUEST,
  326. isCritical, &value, 0, ctrlp );
  327. if ( ld->ld_errno != LDAP_SUCCESS ) {
  328. LDAP_FREE( value.bv_val );
  329. }
  330. }
  331. return ld->ld_errno;
  332. }
  333. /* ---------------------------------------------------------------------------
  334. ldap_parse_sortedresult_control
  335. Decode the server-side sort control return information.
  336. ld (IN) An LDAP session handle, as obtained from a call to
  337. ldap_init().
  338. ctrl (IN) The address of the LDAP Control Structure.
  339. returnCode (OUT) This result parameter is filled in with the sort control
  340. result code. This parameter MUST not be NULL.
  341. attribute (OUT) If an error occurred the server may return a string
  342. indicating the first attribute in the sortkey list
  343. that was in error. If a string is returned, the memory
  344. should be freed with ldap_memfree. If this parameter is
  345. NULL, no string is returned.
  346. Ber encoding for sort control
  347. SortResult ::= SEQUENCE {
  348. sortResult ENUMERATED {
  349. success (0), -- results are sorted
  350. operationsError (1), -- server internal failure
  351. timeLimitExceeded (3), -- timelimit reached before
  352. -- sorting was completed
  353. strongAuthRequired (8), -- refused to return sorted
  354. -- results via insecure
  355. -- protocol
  356. adminLimitExceeded (11), -- too many matching entries
  357. -- for the server to sort
  358. noSuchAttribute (16), -- unrecognized attribute
  359. -- type in sort key
  360. inappropriateMatching (18), -- unrecognized or inappro-
  361. -- priate matching rule in
  362. -- sort key
  363. insufficientAccessRights (50), -- refused to return sorted
  364. -- results to this client
  365. busy (51), -- too busy to process
  366. unwillingToPerform (53), -- unable to sort
  367. other (80)
  368. },
  369. attributeType [0] AttributeDescription OPTIONAL }
  370. ---------------------------------------------------------------------------*/
  371. int
  372. ldap_parse_sortresponse_control(
  373. LDAP *ld,
  374. LDAPControl *ctrl,
  375. ber_int_t *returnCode,
  376. char **attribute )
  377. {
  378. BerElement *ber;
  379. ber_tag_t tag, berTag;
  380. ber_len_t berLen;
  381. assert( ld != NULL );
  382. assert( LDAP_VALID( ld ) );
  383. if (ld == NULL) {
  384. return LDAP_PARAM_ERROR;
  385. }
  386. if (ctrl == NULL) {
  387. ld->ld_errno = LDAP_PARAM_ERROR;
  388. return(ld->ld_errno);
  389. }
  390. if (attribute) {
  391. *attribute = NULL;
  392. }
  393. if ( strcmp(LDAP_CONTROL_SORTRESPONSE, ctrl->ldctl_oid) != 0 ) {
  394. /* Not sort result control */
  395. ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
  396. return(ld->ld_errno);
  397. }
  398. /* Create a BerElement from the berval returned in the control. */
  399. ber = ber_init(&ctrl->ldctl_value);
  400. if (ber == NULL) {
  401. ld->ld_errno = LDAP_NO_MEMORY;
  402. return(ld->ld_errno);
  403. }
  404. /* Extract the result code from the control. */
  405. tag = ber_scanf(ber, "{e" /*}*/, returnCode);
  406. if( tag == LBER_ERROR ) {
  407. ber_free(ber, 1);
  408. ld->ld_errno = LDAP_DECODING_ERROR;
  409. return(ld->ld_errno);
  410. }
  411. /* If caller wants the attribute name, and if it's present in the control,
  412. extract the attribute name which caused the error. */
  413. if (attribute && (LDAP_ATTRTYPES_IDENTIFIER == ber_peek_tag(ber, &berLen)))
  414. {
  415. tag = ber_scanf(ber, "ta", &berTag, attribute);
  416. if (tag == LBER_ERROR ) {
  417. ber_free(ber, 1);
  418. ld->ld_errno = LDAP_DECODING_ERROR;
  419. return(ld->ld_errno);
  420. }
  421. }
  422. ber_free(ber,1);
  423. ld->ld_errno = LDAP_SUCCESS;
  424. return(ld->ld_errno);
  425. }