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 
57 int
ldap_create_page_control_value(LDAP * ld,ber_int_t pagesize,struct berval * cookie,struct berval * value)58 ldap_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 
102 done:;
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 
140 int
ldap_create_page_control(LDAP * ld,ber_int_t pagesize,struct berval * cookie,int iscritical,LDAPControl ** ctrlp)141 ldap_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 
182 int
ldap_parse_pageresponse_control(LDAP * ld,LDAPControl * ctrl,ber_int_t * countp,struct berval * cookie)183 ldap_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 
237 int
ldap_parse_page_control(LDAP * ld,LDAPControl ** ctrls,ber_int_t * countp,struct berval ** cookiep)238 ldap_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