xref: /onnv-gate/usr/src/lib/libldap4/common/sortctrl.c (revision 3857:21b9b714e4ab)
1 /*
2  *
3  * Copyright 1999 Sun Microsystems, Inc.  All rights reserved.
4  * Use is subject to license terms.
5  *
6  *
7  * Comments:
8  *
9  */
10 
11 #pragma ident	"%Z%%M%	%I%	%E% SMI"
12 
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 
17 #include "lber.h"
18 #include "ldap.h"
19 #include "ldap-private.h"
20 #include "ldap-int.h"
21 
22 static int count_tokens(char *s);
23 static int isattrdescchar(char c);
24 static int read_next_token(char **s, LDAPsortkey **key);
25 
26 
ldap_create_sort_control(LDAP * ld,LDAPsortkey ** sortKeyList,const char ctl_iscritical,LDAPControl ** ctrlp)27 int ldap_create_sort_control(LDAP *ld, LDAPsortkey **sortKeyList,
28 	const char ctl_iscritical, LDAPControl **ctrlp)
29 {
30 	BerElement *ber;
31 	int i, rc;
32 
33 	if (NULL == ld) {
34 		return (LDAP_PARAM_ERROR);
35 	}
36 
37 	if (sortKeyList == NULL || ctrlp == NULL) {
38 		ld->ld_errno = LDAP_PARAM_ERROR;
39 		return (LDAP_PARAM_ERROR);
40 	}
41 
42 	/* create a ber package to hold the controlValue */
43 	if ((ber = alloc_ber_with_options(ld)) == NULLBER) {
44 		ld->ld_errno = LDAP_NO_MEMORY;
45 		return (LDAP_NO_MEMORY);
46 	}
47 
48 	/* encode the start of the sequence of sequences into the ber */
49 	if (ber_printf(ber, "{") == -1) {
50 		goto encoding_error_exit;
51 	}
52 
53 	/*
54 	 * the sort control value will be encoded as a sequence of sequences
55 	 * which are each encoded as one of the following: {s} or {sts} or
56 	 * {stb} or {ststb} since the orderingRule and reverseOrder flag are
57 	 * both optional
58 	 */
59 	for (i = 0; sortKeyList[i] != NULL; i++) {
60 
61 		/* encode the attributeType into the ber */
62 		if (ber_printf(ber, "{s", (sortKeyList[i])->sk_attrtype)
63 		    == -1) {
64 			goto encoding_error_exit;
65 		}
66 
67 		/* encode the optional orderingRule into the ber */
68 		if ((sortKeyList[i])->sk_matchruleoid != NULL) {
69 			if (ber_printf(ber, "ts", LDAP_TAG_SK_MATCHRULE,
70 			    (sortKeyList[i])->sk_matchruleoid)
71 			    == -1) {
72 				goto encoding_error_exit;
73 			}
74 		}
75 
76 		/* Encode the optional reverseOrder flag into the ber. */
77 		/* If the flag is false, it should be absent. */
78 		if ((sortKeyList[i])->sk_reverseorder) {
79 			if (ber_printf(ber, "tb}", LDAP_TAG_SK_REVERSE,
80 			    (sortKeyList[i])->sk_reverseorder) == -1) {
81 				goto encoding_error_exit;
82 			}
83 		} else {
84 			if (ber_printf(ber, "}") == -1) {
85 				goto encoding_error_exit;
86 			}
87 		}
88 	}
89 
90 	/* encode the end of the sequence of sequences into the ber */
91 	if (ber_printf(ber, "}") == -1) {
92 		goto encoding_error_exit;
93 	}
94 
95 	rc = ldap_build_control(LDAP_CONTROL_SORTREQUEST, ber, 1,
96 	    ctl_iscritical, ctrlp);
97 	ld->ld_errno = rc;
98 	return (rc);
99 
100 encoding_error_exit:
101 	ld->ld_errno = LDAP_ENCODING_ERROR;
102 	ber_free(ber, 1);
103 	return (LDAP_ENCODING_ERROR);
104 }
105 
106 
ldap_parse_sort_control(LDAP * ld,LDAPControl ** ctrlp,unsigned long * result,char ** attribute)107 int ldap_parse_sort_control(LDAP *ld, LDAPControl **ctrlp,
108 	unsigned long *result, char **attribute)
109 {
110 	BerElement *ber;
111 	int i, foundSortControl;
112 	LDAPControl *sortCtrlp;
113 	unsigned int len;
114 	char *attr;
115 	int tag;
116 
117 	if ((NULL == ld) || (result == NULL) ||
118 		(attribute == NULL)) {
119 	    return (LDAP_PARAM_ERROR);
120 	}
121 
122 
123 	/* find the sortControl in the list of controls if it exists */
124 	if (ctrlp == NULL) {
125 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
126 		return (LDAP_CONTROL_NOT_FOUND);
127 	}
128 	foundSortControl = 0;
129 	for (i = 0; ((ctrlp[i] != NULL) && (!foundSortControl)); i++) {
130 		foundSortControl = !(strcmp(ctrlp[i]->ldctl_oid,
131 			LDAP_CONTROL_SORTRESPONSE));
132 	}
133 	if (!foundSortControl) {
134 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
135 		return (LDAP_CONTROL_NOT_FOUND);
136 	} else {
137 		/* let local var point to the sortControl */
138 		sortCtrlp = ctrlp[i-1];
139 	}
140 
141 	/*
142 	 * allocate a Ber element with the contents of the sort_control's
143 	 * struct berval
144 	 */
145 	if ((ber = ber_init(&sortCtrlp->ldctl_value)) == NULL) {
146 		ld->ld_errno = LDAP_NO_MEMORY;
147 		return (LDAP_NO_MEMORY);
148 	}
149 
150 	/* decode the result from the Berelement */
151 	if (ber_scanf(ber, "{i", result) == LBER_ERROR) {
152 		ld->ld_errno = LDAP_DECODING_ERROR;
153 		ber_free(ber, 1);
154 		return (LDAP_DECODING_ERROR);
155 	}
156 
157 	/*
158 	 * if the server returned one, decode the attribute from the Ber element
159 	 */
160 	if (ber_peek_tag(ber, &len) == LDAP_TAG_SR_ATTRTYPE) {
161 		if (ber_scanf(ber, "ta", &tag, &attr) == LBER_ERROR) {
162 			ld->ld_errno = LDAP_DECODING_ERROR;
163 			ber_free(ber, 1);
164 			return (LDAP_DECODING_ERROR);
165 		}
166 		*attribute = attr;
167 	} else {
168 		*attribute = NULL;
169 	}
170 
171 	if (ber_scanf(ber, "}") == LBER_ERROR) {
172 		ld->ld_errno = LDAP_DECODING_ERROR;
173 		ber_free(ber, 1);
174 		return (LDAP_DECODING_ERROR);
175 	}
176 
177 	/* the ber encoding is no longer needed */
178 	ber_free(ber, 1);
179 	return (LDAP_SUCCESS);
180 }
181 
182 
183 /*
184  * Routines for the manipulation of string-representations of sort control
185  * keylists
186  */
count_tokens(char * s)187 static int count_tokens(char *s)
188 {
189 	int count = 0;
190 	char *p = s;
191 	int whitespace = 1;
192 	/*
193 	 * Loop along the string counting the number of times we see the
194 	 * beginning of non-whitespace. This tells us
195 	 * the number of tokens in the string
196 	 */
197 	while (*p != '\0') {
198 		if (whitespace) {
199 			if (!isspace(*p)) {
200 				whitespace = 0;
201 				count++;
202 			}
203 		} else {
204 			if (isspace(*p)) {
205 				whitespace = 1;
206 			}
207 		}
208 		p++;
209 	}
210 	return (count);
211 }
212 
213 
214 /* Is this character a valid attribute description character ? */
isattrdescchar(char c)215 static int isattrdescchar(char c)
216 {
217 	/* Alphanumeric chars are in */
218 	if (isalnum(c)) {
219 		return (1);
220 	}
221 	/* As is ';' */
222 	if (';' == c) {
223 		return (1);
224 	}
225 	/* Everything else is out */
226 	return (0);
227 }
228 
229 
read_next_token(char ** s,LDAPsortkey ** key)230 static int read_next_token(char **s, LDAPsortkey **key)
231 {
232 	char c = 0;
233 	char *pos = *s;
234 	int retval = 0;
235 	LDAPsortkey *new_key = NULL;
236 
237 	char *matchrule_source = NULL;
238 	int matchrule_size = 0;
239 	char *attrdesc_source = NULL;
240 	int attrdesc_size = 0;
241 	int reverse = 0;
242 
243 	int state = 0;
244 
245 	while (((c = *pos++) != '\0') && (state != 4)) {
246 		switch (state) {
247 		case 0:
248 		/* case where we've not seen the beginning of the attr yet */
249 			/* If we still see whitespace, nothing to do */
250 			if (!isspace(c)) {
251 				/* Otherwise, something to look at */
252 				/* Is it a minus sign ? */
253 				if ('-' == c) {
254 					reverse = 1;
255 				} else {
256 					attrdesc_source = pos - 1;
257 					state = 1;
258 				}
259 			}
260 			break;
261 		case 1:
262 		/*
263 		 * case where we've seen the beginning of the attr, but not
264 		 * the end
265 		 */
266 			/* Is this char either whitespace or a ':' ? */
267 			if (isspace(c) || (':' == c)) {
268 				attrdesc_size = (pos - attrdesc_source) - 1;
269 				if (':' == c) {
270 					state = 2;
271 				} else {
272 					state = 4;
273 				}
274 			}
275 			break;
276 		case 2:
277 		/*
278 		 * case where we've seen the end of the attr and want the
279 		 * beginning of match rule
280 		 */
281 			if (!isspace(c)) {
282 				matchrule_source = pos - 1;
283 				state = 3;
284 			} else {
285 				state = 4;
286 			}
287 			break;
288 		case 3:
289 		/*
290 		 * case where we've seen the beginning of match rule and
291 		 * want to find the end
292 		 */
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 		/*
305 		 * means we fell off the end of the string looking for the
306 		 * end of the marching rule
307 		 */
308 		matchrule_size = (pos - matchrule_source) - 1;
309 	}
310 
311 	if (1 == state) {
312 		/*
313 		 * means we fell of the end of the string looking for the
314 		 * end of the attribute
315 		 */
316 		attrdesc_size = (pos - attrdesc_source) - 1;
317 	}
318 
319 	if (NULL == attrdesc_source)  {
320 		/* Didn't find anything */
321 		return (-1);
322 	}
323 
324 	new_key = (LDAPsortkey*)malloc(sizeof (LDAPsortkey));
325 	if (0 == new_key) {
326 		return (LDAP_NO_MEMORY);
327 	}
328 
329 	/* Allocate the strings */
330 	new_key->sk_attrtype = (char *)malloc(attrdesc_size + 1);
331 	if (NULL != matchrule_source) {
332 		new_key->sk_matchruleoid = (char *)malloc(matchrule_size + 1);
333 	} else {
334 		new_key->sk_matchruleoid = NULL;
335 	}
336 	/* Copy over the strings */
337 	memcpy(new_key->sk_attrtype, attrdesc_source, attrdesc_size);
338 	*(new_key->sk_attrtype + attrdesc_size) = '\0';
339 	if (NULL != matchrule_source) {
340 		memcpy(new_key->sk_matchruleoid, matchrule_source,
341 			matchrule_size);
342 		*(new_key->sk_matchruleoid + matchrule_size) = '\0';
343 	}
344 
345 	new_key->sk_reverseorder = reverse;
346 
347 	*s = pos - 1;
348 	*key = new_key;
349 	return (retval);
350 }
351 
352 
353 int
ldap_create_sort_keylist(LDAPsortkey *** sortKeyList,char * string_rep)354 ldap_create_sort_keylist(LDAPsortkey ***sortKeyList, char *string_rep)
355 {
356 	int count = 0;
357 	LDAPsortkey **pointer_array = NULL;
358 	char *current_position = NULL;
359 	char *s = NULL;
360 	int retval = 0;
361 	int i = 0;
362 
363 	/* Figure out how many there are */
364 	if (NULL == string_rep) {
365 		return (LDAP_PARAM_ERROR);
366 	}
367 	if (NULL == sortKeyList) {
368 		return (LDAP_PARAM_ERROR);
369 	}
370 	count = count_tokens(string_rep);
371 	if (0 == count) {
372 		*sortKeyList = NULL;
373 		return (LDAP_PARAM_ERROR);
374 	}
375 	/* Allocate enough memory for the pointers */
376 	pointer_array = (LDAPsortkey**)malloc(sizeof (LDAPsortkey*)
377 	    * (count + 1));
378 	if (NULL == pointer_array) {
379 		return (LDAP_NO_MEMORY);
380 	}
381 	/*
382 	 * Now walk along the string, allocating and filling in the
383 	 * LDAPsearchkey structure
384 	 */
385 	current_position = string_rep;
386 
387 	for (i = 0; i < count; i++) {
388 		if (0 != (retval = read_next_token(&current_position,
389 			&(pointer_array[i])))) {
390 			pointer_array[count] = NULL;
391 			ldap_free_sort_keylist(pointer_array);
392 			*sortKeyList = NULL;
393 			return (retval);
394 		}
395 	}
396 	pointer_array[count] = NULL;
397 	*sortKeyList = pointer_array;
398 	return (LDAP_SUCCESS);
399 }
400 
401 
402 void
ldap_free_sort_keylist(LDAPsortkey ** sortKeyList)403 ldap_free_sort_keylist(LDAPsortkey **sortKeyList)
404 {
405 	LDAPsortkey *this_one = NULL;
406 	int i = 0;
407 
408 	if (NULL == sortKeyList) {
409 		return;
410 	}
411 
412 	/* Walk down the list freeing the LDAPsortkey structures */
413 	for (this_one = sortKeyList[0]; this_one;
414 		this_one = sortKeyList[++i]) {
415 		/* Free the strings, if present */
416 		if (NULL != this_one->sk_attrtype) {
417 			free(this_one->sk_attrtype);
418 		}
419 		if (NULL != this_one->sk_matchruleoid) {
420 			free(this_one->sk_matchruleoid);
421 		}
422 		free(this_one);
423 	}
424 	/* Free the pointer list */
425 	free(sortKeyList);
426 }
427