1/*	$NetBSD: pagectrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
2
3/* $OpenLDAP$ */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2021 The OpenLDAP Foundation.
7 * Copyright 2006 Hans Leidekker
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18
19#include <sys/cdefs.h>
20__RCSID("$NetBSD: pagectrl.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
21
22#include "portable.h"
23
24#include <stdio.h>
25#include <ac/stdlib.h>
26#include <ac/string.h>
27#include <ac/time.h>
28
29#include "ldap-int.h"
30
31/* ---------------------------------------------------------------------------
32    ldap_create_page_control_value
33
34    Create and encode the value of the paged results control (RFC 2696).
35
36    ld          (IN) An LDAP session handle
37    pagesize    (IN) Page size requested
38    cookie      (IN) Opaque structure used by the server to track its
39                     location in the search results.  NULL on the
40                     first call.
41    value      (OUT) Control value, SHOULD be freed by calling
42					 ldap_memfree() when done.
43
44    pagedResultsControl ::= SEQUENCE {
45            controlType     1.2.840.113556.1.4.319,
46            criticality     BOOLEAN DEFAULT FALSE,
47            controlValue    searchControlValue }
48
49    searchControlValue ::= SEQUENCE {
50            size            INTEGER (0..maxInt),
51                                    -- requested page size from client
52                                    -- result set size estimate from server
53            cookie          OCTET STRING }
54
55   ---------------------------------------------------------------------------*/
56
57int
58ldap_create_page_control_value(
59	LDAP *ld,
60	ber_int_t pagesize,
61	struct berval	*cookie,
62	struct berval	*value )
63{
64	BerElement	*ber = NULL;
65	ber_tag_t	tag;
66	struct berval	null_cookie = { 0, NULL };
67
68	if ( ld == NULL || value == NULL ||
69		pagesize < 1 || pagesize > LDAP_MAXINT )
70	{
71		if ( ld )
72			ld->ld_errno = LDAP_PARAM_ERROR;
73		return LDAP_PARAM_ERROR;
74	}
75
76	assert( LDAP_VALID( ld ) );
77
78	value->bv_val = NULL;
79	value->bv_len = 0;
80	ld->ld_errno = LDAP_SUCCESS;
81
82	if ( cookie == NULL ) {
83		cookie = &null_cookie;
84	}
85
86	ber = ldap_alloc_ber_with_options( ld );
87	if ( ber == NULL ) {
88		ld->ld_errno = LDAP_NO_MEMORY;
89		return ld->ld_errno;
90	}
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