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