1/* $NetBSD: psearchctrl.c,v 1.2 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 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* ACKNOWLEDGEMENTS: 18 * This work was developed by Howard Chu for inclusion in 19 * OpenLDAP Software. 20 */ 21 22#include <sys/cdefs.h> 23__RCSID("$NetBSD: psearchctrl.c,v 1.2 2021/08/14 16:14:56 christos Exp $"); 24 25#include "portable.h" 26 27#include <stdio.h> 28#include <ac/stdlib.h> 29#include <ac/string.h> 30#include <ac/time.h> 31 32#include "ldap-int.h" 33 34/* Based on draft-ietf-ldapext-c-api-psearch-00 */ 35 36/* --------------------------------------------------------------------------- 37 ldap_create_persistentsearch_control_value 38 39 Create and encode the value of the server-side sort control. 40 41 ld (IN) An LDAP session handle, as obtained from a call to 42 ldap_init(). 43 44 changetypes (IN) A bit-sensitive field that indicates which kinds of 45 changes the client wants to be informed about. Its 46 value should be LDAP_CHANGETYPE_ANY, or any logical-OR 47 combination of LDAP_CHANGETYPE_ADD, 48 LDAP_CHANGETYPE_DELETE, LDAP_CHANGETYPE_MODIFY, and 49 LDAP_CHANGETYPE_MODDN. This field corresponds to the 50 changeType element of the BER-encoded PersistentSearch 51 control value itself. 52 53 changesonly (IN) A Boolean field that indicates whether the client 54 wishes to only receive searchResultEntry messages for 55 entries that have been changed. If non-zero, only 56 entries that result from changes are returned; other- 57 wise, all of the static entries that match the search 58 criteria are returned before the server begins change 59 notification. This field corresponds to the changes- 60 Only element of the BER-encoded PersistentSearch con- 61 trol value itself. 62 63 return_echg_ctls (IN) A Boolean field that indicates whether the server 64 should send back an Entry Change Notification control 65 with each searchResultEntry that is returned due to a 66 change to an entry. If non-zero, Entry Change 67 Notification controls are requested; if zero, they are 68 not. This field corresponds to the returnECs element 69 of the BER-encoded PersistentSearch control value 70 itself. 71 72 value (OUT) Contains the control value; the bv_val member of the berval structure 73 SHOULD be freed by calling ldap_memfree() when done. 74 75 ---------------------------------------------------------------------------*/ 76 77int 78ldap_create_persistentsearch_control_value( 79 LDAP *ld, 80 int changetypes, 81 int changesonly, 82 int return_echg_ctls, 83 struct berval *value ) 84{ 85 int i; 86 BerElement *ber = NULL; 87 ber_tag_t tag; 88 89 assert( ld != NULL ); 90 assert( LDAP_VALID( ld ) ); 91 92 if ( ld == NULL ) return LDAP_PARAM_ERROR; 93 if ( value == NULL ) { 94 ld->ld_errno = LDAP_PARAM_ERROR; 95 return LDAP_PARAM_ERROR; 96 } 97 if (( changetypes & 0x0f ) != changetypes ) { 98 ld->ld_errno = LDAP_PARAM_ERROR; 99 return LDAP_PARAM_ERROR; 100 } 101 102 value->bv_val = NULL; 103 value->bv_len = 0; 104 ld->ld_errno = LDAP_SUCCESS; 105 106 ber = ldap_alloc_ber_with_options( ld ); 107 if ( ber == NULL) { 108 ld->ld_errno = LDAP_NO_MEMORY; 109 return ld->ld_errno; 110 } 111 112 tag = ber_printf( ber, "{ibb}", changetypes, changesonly, return_echg_ctls ); 113 if ( tag == LBER_ERROR ) { 114 goto error_return; 115 } 116 117 if ( ber_flatten2( ber, value, 1 ) == -1 ) { 118 ld->ld_errno = LDAP_NO_MEMORY; 119 } 120 121 if ( 0 ) { 122error_return:; 123 ld->ld_errno = LDAP_ENCODING_ERROR; 124 } 125 126 if ( ber != NULL ) { 127 ber_free( ber, 1 ); 128 } 129 130 return ld->ld_errno; 131} 132 133 134/* --------------------------------------------------------------------------- 135 ldap_create_persistentsearch_control 136 137 Create and encode the persistent search control. 138 139 ld (IN) An LDAP session handle, as obtained from a call to 140 ldap_init(). 141 142 changetypes (IN) A bit-sensitive field that indicates which kinds of 143 changes the client wants to be informed about. Its 144 value should be LDAP_CHANGETYPE_ANY, or any logical-OR 145 combination of LDAP_CHANGETYPE_ADD, 146 LDAP_CHANGETYPE_DELETE, LDAP_CHANGETYPE_MODIFY, and 147 LDAP_CHANGETYPE_MODDN. This field corresponds to the 148 changeType element of the BER-encoded PersistentSearch 149 control value itself. 150 151 changesonly (IN) A Boolean field that indicates whether the client 152 wishes to only receive searchResultEntry messages for 153 entries that have been changed. If non-zero, only 154 entries that result from changes are returned; other- 155 wise, all of the static entries that match the search 156 criteria are returned before the server begins change 157 notification. This field corresponds to the changes- 158 Only element of the BER-encoded PersistentSearch con- 159 trol value itself. 160 161 return_echg_ctls (IN) A Boolean field that indicates whether the server 162 should send back an Entry Change Notification control 163 with each searchResultEntry that is returned due to a 164 change to an entry. If non-zero, Entry Change 165 Notification controls are requested; if zero, they are 166 not. This field corresponds to the returnECs element 167 of the BER-encoded PersistentSearch control value 168 itself. 169 170 isCritical (IN) 0 - Indicates the control is not critical to the operation. 171 non-zero - The control is critical to the operation. 172 173 ctrlp (OUT) Returns a pointer to the LDAPControl created. This control 174 SHOULD be freed by calling ldap_control_free() when done. 175 176 ---------------------------------------------------------------------------*/ 177 178int 179ldap_create_persistentsearch_control( 180 LDAP *ld, 181 int changetypes, 182 int changesonly, 183 int return_echg_ctls, 184 int isCritical, 185 LDAPControl **ctrlp ) 186{ 187 struct berval value; 188 189 assert( ld != NULL ); 190 assert( LDAP_VALID( ld ) ); 191 192 if ( ld == NULL ) { 193 return LDAP_PARAM_ERROR; 194 } 195 196 if ( ctrlp == NULL ) { 197 ld->ld_errno = LDAP_PARAM_ERROR; 198 return ld->ld_errno; 199 } 200 201 ld->ld_errno = ldap_create_persistentsearch_control_value( ld, changetypes, changesonly, return_echg_ctls, &value ); 202 if ( ld->ld_errno == LDAP_SUCCESS ) { 203 ld->ld_errno = ldap_control_create( LDAP_CONTROL_PERSIST_REQUEST, 204 isCritical, &value, 0, ctrlp ); 205 if ( ld->ld_errno != LDAP_SUCCESS ) { 206 LDAP_FREE( value.bv_val ); 207 } 208 } 209 210 return ld->ld_errno; 211} 212 213 214/* --------------------------------------------------------------------------- 215 ldap_parse_entrychange_control 216 217 Decode the entry change notification control return information. 218 219 ld (IN) An LDAP session handle, as obtained from a call to 220 ldap_init(). 221 222 ctrl (IN) The address of the LDAP Control Structure. 223 224 chgtypep (OUT) This result parameter is filled in with one of the 225 following values to indicate the type of change that was 226 made that caused the entry to be returned: 227 LDAP_CONTROL_PERSIST_ENTRY_CHANGE_ADD (1), 228 LDAP_CONTROL_PERSIST_ENTRY_CHANGE_DELETE (2), 229 LDAP_CONTROL_PERSIST_ENTRY_CHANGE_MODIFY (4), or 230 LDAP_CONTROL_PERSIST_ENTRY_CHANGE_RENAME (8). 231 If this parameter is NULL, the change type information 232 is not returned. 233 234 prevdnp (OUT) This result parameter points to the DN the 235 entry had before it was renamed and/or moved by a 236 modifyDN operation. It is set to NULL for other types 237 of changes. If this parameter is NULL, the previous DN 238 information is not returned. The returned value is a 239 pointer to the contents of the control; it is not a 240 copy of the data. 241 242 chgnumpresentp (OUT) This result parameter is filled in with a non-zero 243 value if a change number was returned in the control 244 (the change number is optional and servers MAY choose 245 not to return it). If this parameter is NULL, no indication 246 of whether the change number was present is returned. 247 248 chgnump (OUT) This result parameter is filled in with the change number 249 if one was returned in the control. If this parameter 250 is NULL, the change number is not returned. 251 252 ---------------------------------------------------------------------------*/ 253 254int 255ldap_parse_entrychange_control( 256 LDAP *ld, 257 LDAPControl *ctrl, 258 int *chgtypep, 259 struct berval *prevdnp, 260 int *chgnumpresentp, 261 long *chgnump ) 262{ 263 BerElement *ber; 264 ber_tag_t tag, berTag; 265 ber_len_t berLen; 266 ber_int_t chgtype; 267 268 assert( ld != NULL ); 269 assert( LDAP_VALID( ld ) ); 270 assert( ctrl != NULL ); 271 272 if (ld == NULL) { 273 return LDAP_PARAM_ERROR; 274 } 275 276 if (ctrl == NULL) { 277 ld->ld_errno = LDAP_PARAM_ERROR; 278 return(ld->ld_errno); 279 } 280 281 if ( !ctrl->ldctl_value.bv_val ) { 282 ld->ld_errno = LDAP_DECODING_ERROR; 283 return(ld->ld_errno); 284 } 285 286 /* Create a BerElement from the berval returned in the control. */ 287 ber = ber_init(&ctrl->ldctl_value); 288 289 if (ber == NULL) { 290 ld->ld_errno = LDAP_NO_MEMORY; 291 return(ld->ld_errno); 292 } 293 294 if ( prevdnp != NULL ) { 295 BER_BVZERO( prevdnp ); 296 } 297 if ( chgnumpresentp != NULL ) 298 *chgnumpresentp = 0; 299 if ( chgnump != NULL ) 300 *chgnump = 0; 301 302 /* Extract the change type from the control. */ 303 tag = ber_scanf(ber, "{e" /*}*/, &chgtype); 304 305 if( tag != LBER_ENUMERATED ) { 306 ber_free(ber, 1); 307 ld->ld_errno = LDAP_DECODING_ERROR; 308 return(ld->ld_errno); 309 } 310 if ( chgtypep != NULL ) 311 *chgtypep = chgtype; 312 313 tag = ber_peek_tag( ber, &berLen ); 314 if ( berLen ) { 315 if (tag == LBER_OCTETSTRING) { 316 if (prevdnp != NULL) { 317 tag = ber_get_stringbv( ber, prevdnp, 0 ); 318 } else { 319 struct berval bv; 320 tag = ber_skip_element( ber, &bv ); 321 } 322 if ( tag == LBER_ERROR ) { 323 ber_free(ber, 1); 324 ld->ld_errno = LDAP_DECODING_ERROR; 325 return(ld->ld_errno); 326 } 327 tag = ber_peek_tag( ber, &berLen ); 328 } 329 330 if ( chgnumpresentp != NULL || chgnump != NULL ) { 331 ber_int_t chgnum = 0; 332 int present = 0; 333 if (tag == LBER_INTEGER) { 334 present = 1; 335 tag = ber_get_int( ber, &chgnum ); 336 if ( tag == LBER_ERROR ) { 337 ber_free(ber, 1); 338 ld->ld_errno = LDAP_DECODING_ERROR; 339 return(ld->ld_errno); 340 } 341 if ( chgnumpresentp != NULL ) 342 *chgnumpresentp = present; 343 if ( chgnump != NULL ) 344 *chgnump = chgnum; 345 } 346 } 347 } 348 349 ber_free(ber,1); 350 351 ld->ld_errno = LDAP_SUCCESS; 352 return(ld->ld_errno); 353} 354