1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2011 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
52int
53ldap_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
97done:;
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
135int
136ldap_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
177int
178ldap_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
232int
233ldap_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