17c478bd9Sstevel@tonic-gate /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
27c478bd9Sstevel@tonic-gate  *
37c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the Netscape Public License
47c478bd9Sstevel@tonic-gate  * Version 1.0 (the "NPL"); you may not use this file except in
57c478bd9Sstevel@tonic-gate  * compliance with the NPL.  You may obtain a copy of the NPL at
67c478bd9Sstevel@tonic-gate  * http://www.mozilla.org/NPL/
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Software distributed under the NPL is distributed on an "AS IS" basis,
97c478bd9Sstevel@tonic-gate  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
107c478bd9Sstevel@tonic-gate  * for the specific language governing rights and limitations under the
117c478bd9Sstevel@tonic-gate  * NPL.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * The Initial Developer of this code under the NPL is Netscape
147c478bd9Sstevel@tonic-gate  * Communications Corporation.  Portions created by Netscape are
157c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
167c478bd9Sstevel@tonic-gate  * Reserved.
177c478bd9Sstevel@tonic-gate  */
187c478bd9Sstevel@tonic-gate #include "ldap-int.h"
197c478bd9Sstevel@tonic-gate 
207c478bd9Sstevel@tonic-gate /* ldap_create_sort_control:
217c478bd9Sstevel@tonic-gate 
22*1da57d55SToomas Soome    Parameters are
237c478bd9Sstevel@tonic-gate 
24*1da57d55SToomas Soome    ld              LDAP pointer to the desired connection
257c478bd9Sstevel@tonic-gate 
26*1da57d55SToomas Soome    sortKeyList     an array of sortkeys
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate    ctl_iscritical  Indicates whether the control is critical of not. If
297c478bd9Sstevel@tonic-gate                    this field is non-zero, the operation will only be car-
307c478bd9Sstevel@tonic-gate                    ried out if the control is recognized by the server
317c478bd9Sstevel@tonic-gate                    and/or client
327c478bd9Sstevel@tonic-gate 
33*1da57d55SToomas Soome    ctrlp           the address of a place to put the constructed control
347c478bd9Sstevel@tonic-gate */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate int
377c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_create_sort_control(LDAP * ld,LDAPsortkey ** sortKeyList,const char ctl_iscritical,LDAPControl ** ctrlp)38*1da57d55SToomas Soome ldap_create_sort_control (
39*1da57d55SToomas Soome      LDAP *ld,
407c478bd9Sstevel@tonic-gate      LDAPsortkey **sortKeyList,
417c478bd9Sstevel@tonic-gate      const char ctl_iscritical,
42*1da57d55SToomas Soome      LDAPControl **ctrlp
437c478bd9Sstevel@tonic-gate )
447c478bd9Sstevel@tonic-gate {
457c478bd9Sstevel@tonic-gate 	BerElement		*ber;
467c478bd9Sstevel@tonic-gate 	int				i, rc;
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
497c478bd9Sstevel@tonic-gate 		return( LDAP_PARAM_ERROR );
507c478bd9Sstevel@tonic-gate 	}
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	if ( sortKeyList == NULL || ctrlp == NULL ) {
537c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
547c478bd9Sstevel@tonic-gate 		return ( LDAP_PARAM_ERROR );
557c478bd9Sstevel@tonic-gate 	}
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	/* create a ber package to hold the controlValue */
587c478bd9Sstevel@tonic-gate 	if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
597c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
607c478bd9Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
617c478bd9Sstevel@tonic-gate 	}
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	/* encode the start of the sequence of sequences into the ber */
647c478bd9Sstevel@tonic-gate 	if ( ber_printf( ber, "{" ) == -1 ) {
657c478bd9Sstevel@tonic-gate 		goto encoding_error_exit;
667c478bd9Sstevel@tonic-gate 	}
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	/* the sort control value will be encoded as a sequence of sequences
69*1da57d55SToomas Soome 	   which are each encoded as one of the following: {s} or {sts} or {stb} or {ststb}
707c478bd9Sstevel@tonic-gate 	   since the orderingRule and reverseOrder flag are both optional */
717c478bd9Sstevel@tonic-gate 	for ( i = 0; sortKeyList[i] != NULL; i++ ) {
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 		/* encode the attributeType into the ber */
747c478bd9Sstevel@tonic-gate 		if ( ber_printf( ber, "{s", (sortKeyList[i])->sk_attrtype  )
757c478bd9Sstevel@tonic-gate 		    == -1 ) {
767c478bd9Sstevel@tonic-gate 			goto encoding_error_exit;
777c478bd9Sstevel@tonic-gate 		}
78*1da57d55SToomas Soome 
797c478bd9Sstevel@tonic-gate 		/* encode the optional orderingRule into the ber */
807c478bd9Sstevel@tonic-gate 		if ( (sortKeyList[i])->sk_matchruleoid != NULL ) {
817c478bd9Sstevel@tonic-gate 			if ( ber_printf( ber, "ts", LDAP_TAG_SK_MATCHRULE,
827c478bd9Sstevel@tonic-gate 			    (sortKeyList[i])->sk_matchruleoid )
837c478bd9Sstevel@tonic-gate 			    == -1 ) {
847c478bd9Sstevel@tonic-gate 				goto encoding_error_exit;
857c478bd9Sstevel@tonic-gate 			}
86*1da57d55SToomas Soome 		}
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 		/* Encode the optional reverseOrder flag into the ber. */
897c478bd9Sstevel@tonic-gate 		/* If the flag is false, it should be absent. */
907c478bd9Sstevel@tonic-gate 		if ( (sortKeyList[i])->sk_reverseorder ) {
917c478bd9Sstevel@tonic-gate 			if ( ber_printf( ber, "tb}", LDAP_TAG_SK_REVERSE,
927c478bd9Sstevel@tonic-gate 			    (sortKeyList[i])->sk_reverseorder ) == -1 ) {
937c478bd9Sstevel@tonic-gate 				goto encoding_error_exit;
947c478bd9Sstevel@tonic-gate 			}
957c478bd9Sstevel@tonic-gate 		} else {
967c478bd9Sstevel@tonic-gate 			if ( ber_printf( ber, "}" ) == -1 ) {
977c478bd9Sstevel@tonic-gate 				goto encoding_error_exit;
987c478bd9Sstevel@tonic-gate 			}
997c478bd9Sstevel@tonic-gate 		}
1007c478bd9Sstevel@tonic-gate 	}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	/* encode the end of the sequence of sequences into the ber */
1037c478bd9Sstevel@tonic-gate 	if ( ber_printf( ber, "}" ) == -1 ) {
1047c478bd9Sstevel@tonic-gate 		goto encoding_error_exit;
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	rc = nsldapi_build_control( LDAP_CONTROL_SORTREQUEST, ber, 1,
1087c478bd9Sstevel@tonic-gate 	    ctl_iscritical, ctrlp );
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
1117c478bd9Sstevel@tonic-gate 	return( rc );
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate encoding_error_exit:
1147c478bd9Sstevel@tonic-gate 	LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
1157c478bd9Sstevel@tonic-gate 	ber_free( ber, 1 );
1167c478bd9Sstevel@tonic-gate 	return( LDAP_ENCODING_ERROR );
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /* ldap_parse_sort_control:
1207c478bd9Sstevel@tonic-gate 
121*1da57d55SToomas Soome    Parameters are
1227c478bd9Sstevel@tonic-gate 
123*1da57d55SToomas Soome    ld              LDAP pointer to the desired connection
1247c478bd9Sstevel@tonic-gate 
125*1da57d55SToomas Soome    ctrlp           An array of controls obtained from calling
126*1da57d55SToomas Soome                    ldap_parse_result on the set of results returned by
127*1da57d55SToomas Soome                    the server
1287c478bd9Sstevel@tonic-gate 
129*1da57d55SToomas Soome    result          the address of a place to put the result code
1307c478bd9Sstevel@tonic-gate 
131*1da57d55SToomas Soome    attribute       the address of a place to put the name of the
132*1da57d55SToomas Soome                    attribute which cause the operation to fail, optionally
1337c478bd9Sstevel@tonic-gate                    returned by the server */
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate int
1367c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_parse_sort_control(LDAP * ld,LDAPControl ** ctrlp,unsigned long * result,char ** attribute)137*1da57d55SToomas Soome ldap_parse_sort_control (
138*1da57d55SToomas Soome      LDAP *ld,
139*1da57d55SToomas Soome      LDAPControl **ctrlp,
1407c478bd9Sstevel@tonic-gate      unsigned long *result,
1417c478bd9Sstevel@tonic-gate      char **attribute
1427c478bd9Sstevel@tonic-gate )
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	BerElement *ber;
1457c478bd9Sstevel@tonic-gate 	int i, foundSortControl;
1467c478bd9Sstevel@tonic-gate 	LDAPControl *sortCtrlp;
1477c478bd9Sstevel@tonic-gate 	ber_len_t len;
1487c478bd9Sstevel@tonic-gate 	ber_tag_t tag;
1497c478bd9Sstevel@tonic-gate 	char *attr;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || result == NULL ||
1527c478bd9Sstevel@tonic-gate 		attribute == NULL ) {
1537c478bd9Sstevel@tonic-gate 	    return( LDAP_PARAM_ERROR );
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/* find the sortControl in the list of controls if it exists */
1587c478bd9Sstevel@tonic-gate 	if ( ctrlp == NULL ) {
1597c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
1607c478bd9Sstevel@tonic-gate 		return ( LDAP_CONTROL_NOT_FOUND );
161*1da57d55SToomas Soome 	}
1627c478bd9Sstevel@tonic-gate 	foundSortControl = 0;
1637c478bd9Sstevel@tonic-gate 	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundSortControl )); i++ ) {
1647c478bd9Sstevel@tonic-gate 		foundSortControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_SORTRESPONSE );
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 	if ( !foundSortControl ) {
1677c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
1687c478bd9Sstevel@tonic-gate 		return ( LDAP_CONTROL_NOT_FOUND );
1697c478bd9Sstevel@tonic-gate 	} else {
1707c478bd9Sstevel@tonic-gate 		/* let local var point to the sortControl */
171*1da57d55SToomas Soome 		sortCtrlp = ctrlp[i-1];
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/*  allocate a Ber element with the contents of the sort_control's struct berval */
1757c478bd9Sstevel@tonic-gate 	if ( ( ber = ber_init( &sortCtrlp->ldctl_value ) ) == NULL ) {
1767c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
1777c478bd9Sstevel@tonic-gate 		return( LDAP_NO_MEMORY );
178*1da57d55SToomas Soome 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* decode the result from the Berelement */
1817c478bd9Sstevel@tonic-gate 	if ( ber_scanf( ber, "{i", result ) == LBER_ERROR ) {
1827c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
1837c478bd9Sstevel@tonic-gate 		ber_free( ber, 1 );
1847c478bd9Sstevel@tonic-gate 		return( LDAP_DECODING_ERROR );
1857c478bd9Sstevel@tonic-gate 	}
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/* if the server returned one, decode the attribute from the Ber element */
1887c478bd9Sstevel@tonic-gate 	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SR_ATTRTYPE ) {
1897c478bd9Sstevel@tonic-gate 		if ( ber_scanf( ber, "ta", &tag, &attr ) == LBER_ERROR ) {
1907c478bd9Sstevel@tonic-gate 			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
1917c478bd9Sstevel@tonic-gate 			ber_free( ber, 1 );
1927c478bd9Sstevel@tonic-gate 			return( LDAP_DECODING_ERROR );
1937c478bd9Sstevel@tonic-gate 		}
194*1da57d55SToomas Soome 		*attribute = attr;
1957c478bd9Sstevel@tonic-gate 	} else {
1967c478bd9Sstevel@tonic-gate 		*attribute = NULL;
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if ( ber_scanf( ber, "}" ) == LBER_ERROR ) {
2007c478bd9Sstevel@tonic-gate 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
2017c478bd9Sstevel@tonic-gate 		ber_free( ber, 1 );
2027c478bd9Sstevel@tonic-gate 		return( LDAP_DECODING_ERROR );
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	/* the ber encoding is no longer needed */
2067c478bd9Sstevel@tonic-gate 	ber_free(ber,1);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	return( LDAP_SUCCESS );
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /* Routines for the manipulation of string-representations of sort control keylists */
2127c478bd9Sstevel@tonic-gate 
count_tokens(const char * s)2137c478bd9Sstevel@tonic-gate static int count_tokens(const char *s)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	int count = 0;
2167c478bd9Sstevel@tonic-gate 	const char *p = s;
2177c478bd9Sstevel@tonic-gate 	int whitespace = 1;
2187c478bd9Sstevel@tonic-gate 	/* Loop along the string counting the number of times we see the
2197c478bd9Sstevel@tonic-gate 	 * beginning of non-whitespace. This tells us
2207c478bd9Sstevel@tonic-gate 	 * the number of tokens in the string
2217c478bd9Sstevel@tonic-gate 	 */
2227c478bd9Sstevel@tonic-gate 	while (*p != '\0') {
2237c478bd9Sstevel@tonic-gate 		if (whitespace) {
2247c478bd9Sstevel@tonic-gate 			if (!isspace(*p)) {
2257c478bd9Sstevel@tonic-gate 				whitespace = 0;
2267c478bd9Sstevel@tonic-gate 				count++;
2277c478bd9Sstevel@tonic-gate 			}
2287c478bd9Sstevel@tonic-gate 		} else {
2297c478bd9Sstevel@tonic-gate 			if (isspace(*p)) {
2307c478bd9Sstevel@tonic-gate 				whitespace = 1;
2317c478bd9Sstevel@tonic-gate 			}
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 		p++;
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 	return count;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 
read_next_token(const char ** s,LDAPsortkey ** key)2397c478bd9Sstevel@tonic-gate static int read_next_token(const char **s,LDAPsortkey **key)
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate 	char c = 0;
2427c478bd9Sstevel@tonic-gate 	const char *pos = *s;
2437c478bd9Sstevel@tonic-gate 	int retval = 0;
2447c478bd9Sstevel@tonic-gate 	LDAPsortkey *new_key = NULL;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	const char *matchrule_source = NULL;
2477c478bd9Sstevel@tonic-gate 	int matchrule_size = 0;
2487c478bd9Sstevel@tonic-gate 	const char *attrdesc_source = NULL;
2497c478bd9Sstevel@tonic-gate 	int attrdesc_size = 0;
2507c478bd9Sstevel@tonic-gate 	int reverse = 0;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	int state = 0;
253*1da57d55SToomas Soome 
2547c478bd9Sstevel@tonic-gate 	while ( ((c = *pos++) != '\0') && (state != 4) ) {
2557c478bd9Sstevel@tonic-gate 		switch (state) {
2567c478bd9Sstevel@tonic-gate 		case 0:
2577c478bd9Sstevel@tonic-gate 		/* case where we've not seen the beginning of the attr yet */
2587c478bd9Sstevel@tonic-gate 			/* If we still see whitespace, nothing to do */
2597c478bd9Sstevel@tonic-gate 			if (!isspace(c)) {
2607c478bd9Sstevel@tonic-gate 				/* Otherwise, something to look at */
2617c478bd9Sstevel@tonic-gate 				/* Is it a minus sign ? */
2627c478bd9Sstevel@tonic-gate 				if ('-' == c) {
2637c478bd9Sstevel@tonic-gate 					reverse = 1;
2647c478bd9Sstevel@tonic-gate 				} else {
2657c478bd9Sstevel@tonic-gate 					attrdesc_source = pos - 1;
2667c478bd9Sstevel@tonic-gate 					state = 1;
2677c478bd9Sstevel@tonic-gate 				}
2687c478bd9Sstevel@tonic-gate 			}
2697c478bd9Sstevel@tonic-gate 			break;
2707c478bd9Sstevel@tonic-gate 		case 1:
2717c478bd9Sstevel@tonic-gate 		/* case where we've seen the beginning of the attr, but not the end */
2727c478bd9Sstevel@tonic-gate 			/* Is this char either whitespace or a ';' ? */
2737c478bd9Sstevel@tonic-gate 			if ( isspace(c) || (':' == c)) {
2747c478bd9Sstevel@tonic-gate 				attrdesc_size = (pos - attrdesc_source) - 1;
2757c478bd9Sstevel@tonic-gate 				if (':' == c) {
2767c478bd9Sstevel@tonic-gate 					state = 2;
2777c478bd9Sstevel@tonic-gate 				} else {
2787c478bd9Sstevel@tonic-gate 					state = 4;
2797c478bd9Sstevel@tonic-gate 				}
280*1da57d55SToomas Soome 			}
2817c478bd9Sstevel@tonic-gate 			break;
2827c478bd9Sstevel@tonic-gate 		case 2:
2837c478bd9Sstevel@tonic-gate 		/* case where we've seen the end of the attr and want the beginning of match rule */
2847c478bd9Sstevel@tonic-gate 			if (!isspace(c)) {
2857c478bd9Sstevel@tonic-gate 				matchrule_source = pos - 1;
2867c478bd9Sstevel@tonic-gate 				state = 3;
2877c478bd9Sstevel@tonic-gate 			} else {
2887c478bd9Sstevel@tonic-gate 				state = 4;
2897c478bd9Sstevel@tonic-gate 			}
2907c478bd9Sstevel@tonic-gate 			break;
2917c478bd9Sstevel@tonic-gate 		case 3:
2927c478bd9Sstevel@tonic-gate 		/* case where we've seen the beginning of match rule and want to find the end */
2937c478bd9Sstevel@tonic-gate 			if (isspace(c)) {
2947c478bd9Sstevel@tonic-gate 				matchrule_size = (pos - matchrule_source) - 1;
2957c478bd9Sstevel@tonic-gate 				state = 4;
2967c478bd9Sstevel@tonic-gate 			}
2977c478bd9Sstevel@tonic-gate 			break;
2987c478bd9Sstevel@tonic-gate 		default:
2997c478bd9Sstevel@tonic-gate 			break;
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 	}
302*1da57d55SToomas Soome 
3037c478bd9Sstevel@tonic-gate 	if (3 == state) {
3047c478bd9Sstevel@tonic-gate 		/* means we fell off the end of the string looking for the end of the marching rule */
3057c478bd9Sstevel@tonic-gate 		matchrule_size = (pos - matchrule_source) - 1;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	if (1 == state) {
3097c478bd9Sstevel@tonic-gate 		/* means we fell of the end of the string looking for the end of the attribute */
3107c478bd9Sstevel@tonic-gate 		attrdesc_size = (pos - attrdesc_source) - 1;
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if (NULL == attrdesc_source)  {
3147c478bd9Sstevel@tonic-gate 		/* Didn't find anything */
3157c478bd9Sstevel@tonic-gate 		return -1;
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	new_key = (LDAPsortkey*)NSLDAPI_MALLOC(sizeof(LDAPsortkey));
3197c478bd9Sstevel@tonic-gate 	if (0 == new_key) {
3207c478bd9Sstevel@tonic-gate 		return LDAP_NO_MEMORY;
3217c478bd9Sstevel@tonic-gate 	}
322*1da57d55SToomas Soome 
3237c478bd9Sstevel@tonic-gate 	/* Allocate the strings */
3247c478bd9Sstevel@tonic-gate 	new_key->sk_attrtype = (char *)NSLDAPI_MALLOC(attrdesc_size + 1);
3257c478bd9Sstevel@tonic-gate 	if (NULL != matchrule_source) {
3267c478bd9Sstevel@tonic-gate 		new_key->sk_matchruleoid = (char *)NSLDAPI_MALLOC(
3277c478bd9Sstevel@tonic-gate 		    matchrule_size + 1);
3287c478bd9Sstevel@tonic-gate 	} else {
3297c478bd9Sstevel@tonic-gate 		new_key->sk_matchruleoid = NULL;
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 	/* Copy over the strings */
3327c478bd9Sstevel@tonic-gate 	memcpy(new_key->sk_attrtype,attrdesc_source,attrdesc_size);
3337c478bd9Sstevel@tonic-gate 	*(new_key->sk_attrtype + attrdesc_size) = '\0';
3347c478bd9Sstevel@tonic-gate 	if (NULL != matchrule_source) {
3357c478bd9Sstevel@tonic-gate 		memcpy(new_key->sk_matchruleoid,matchrule_source,matchrule_size);
3367c478bd9Sstevel@tonic-gate 		*(new_key->sk_matchruleoid + matchrule_size) = '\0';
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	new_key->sk_reverseorder = reverse;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	*s = pos - 1;
3427c478bd9Sstevel@tonic-gate 	*key = new_key;
3437c478bd9Sstevel@tonic-gate 	return retval;
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate int
3477c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_create_sort_keylist(LDAPsortkey *** sortKeyList,const char * string_rep)3487c478bd9Sstevel@tonic-gate ldap_create_sort_keylist (
3497c478bd9Sstevel@tonic-gate 	LDAPsortkey ***sortKeyList,
3507c478bd9Sstevel@tonic-gate 	const char *string_rep
3517c478bd9Sstevel@tonic-gate )
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	int count = 0;
3547c478bd9Sstevel@tonic-gate 	LDAPsortkey **pointer_array = NULL;
3557c478bd9Sstevel@tonic-gate 	const char *current_position = NULL;
3567c478bd9Sstevel@tonic-gate 	int retval = 0;
3577c478bd9Sstevel@tonic-gate 	int i = 0;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/* Figure out how many there are */
3607c478bd9Sstevel@tonic-gate 	if (NULL == string_rep) {
3617c478bd9Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 	if (NULL == sortKeyList) {
3647c478bd9Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 	count = count_tokens(string_rep);
3677c478bd9Sstevel@tonic-gate 	if (0 == count) {
3687c478bd9Sstevel@tonic-gate 		*sortKeyList = NULL;
3697c478bd9Sstevel@tonic-gate 		return LDAP_PARAM_ERROR;
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	/* Allocate enough memory for the pointers */
3727c478bd9Sstevel@tonic-gate 	pointer_array = (LDAPsortkey**)NSLDAPI_MALLOC(sizeof(LDAPsortkey*)
3737c478bd9Sstevel@tonic-gate 	    * (count + 1) );
3747c478bd9Sstevel@tonic-gate 	if (NULL == pointer_array) {
3757c478bd9Sstevel@tonic-gate 		return LDAP_NO_MEMORY;
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 	/* Now walk along the string, allocating and filling in the LDAPsearchkey structure */
3787c478bd9Sstevel@tonic-gate 	current_position = string_rep;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3817c478bd9Sstevel@tonic-gate 		if (0 != (retval = read_next_token(&current_position,&(pointer_array[i])))) {
3827c478bd9Sstevel@tonic-gate 			pointer_array[count] = NULL;
3837c478bd9Sstevel@tonic-gate 			ldap_free_sort_keylist(pointer_array);
3847c478bd9Sstevel@tonic-gate 			*sortKeyList = NULL;
3857c478bd9Sstevel@tonic-gate 			return retval;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 	}
3887c478bd9Sstevel@tonic-gate 	pointer_array[count] = NULL;
3897c478bd9Sstevel@tonic-gate 	*sortKeyList = pointer_array;
3907c478bd9Sstevel@tonic-gate 	return LDAP_SUCCESS;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate void
3947c478bd9Sstevel@tonic-gate LDAP_CALL
ldap_free_sort_keylist(LDAPsortkey ** sortKeyList)3957c478bd9Sstevel@tonic-gate ldap_free_sort_keylist (
3967c478bd9Sstevel@tonic-gate 	LDAPsortkey **sortKeyList
3977c478bd9Sstevel@tonic-gate )
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate 	LDAPsortkey *this_one = NULL;
4007c478bd9Sstevel@tonic-gate 	int i = 0;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	if ( NULL == sortKeyList ) {
4037c478bd9Sstevel@tonic-gate 		return;
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/* Walk down the list freeing the LDAPsortkey structures */
4077c478bd9Sstevel@tonic-gate 	for (this_one = sortKeyList[0]; this_one ; this_one = sortKeyList[++i]) {
4087c478bd9Sstevel@tonic-gate 		/* Free the strings, if present */
4097c478bd9Sstevel@tonic-gate 		if (NULL != this_one->sk_attrtype) {
4107c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE(this_one->sk_attrtype);
4117c478bd9Sstevel@tonic-gate 		}
4127c478bd9Sstevel@tonic-gate 		if (NULL != this_one->sk_matchruleoid) {
4137c478bd9Sstevel@tonic-gate 			NSLDAPI_FREE(this_one->sk_matchruleoid);
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 		NSLDAPI_FREE(this_one);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 	/* Free the pointer list */
4187c478bd9Sstevel@tonic-gate 	NSLDAPI_FREE(sortKeyList);
4197c478bd9Sstevel@tonic-gate }
420