1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * The contents of this file are subject to the Netscape Public License
4  * Version 1.0 (the "NPL"); you may not use this file except in
5  * compliance with the NPL.  You may obtain a copy of the NPL at
6  * http://www.mozilla.org/NPL/
7  *
8  * Software distributed under the NPL is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
10  * for the specific language governing rights and limitations under the
11  * NPL.
12  *
13  * The Initial Developer of this code under the NPL is Netscape
14  * Communications Corporation.  Portions created by Netscape are
15  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
16  * Reserved.
17  */
18 #include "ldap-int.h"
19 
20 /* ldap_create_sort_control:
21 
22    Parameters are
23 
24    ld              LDAP pointer to the desired connection
25 
26    sortKeyList     an array of sortkeys
27 
28    ctl_iscritical  Indicates whether the control is critical of not. If
29                    this field is non-zero, the operation will only be car-
30                    ried out if the control is recognized by the server
31                    and/or client
32 
33    ctrlp           the address of a place to put the constructed control
34 */
35 
36 int
37 LDAP_CALL
ldap_create_sort_control(LDAP * ld,LDAPsortkey ** sortKeyList,const char ctl_iscritical,LDAPControl ** ctrlp)38 ldap_create_sort_control (
39      LDAP *ld,
40      LDAPsortkey **sortKeyList,
41      const char ctl_iscritical,
42      LDAPControl **ctrlp
43 )
44 {
45 	BerElement		*ber;
46 	int				i, rc;
47 
48 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
49 		return( LDAP_PARAM_ERROR );
50 	}
51 
52 	if ( sortKeyList == NULL || ctrlp == NULL ) {
53 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
54 		return ( LDAP_PARAM_ERROR );
55 	}
56 
57 	/* create a ber package to hold the controlValue */
58 	if ( ( nsldapi_alloc_ber_with_options( ld, &ber ) ) != LDAP_SUCCESS ) {
59 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
60 		return( LDAP_NO_MEMORY );
61 	}
62 
63 	/* encode the start of the sequence of sequences into the ber */
64 	if ( ber_printf( ber, "{" ) == -1 ) {
65 		goto encoding_error_exit;
66 	}
67 
68 	/* the sort control value will be encoded as a sequence of sequences
69 	   which are each encoded as one of the following: {s} or {sts} or {stb} or {ststb}
70 	   since the orderingRule and reverseOrder flag are both optional */
71 	for ( i = 0; sortKeyList[i] != NULL; i++ ) {
72 
73 		/* encode the attributeType into the ber */
74 		if ( ber_printf( ber, "{s", (sortKeyList[i])->sk_attrtype  )
75 		    == -1 ) {
76 			goto encoding_error_exit;
77 		}
78 
79 		/* encode the optional orderingRule into the ber */
80 		if ( (sortKeyList[i])->sk_matchruleoid != NULL ) {
81 			if ( ber_printf( ber, "ts", LDAP_TAG_SK_MATCHRULE,
82 			    (sortKeyList[i])->sk_matchruleoid )
83 			    == -1 ) {
84 				goto encoding_error_exit;
85 			}
86 		}
87 
88 		/* Encode the optional reverseOrder flag into the ber. */
89 		/* If the flag is false, it should be absent. */
90 		if ( (sortKeyList[i])->sk_reverseorder ) {
91 			if ( ber_printf( ber, "tb}", LDAP_TAG_SK_REVERSE,
92 			    (sortKeyList[i])->sk_reverseorder ) == -1 ) {
93 				goto encoding_error_exit;
94 			}
95 		} else {
96 			if ( ber_printf( ber, "}" ) == -1 ) {
97 				goto encoding_error_exit;
98 			}
99 		}
100 	}
101 
102 	/* encode the end of the sequence of sequences into the ber */
103 	if ( ber_printf( ber, "}" ) == -1 ) {
104 		goto encoding_error_exit;
105 	}
106 
107 	rc = nsldapi_build_control( LDAP_CONTROL_SORTREQUEST, ber, 1,
108 	    ctl_iscritical, ctrlp );
109 
110 	LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
111 	return( rc );
112 
113 encoding_error_exit:
114 	LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
115 	ber_free( ber, 1 );
116 	return( LDAP_ENCODING_ERROR );
117 }
118 
119 /* ldap_parse_sort_control:
120 
121    Parameters are
122 
123    ld              LDAP pointer to the desired connection
124 
125    ctrlp           An array of controls obtained from calling
126                    ldap_parse_result on the set of results returned by
127                    the server
128 
129    result          the address of a place to put the result code
130 
131    attribute       the address of a place to put the name of the
132                    attribute which cause the operation to fail, optionally
133                    returned by the server */
134 
135 int
136 LDAP_CALL
ldap_parse_sort_control(LDAP * ld,LDAPControl ** ctrlp,unsigned long * result,char ** attribute)137 ldap_parse_sort_control (
138      LDAP *ld,
139      LDAPControl **ctrlp,
140      unsigned long *result,
141      char **attribute
142 )
143 {
144 	BerElement *ber;
145 	int i, foundSortControl;
146 	LDAPControl *sortCtrlp;
147 	ber_len_t len;
148 	ber_tag_t tag;
149 	char *attr;
150 
151 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld ) || result == NULL ||
152 		attribute == NULL ) {
153 	    return( LDAP_PARAM_ERROR );
154 	}
155 
156 
157 	/* find the sortControl in the list of controls if it exists */
158 	if ( ctrlp == NULL ) {
159 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
160 		return ( LDAP_CONTROL_NOT_FOUND );
161 	}
162 	foundSortControl = 0;
163 	for ( i = 0; (( ctrlp[i] != NULL ) && ( !foundSortControl )); i++ ) {
164 		foundSortControl = !strcmp( ctrlp[i]->ldctl_oid, LDAP_CONTROL_SORTRESPONSE );
165 	}
166 	if ( !foundSortControl ) {
167 		LDAP_SET_LDERRNO( ld, LDAP_CONTROL_NOT_FOUND, NULL, NULL );
168 		return ( LDAP_CONTROL_NOT_FOUND );
169 	} else {
170 		/* let local var point to the sortControl */
171 		sortCtrlp = ctrlp[i-1];
172 	}
173 
174 	/*  allocate a Ber element with the contents of the sort_control's struct berval */
175 	if ( ( ber = ber_init( &sortCtrlp->ldctl_value ) ) == NULL ) {
176 		LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
177 		return( LDAP_NO_MEMORY );
178 	}
179 
180 	/* decode the result from the Berelement */
181 	if ( ber_scanf( ber, "{i", result ) == LBER_ERROR ) {
182 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
183 		ber_free( ber, 1 );
184 		return( LDAP_DECODING_ERROR );
185 	}
186 
187 	/* if the server returned one, decode the attribute from the Ber element */
188 	if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SR_ATTRTYPE ) {
189 		if ( ber_scanf( ber, "ta", &tag, &attr ) == LBER_ERROR ) {
190 			LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
191 			ber_free( ber, 1 );
192 			return( LDAP_DECODING_ERROR );
193 		}
194 		*attribute = attr;
195 	} else {
196 		*attribute = NULL;
197 	}
198 
199 	if ( ber_scanf( ber, "}" ) == LBER_ERROR ) {
200 		LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
201 		ber_free( ber, 1 );
202 		return( LDAP_DECODING_ERROR );
203 	}
204 
205 	/* the ber encoding is no longer needed */
206 	ber_free(ber,1);
207 
208 	return( LDAP_SUCCESS );
209 }
210 
211 /* Routines for the manipulation of string-representations of sort control keylists */
212 
count_tokens(const char * s)213 static int count_tokens(const char *s)
214 {
215 	int count = 0;
216 	const char *p = s;
217 	int whitespace = 1;
218 	/* Loop along the string counting the number of times we see the
219 	 * beginning of non-whitespace. This tells us
220 	 * the number of tokens in the string
221 	 */
222 	while (*p != '\0') {
223 		if (whitespace) {
224 			if (!isspace(*p)) {
225 				whitespace = 0;
226 				count++;
227 			}
228 		} else {
229 			if (isspace(*p)) {
230 				whitespace = 1;
231 			}
232 		}
233 		p++;
234 	}
235 	return count;
236 }
237 
238 
read_next_token(const char ** s,LDAPsortkey ** key)239 static int read_next_token(const char **s,LDAPsortkey **key)
240 {
241 	char c = 0;
242 	const char *pos = *s;
243 	int retval = 0;
244 	LDAPsortkey *new_key = NULL;
245 
246 	const char *matchrule_source = NULL;
247 	int matchrule_size = 0;
248 	const char *attrdesc_source = NULL;
249 	int attrdesc_size = 0;
250 	int reverse = 0;
251 
252 	int state = 0;
253 
254 	while ( ((c = *pos++) != '\0') && (state != 4) ) {
255 		switch (state) {
256 		case 0:
257 		/* case where we've not seen the beginning of the attr yet */
258 			/* If we still see whitespace, nothing to do */
259 			if (!isspace(c)) {
260 				/* Otherwise, something to look at */
261 				/* Is it a minus sign ? */
262 				if ('-' == c) {
263 					reverse = 1;
264 				} else {
265 					attrdesc_source = pos - 1;
266 					state = 1;
267 				}
268 			}
269 			break;
270 		case 1:
271 		/* case where we've seen the beginning of the attr, but not the end */
272 			/* Is this char either whitespace or a ';' ? */
273 			if ( isspace(c) || (':' == c)) {
274 				attrdesc_size = (pos - attrdesc_source) - 1;
275 				if (':' == c) {
276 					state = 2;
277 				} else {
278 					state = 4;
279 				}
280 			}
281 			break;
282 		case 2:
283 		/* case where we've seen the end of the attr and want the beginning of match rule */
284 			if (!isspace(c)) {
285 				matchrule_source = pos - 1;
286 				state = 3;
287 			} else {
288 				state = 4;
289 			}
290 			break;
291 		case 3:
292 		/* case where we've seen the beginning of match rule and want to find the end */
293 			if (isspace(c)) {
294 				matchrule_size = (pos - matchrule_source) - 1;
295 				state = 4;
296 			}
297 			break;
298 		default:
299 			break;
300 		}
301 	}
302 
303 	if (3 == state) {
304 		/* means we fell off the end of the string looking for the end of the marching rule */
305 		matchrule_size = (pos - matchrule_source) - 1;
306 	}
307 
308 	if (1 == state) {
309 		/* means we fell of the end of the string looking for the end of the attribute */
310 		attrdesc_size = (pos - attrdesc_source) - 1;
311 	}
312 
313 	if (NULL == attrdesc_source)  {
314 		/* Didn't find anything */
315 		return -1;
316 	}
317 
318 	new_key = (LDAPsortkey*)NSLDAPI_MALLOC(sizeof(LDAPsortkey));
319 	if (0 == new_key) {
320 		return LDAP_NO_MEMORY;
321 	}
322 
323 	/* Allocate the strings */
324 	new_key->sk_attrtype = (char *)NSLDAPI_MALLOC(attrdesc_size + 1);
325 	if (NULL != matchrule_source) {
326 		new_key->sk_matchruleoid = (char *)NSLDAPI_MALLOC(
327 		    matchrule_size + 1);
328 	} else {
329 		new_key->sk_matchruleoid = NULL;
330 	}
331 	/* Copy over the strings */
332 	memcpy(new_key->sk_attrtype,attrdesc_source,attrdesc_size);
333 	*(new_key->sk_attrtype + attrdesc_size) = '\0';
334 	if (NULL != matchrule_source) {
335 		memcpy(new_key->sk_matchruleoid,matchrule_source,matchrule_size);
336 		*(new_key->sk_matchruleoid + matchrule_size) = '\0';
337 	}
338 
339 	new_key->sk_reverseorder = reverse;
340 
341 	*s = pos - 1;
342 	*key = new_key;
343 	return retval;
344 }
345 
346 int
347 LDAP_CALL
ldap_create_sort_keylist(LDAPsortkey *** sortKeyList,const char * string_rep)348 ldap_create_sort_keylist (
349 	LDAPsortkey ***sortKeyList,
350 	const char *string_rep
351 )
352 {
353 	int count = 0;
354 	LDAPsortkey **pointer_array = NULL;
355 	const char *current_position = NULL;
356 	int retval = 0;
357 	int i = 0;
358 
359 	/* Figure out how many there are */
360 	if (NULL == string_rep) {
361 		return LDAP_PARAM_ERROR;
362 	}
363 	if (NULL == sortKeyList) {
364 		return LDAP_PARAM_ERROR;
365 	}
366 	count = count_tokens(string_rep);
367 	if (0 == count) {
368 		*sortKeyList = NULL;
369 		return LDAP_PARAM_ERROR;
370 	}
371 	/* Allocate enough memory for the pointers */
372 	pointer_array = (LDAPsortkey**)NSLDAPI_MALLOC(sizeof(LDAPsortkey*)
373 	    * (count + 1) );
374 	if (NULL == pointer_array) {
375 		return LDAP_NO_MEMORY;
376 	}
377 	/* Now walk along the string, allocating and filling in the LDAPsearchkey structure */
378 	current_position = string_rep;
379 
380 	for (i = 0; i < count; i++) {
381 		if (0 != (retval = read_next_token(&current_position,&(pointer_array[i])))) {
382 			pointer_array[count] = NULL;
383 			ldap_free_sort_keylist(pointer_array);
384 			*sortKeyList = NULL;
385 			return retval;
386 		}
387 	}
388 	pointer_array[count] = NULL;
389 	*sortKeyList = pointer_array;
390 	return LDAP_SUCCESS;
391 }
392 
393 void
394 LDAP_CALL
ldap_free_sort_keylist(LDAPsortkey ** sortKeyList)395 ldap_free_sort_keylist (
396 	LDAPsortkey **sortKeyList
397 )
398 {
399 	LDAPsortkey *this_one = NULL;
400 	int i = 0;
401 
402 	if ( NULL == sortKeyList ) {
403 		return;
404 	}
405 
406 	/* Walk down the list freeing the LDAPsortkey structures */
407 	for (this_one = sortKeyList[0]; this_one ; this_one = sortKeyList[++i]) {
408 		/* Free the strings, if present */
409 		if (NULL != this_one->sk_attrtype) {
410 			NSLDAPI_FREE(this_one->sk_attrtype);
411 		}
412 		if (NULL != this_one->sk_matchruleoid) {
413 			NSLDAPI_FREE(this_one->sk_matchruleoid);
414 		}
415 		NSLDAPI_FREE(this_one);
416 	}
417 	/* Free the pointer list */
418 	NSLDAPI_FREE(sortKeyList);
419 }
420