194209Sdes/*	$NetBSD: pagectrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
2115619Sdes
394209Sdes/* $OpenLDAP$ */
494209Sdes/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
594209Sdes *
699158Sdes * Copyright 1998-2021 The OpenLDAP Foundation.
799158Sdes * Copyright 2006 Hans Leidekker
899158Sdes * All rights reserved.
994209Sdes *
1094209Sdes * Redistribution and use in source and binary forms, with or without
1194209Sdes * modification, are permitted only as authorized by the OpenLDAP
1294209Sdes * Public License.
1394209Sdes *
1494209Sdes * A copy of this license is available in the file LICENSE in the
1594209Sdes * top-level directory of the distribution or, alternatively, at
1694209Sdes * <http://www.OpenLDAP.org/license.html>.
1794209Sdes */
1894209Sdes
1994209Sdes#include <sys/cdefs.h>
2094209Sdes__RCSID("$NetBSD: pagectrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
2194209Sdes
2294209Sdes#include "portable.h"
2394209Sdes
2494209Sdes#include <stdio.h>
2594209Sdes#include <ac/stdlib.h>
2694209Sdes#include <ac/string.h>
2794209Sdes#include <ac/time.h>
2894209Sdes
2994209Sdes#include "ldap-int.h"
3094209Sdes
3194209Sdes/* ---------------------------------------------------------------------------
3294209Sdes    ldap_create_page_control_value
3394209Sdes
34115619Sdes    Create and encode the value of the paged results control (RFC 2696).
3594209Sdes
3694209Sdes    ld          (IN) An LDAP session handle
3794209Sdes    pagesize    (IN) Page size requested
3894209Sdes    cookie      (IN) Opaque structure used by the server to track its
39115619Sdes                     location in the search results.  NULL on the
4094209Sdes                     first call.
4194209Sdes    value      (OUT) Control value, SHOULD be freed by calling
4294209Sdes					 ldap_memfree() when done.
4394209Sdes
4494209Sdes    pagedResultsControl ::= SEQUENCE {
4594209Sdes            controlType     1.2.840.113556.1.4.319,
4694209Sdes            criticality     BOOLEAN DEFAULT FALSE,
4794209Sdes            controlValue    searchControlValue }
4894209Sdes
4994209Sdes    searchControlValue ::= SEQUENCE {
5094209Sdes            size            INTEGER (0..maxInt),
5194209Sdes                                    -- requested page size from client
5294209Sdes                                    -- result set size estimate from server
5394209Sdes            cookie          OCTET STRING }
5494209Sdes
5594209Sdes   ---------------------------------------------------------------------------*/
5694209Sdes
5794209Sdesint
5894209Sdesldap_create_page_control_value(
5994209Sdes	LDAP *ld,
60107937Sdes	ber_int_t pagesize,
6194209Sdes	struct berval	*cookie,
6294209Sdes	struct berval	*value )
63107937Sdes{
6494209Sdes	BerElement	*ber = NULL;
65107937Sdes	ber_tag_t	tag;
66110503Sdes	struct berval	null_cookie = { 0, NULL };
67115619Sdes
68115619Sdes	if ( ld == NULL || value == NULL ||
69115619Sdes		pagesize < 1 || pagesize > LDAP_MAXINT )
70110503Sdes	{
71110503Sdes		if ( ld )
7294209Sdes			ld->ld_errno = LDAP_PARAM_ERROR;
73107937Sdes		return LDAP_PARAM_ERROR;
7494209Sdes	}
7594209Sdes
7694209Sdes	assert( LDAP_VALID( ld ) );
7794209Sdes
7894209Sdes	value->bv_val = NULL;
7994209Sdes	value->bv_len = 0;
8094209Sdes	ld->ld_errno = LDAP_SUCCESS;
8194209Sdes
8294209Sdes	if ( cookie == NULL ) {
8394209Sdes		cookie = &null_cookie;
8494209Sdes	}
8594209Sdes
8694209Sdes	ber = ldap_alloc_ber_with_options( ld );
8794209Sdes	if ( ber == NULL ) {
8894209Sdes		ld->ld_errno = LDAP_NO_MEMORY;
8994209Sdes		return ld->ld_errno;
9094209Sdes	}
91
92	tag = ber_printf( ber, "{iO}", pagesize, cookie );
93	if ( tag == LBER_ERROR ) {
94		ld->ld_errno = LDAP_ENCODING_ERROR;
95		goto done;
96	}
97
98	if ( ber_flatten2( ber, value, 1 ) == -1 ) {
99		ld->ld_errno = LDAP_NO_MEMORY;
100	}
101
102done:;
103	if ( ber != NULL ) {
104		ber_free( ber, 1 );
105	}
106
107	return ld->ld_errno;
108}
109
110
111/* ---------------------------------------------------------------------------
112    ldap_create_page_control
113
114    Create and encode a page control.
115
116    ld          (IN) An LDAP session handle
117    pagesize    (IN) Page size requested
118    cookie      (IN) Opaque structure used by the server to track its
119                     location in the search results.  NULL on the
120                     first call.
121    value      (OUT) Control value, SHOULD be freed by calling
122					 ldap_memfree() when done.
123    iscritical  (IN) Criticality
124    ctrlp      (OUT) LDAP control, SHOULD be freed by calling
125					 ldap_control_free() when done.
126
127    pagedResultsControl ::= SEQUENCE {
128            controlType     1.2.840.113556.1.4.319,
129            criticality     BOOLEAN DEFAULT FALSE,
130            controlValue    searchControlValue }
131
132    searchControlValue ::= SEQUENCE {
133            size            INTEGER (0..maxInt),
134                                    -- requested page size from client
135                                    -- result set size estimate from server
136            cookie          OCTET STRING }
137
138   ---------------------------------------------------------------------------*/
139
140int
141ldap_create_page_control(
142	LDAP		*ld,
143	ber_int_t	pagesize,
144	struct berval	*cookie,
145	int		iscritical,
146	LDAPControl	**ctrlp )
147{
148	struct berval	value;
149
150	if ( ctrlp == NULL ) {
151		ld->ld_errno = LDAP_PARAM_ERROR;
152		return ld->ld_errno;
153	}
154
155	ld->ld_errno = ldap_create_page_control_value( ld,
156		pagesize, cookie, &value );
157	if ( ld->ld_errno == LDAP_SUCCESS ) {
158		ld->ld_errno = ldap_control_create( LDAP_CONTROL_PAGEDRESULTS,
159			iscritical, &value, 0, ctrlp );
160		if ( ld->ld_errno != LDAP_SUCCESS ) {
161			LDAP_FREE( value.bv_val );
162		}
163	}
164
165	return ld->ld_errno;
166}
167
168
169/* ---------------------------------------------------------------------------
170    ldap_parse_pageresponse_control
171
172    Decode a page control.
173
174    ld          (IN) An LDAP session handle
175    ctrl        (IN) The page response control
176    count      (OUT) The number of entries in the page.
177    cookie     (OUT) Opaque cookie.  Use ldap_memfree() to
178                     free the bv_val member of this structure.
179
180   ---------------------------------------------------------------------------*/
181
182int
183ldap_parse_pageresponse_control(
184	LDAP *ld,
185	LDAPControl *ctrl,
186	ber_int_t *countp,
187	struct berval *cookie )
188{
189	BerElement *ber;
190	ber_tag_t tag;
191	ber_int_t count;
192
193	if ( ld == NULL || ctrl == NULL || cookie == NULL ) {
194		if ( ld )
195			ld->ld_errno = LDAP_PARAM_ERROR;
196		return LDAP_PARAM_ERROR;
197	}
198
199	/* Create a BerElement from the berval returned in the control. */
200	ber = ber_init( &ctrl->ldctl_value );
201
202	if ( ber == NULL ) {
203		ld->ld_errno = LDAP_NO_MEMORY;
204		return ld->ld_errno;
205	}
206
207	/* Extract the count and cookie from the control. */
208	tag = ber_scanf( ber, "{io}", &count, cookie );
209        ber_free( ber, 1 );
210
211	if ( tag == LBER_ERROR ) {
212		ld->ld_errno = LDAP_DECODING_ERROR;
213	} else {
214		ld->ld_errno = LDAP_SUCCESS;
215
216		if ( countp != NULL ) {
217			*countp = (unsigned long)count;
218		}
219	}
220
221	return ld->ld_errno;
222}
223
224/* ---------------------------------------------------------------------------
225    ldap_parse_page_control
226
227    Decode a page control.
228
229    ld          (IN) An LDAP session handle
230    ctrls       (IN) Response controls
231    count      (OUT) The number of entries in the page.
232    cookie     (OUT) Opaque cookie.  Use ldap_memfree() to
233                     free the bv_val member of this structure.
234
235   ---------------------------------------------------------------------------*/
236
237int
238ldap_parse_page_control(
239	LDAP		*ld,
240	LDAPControl	**ctrls,
241	ber_int_t *countp,
242	struct berval	**cookiep )
243{
244	LDAPControl *c;
245	struct berval	cookie;
246
247	if ( cookiep == NULL ) {
248		ld->ld_errno = LDAP_PARAM_ERROR;
249		return ld->ld_errno;
250	}
251
252	if ( ctrls == NULL ) {
253		ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
254		return ld->ld_errno;
255	}
256
257	c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, NULL );
258	if ( c == NULL ) {
259		/* No page control was found. */
260		ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
261		return ld->ld_errno;
262	}
263
264	ld->ld_errno = ldap_parse_pageresponse_control( ld, c, countp, &cookie );
265	if ( ld->ld_errno == LDAP_SUCCESS ) {
266		*cookiep = LDAP_MALLOC( sizeof( struct berval ) );
267		if ( *cookiep == NULL ) {
268			ld->ld_errno = LDAP_NO_MEMORY;
269		} else {
270			**cookiep = cookie;
271		}
272	}
273
274	return ld->ld_errno;
275}
276
277