1 /* $NetBSD: deref.c,v 1.4 2025/09/05 21:16:21 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2024 The OpenLDAP Foundation. 7 * Portions Copyright 2008 Pierangelo Masarati. 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 /* ACKNOWLEDGEMENTS: 19 * This work was initially developed by Pierangelo Masarati 20 * for inclusion in OpenLDAP Software. 21 */ 22 23 #include <sys/cdefs.h> 24 __RCSID("$NetBSD: deref.c,v 1.4 2025/09/05 21:16:21 christos Exp $"); 25 26 #include "portable.h" 27 28 #include <stdio.h> 29 #include <ac/stdlib.h> 30 #include <ac/string.h> 31 #include <ac/time.h> 32 33 #include "ldap-int.h" 34 35 int 36 ldap_create_deref_control_value( 37 LDAP *ld, 38 LDAPDerefSpec *ds, 39 struct berval *value ) 40 { 41 BerElement *ber = NULL; 42 ber_tag_t tag; 43 int i; 44 45 if ( ld == NULL || value == NULL || ds == NULL ) 46 { 47 if ( ld ) 48 ld->ld_errno = LDAP_PARAM_ERROR; 49 return LDAP_PARAM_ERROR; 50 } 51 52 assert( LDAP_VALID( ld ) ); 53 54 value->bv_val = NULL; 55 value->bv_len = 0; 56 ld->ld_errno = LDAP_SUCCESS; 57 58 ber = ldap_alloc_ber_with_options( ld ); 59 if ( ber == NULL ) { 60 ld->ld_errno = LDAP_NO_MEMORY; 61 return ld->ld_errno; 62 } 63 64 tag = ber_printf( ber, "{" /*}*/ ); 65 if ( tag == LBER_ERROR ) { 66 ld->ld_errno = LDAP_ENCODING_ERROR; 67 goto done; 68 } 69 70 for ( i = 0; ds[i].derefAttr != NULL; i++ ) { 71 int j; 72 73 tag = ber_printf( ber, "{s{" /*}}*/ , ds[i].derefAttr ); 74 if ( tag == LBER_ERROR ) { 75 ld->ld_errno = LDAP_ENCODING_ERROR; 76 goto done; 77 } 78 79 for ( j = 0; ds[i].attributes[j] != NULL; j++ ) { 80 tag = ber_printf( ber, "s", ds[i].attributes[ j ] ); 81 if ( tag == LBER_ERROR ) { 82 ld->ld_errno = LDAP_ENCODING_ERROR; 83 goto done; 84 } 85 } 86 87 tag = ber_printf( ber, /*{{*/ "}N}" ); 88 if ( tag == LBER_ERROR ) { 89 ld->ld_errno = LDAP_ENCODING_ERROR; 90 goto done; 91 } 92 } 93 94 tag = ber_printf( ber, /*{*/ "}" ); 95 if ( tag == LBER_ERROR ) { 96 ld->ld_errno = LDAP_ENCODING_ERROR; 97 goto done; 98 } 99 100 if ( ber_flatten2( ber, value, 1 ) == -1 ) { 101 ld->ld_errno = LDAP_NO_MEMORY; 102 } 103 104 done:; 105 if ( ber != NULL ) { 106 ber_free( ber, 1 ); 107 } 108 109 return ld->ld_errno; 110 } 111 112 int 113 ldap_create_deref_control( 114 LDAP *ld, 115 LDAPDerefSpec *ds, 116 int iscritical, 117 LDAPControl **ctrlp ) 118 { 119 struct berval value; 120 121 if ( ctrlp == NULL ) { 122 ld->ld_errno = LDAP_PARAM_ERROR; 123 return ld->ld_errno; 124 } 125 126 ld->ld_errno = ldap_create_deref_control_value( ld, ds, &value ); 127 if ( ld->ld_errno == LDAP_SUCCESS ) { 128 ld->ld_errno = ldap_control_create( LDAP_CONTROL_X_DEREF, 129 iscritical, &value, 0, ctrlp ); 130 if ( ld->ld_errno != LDAP_SUCCESS ) { 131 LDAP_FREE( value.bv_val ); 132 } 133 } 134 135 return ld->ld_errno; 136 } 137 138 void 139 ldap_derefresponse_free( LDAPDerefRes *dr ) 140 { 141 for ( ; dr; ) { 142 LDAPDerefRes *drnext = dr->next; 143 LDAPDerefVal *dv; 144 145 LDAP_FREE( dr->derefAttr ); 146 LDAP_FREE( dr->derefVal.bv_val ); 147 148 for ( dv = dr->attrVals; dv; ) { 149 LDAPDerefVal *dvnext = dv->next; 150 LDAP_FREE( dv->type ); 151 ber_bvarray_free( dv->vals ); 152 LDAP_FREE( dv ); 153 dv = dvnext; 154 } 155 156 LDAP_FREE( dr ); 157 158 dr = drnext; 159 } 160 } 161 162 int 163 ldap_parse_derefresponse_control( 164 LDAP *ld, 165 LDAPControl *ctrl, 166 LDAPDerefRes **drp2 ) 167 { 168 BerElementBuffer berbuf; 169 BerElement *ber = (BerElement *)&berbuf; 170 ber_tag_t tag; 171 ber_len_t len; 172 char *last; 173 LDAPDerefRes *drhead = NULL, **drp; 174 175 if ( ld == NULL || ctrl == NULL || drp2 == NULL ) { 176 if ( ld ) 177 ld->ld_errno = LDAP_PARAM_ERROR; 178 return LDAP_PARAM_ERROR; 179 } 180 181 /* Set up a BerElement from the berval returned in the control. */ 182 ber_init2( ber, &ctrl->ldctl_value, 0 ); 183 184 /* Extract the count and cookie from the control. */ 185 drp = &drhead; 186 for ( tag = ber_first_element( ber, &len, &last ); 187 tag != LBER_DEFAULT; 188 tag = ber_next_element( ber, &len, last ) ) 189 { 190 LDAPDerefRes *dr; 191 LDAPDerefVal **dvp; 192 char *last2; 193 194 dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) ); 195 if ( dr == NULL ) { 196 ldap_derefresponse_free( drhead ); 197 *drp2 = NULL; 198 ld->ld_errno = LDAP_NO_MEMORY; 199 return ld->ld_errno; 200 } 201 dvp = &dr->attrVals; 202 203 tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal ); 204 if ( tag == LBER_ERROR ) { 205 goto done; 206 } 207 208 tag = ber_peek_tag( ber, &len ); 209 if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) { 210 for ( tag = ber_first_element( ber, &len, &last2 ); 211 tag != LBER_DEFAULT; 212 tag = ber_next_element( ber, &len, last2 ) ) 213 { 214 LDAPDerefVal *dv; 215 216 dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) ); 217 if ( dv == NULL ) { 218 ldap_derefresponse_free( drhead ); 219 LDAP_FREE( dr ); 220 *drp2 = NULL; 221 ld->ld_errno = LDAP_NO_MEMORY; 222 return ld->ld_errno; 223 } 224 225 tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals ); 226 if ( tag == LBER_ERROR ) { 227 goto done; 228 } 229 230 *dvp = dv; 231 dvp = &dv->next; 232 } 233 } 234 235 tag = ber_scanf( ber, "}" ); 236 if ( tag == LBER_ERROR ) { 237 goto done; 238 } 239 240 *drp = dr; 241 drp = &dr->next; 242 } 243 244 tag = 0; 245 246 done:; 247 if ( tag == LBER_ERROR ) { 248 if ( drhead != NULL ) { 249 ldap_derefresponse_free( drhead ); 250 } 251 252 *drp2 = NULL; 253 ld->ld_errno = LDAP_DECODING_ERROR; 254 255 } else { 256 *drp2 = drhead; 257 ld->ld_errno = LDAP_SUCCESS; 258 } 259 260 return ld->ld_errno; 261 } 262 263 int 264 ldap_parse_deref_control( 265 LDAP *ld, 266 LDAPControl **ctrls, 267 LDAPDerefRes **drp ) 268 { 269 LDAPControl *c; 270 271 if ( drp == NULL ) { 272 ld->ld_errno = LDAP_PARAM_ERROR; 273 return ld->ld_errno; 274 } 275 276 *drp = NULL; 277 278 if ( ctrls == NULL ) { 279 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 280 return ld->ld_errno; 281 } 282 283 c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL ); 284 if ( c == NULL ) { 285 /* No deref control was found. */ 286 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 287 return ld->ld_errno; 288 } 289 290 ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp ); 291 292 return ld->ld_errno; 293 } 294 295