1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2021 The OpenLDAP Foundation.
5  * Copyright 2006 Hans Leidekker
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 
17 #include "portable.h"
18 
19 #include <stdio.h>
20 #include <ac/stdlib.h>
21 #include <ac/string.h>
22 #include <ac/time.h>
23 
24 #include "ldap-int.h"
25 
26 /* ---------------------------------------------------------------------------
27     ldap_create_page_control_value
28 
29     Create and encode the value of the paged results control (RFC 2696).
30 
31     ld          (IN) An LDAP session handle
32     pagesize    (IN) Page size requested
33     cookie      (IN) Opaque structure used by the server to track its
34                      location in the search results.  NULL on the
35                      first call.
36     value      (OUT) Control value, SHOULD be freed by calling
37 					 ldap_memfree() when done.
38 
39     pagedResultsControl ::= SEQUENCE {
40             controlType     1.2.840.113556.1.4.319,
41             criticality     BOOLEAN DEFAULT FALSE,
42             controlValue    searchControlValue }
43 
44     searchControlValue ::= SEQUENCE {
45             size            INTEGER (0..maxInt),
46                                     -- requested page size from client
47                                     -- result set size estimate from server
48             cookie          OCTET STRING }
49 
50    ---------------------------------------------------------------------------*/
51 
52 int
ldap_create_page_control_value(LDAP * ld,ber_int_t pagesize,struct berval * cookie,struct berval * value)53 ldap_create_page_control_value(
54 	LDAP *ld,
55 	ber_int_t pagesize,
56 	struct berval	*cookie,
57 	struct berval	*value )
58 {
59 	BerElement	*ber = NULL;
60 	ber_tag_t	tag;
61 	struct berval	null_cookie = { 0, NULL };
62 
63 	if ( ld == NULL || value == NULL ||
64 		pagesize < 1 || pagesize > LDAP_MAXINT )
65 	{
66 		if ( ld )
67 			ld->ld_errno = LDAP_PARAM_ERROR;
68 		return LDAP_PARAM_ERROR;
69 	}
70 
71 	assert( LDAP_VALID( ld ) );
72 
73 	value->bv_val = NULL;
74 	value->bv_len = 0;
75 	ld->ld_errno = LDAP_SUCCESS;
76 
77 	if ( cookie == NULL ) {
78 		cookie = &null_cookie;
79 	}
80 
81 	ber = ldap_alloc_ber_with_options( ld );
82 	if ( ber == NULL ) {
83 		ld->ld_errno = LDAP_NO_MEMORY;
84 		return ld->ld_errno;
85 	}
86 
87 	tag = ber_printf( ber, "{iO}", pagesize, cookie );
88 	if ( tag == LBER_ERROR ) {
89 		ld->ld_errno = LDAP_ENCODING_ERROR;
90 		goto done;
91 	}
92 
93 	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
94 		ld->ld_errno = LDAP_NO_MEMORY;
95 	}
96 
97 done:;
98 	if ( ber != NULL ) {
99 		ber_free( ber, 1 );
100 	}
101 
102 	return ld->ld_errno;
103 }
104 
105 
106 /* ---------------------------------------------------------------------------
107     ldap_create_page_control
108 
109     Create and encode a page control.
110 
111     ld          (IN) An LDAP session handle
112     pagesize    (IN) Page size requested
113     cookie      (IN) Opaque structure used by the server to track its
114                      location in the search results.  NULL on the
115                      first call.
116     value      (OUT) Control value, SHOULD be freed by calling
117 					 ldap_memfree() when done.
118     iscritical  (IN) Criticality
119     ctrlp      (OUT) LDAP control, SHOULD be freed by calling
120 					 ldap_control_free() when done.
121 
122     pagedResultsControl ::= SEQUENCE {
123             controlType     1.2.840.113556.1.4.319,
124             criticality     BOOLEAN DEFAULT FALSE,
125             controlValue    searchControlValue }
126 
127     searchControlValue ::= SEQUENCE {
128             size            INTEGER (0..maxInt),
129                                     -- requested page size from client
130                                     -- result set size estimate from server
131             cookie          OCTET STRING }
132 
133    ---------------------------------------------------------------------------*/
134 
135 int
ldap_create_page_control(LDAP * ld,ber_int_t pagesize,struct berval * cookie,int iscritical,LDAPControl ** ctrlp)136 ldap_create_page_control(
137 	LDAP		*ld,
138 	ber_int_t	pagesize,
139 	struct berval	*cookie,
140 	int		iscritical,
141 	LDAPControl	**ctrlp )
142 {
143 	struct berval	value;
144 
145 	if ( ctrlp == NULL ) {
146 		ld->ld_errno = LDAP_PARAM_ERROR;
147 		return ld->ld_errno;
148 	}
149 
150 	ld->ld_errno = ldap_create_page_control_value( ld,
151 		pagesize, cookie, &value );
152 	if ( ld->ld_errno == LDAP_SUCCESS ) {
153 		ld->ld_errno = ldap_control_create( LDAP_CONTROL_PAGEDRESULTS,
154 			iscritical, &value, 0, ctrlp );
155 		if ( ld->ld_errno != LDAP_SUCCESS ) {
156 			LDAP_FREE( value.bv_val );
157 		}
158 	}
159 
160 	return ld->ld_errno;
161 }
162 
163 
164 /* ---------------------------------------------------------------------------
165     ldap_parse_pageresponse_control
166 
167     Decode a page control.
168 
169     ld          (IN) An LDAP session handle
170     ctrl        (IN) The page response control
171     count      (OUT) The number of entries in the page.
172     cookie     (OUT) Opaque cookie.  Use ldap_memfree() to
173                      free the bv_val member of this structure.
174 
175    ---------------------------------------------------------------------------*/
176 
177 int
ldap_parse_pageresponse_control(LDAP * ld,LDAPControl * ctrl,ber_int_t * countp,struct berval * cookie)178 ldap_parse_pageresponse_control(
179 	LDAP *ld,
180 	LDAPControl *ctrl,
181 	ber_int_t *countp,
182 	struct berval *cookie )
183 {
184 	BerElement *ber;
185 	ber_tag_t tag;
186 	ber_int_t count;
187 
188 	if ( ld == NULL || ctrl == NULL || cookie == NULL ) {
189 		if ( ld )
190 			ld->ld_errno = LDAP_PARAM_ERROR;
191 		return LDAP_PARAM_ERROR;
192 	}
193 
194 	/* Create a BerElement from the berval returned in the control. */
195 	ber = ber_init( &ctrl->ldctl_value );
196 
197 	if ( ber == NULL ) {
198 		ld->ld_errno = LDAP_NO_MEMORY;
199 		return ld->ld_errno;
200 	}
201 
202 	/* Extract the count and cookie from the control. */
203 	tag = ber_scanf( ber, "{io}", &count, cookie );
204         ber_free( ber, 1 );
205 
206 	if ( tag == LBER_ERROR ) {
207 		ld->ld_errno = LDAP_DECODING_ERROR;
208 	} else {
209 		ld->ld_errno = LDAP_SUCCESS;
210 
211 		if ( countp != NULL ) {
212 			*countp = (unsigned long)count;
213 		}
214 	}
215 
216 	return ld->ld_errno;
217 }
218 
219 /* ---------------------------------------------------------------------------
220     ldap_parse_page_control
221 
222     Decode a page control.
223 
224     ld          (IN) An LDAP session handle
225     ctrls       (IN) Response controls
226     count      (OUT) The number of entries in the page.
227     cookie     (OUT) Opaque cookie.  Use ldap_memfree() to
228                      free the bv_val member of this structure.
229 
230    ---------------------------------------------------------------------------*/
231 
232 int
ldap_parse_page_control(LDAP * ld,LDAPControl ** ctrls,ber_int_t * countp,struct berval ** cookiep)233 ldap_parse_page_control(
234 	LDAP		*ld,
235 	LDAPControl	**ctrls,
236 	ber_int_t *countp,
237 	struct berval	**cookiep )
238 {
239 	LDAPControl *c;
240 	struct berval	cookie;
241 
242 	if ( cookiep == NULL ) {
243 		ld->ld_errno = LDAP_PARAM_ERROR;
244 		return ld->ld_errno;
245 	}
246 
247 	if ( ctrls == NULL ) {
248 		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
249 		return ld->ld_errno;
250 	}
251 
252 	c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
253 	if ( c == NULL ) {
254 		/* No page control was found. */
255 		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
256 		return ld->ld_errno;
257 	}
258 
259 	ld->ld_errno = ldap_parse_pageresponse_control( ld, c, countp, &cookie );
260 	if ( ld->ld_errno == LDAP_SUCCESS ) {
261 		*cookiep = LDAP_MALLOC( sizeof( struct berval ) );
262 		if ( *cookiep == NULL ) {
263 			ld->ld_errno = LDAP_NO_MEMORY;
264 		} else {
265 			**cookiep = cookie;
266 		}
267 	}
268 
269 	return ld->ld_errno;
270 }
271 
272