1 /* $NetBSD: deref.c,v 1.3 2021/08/14 16:14:55 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 * 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.3 2021/08/14 16:14:55 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 BerElement *ber; 169 ber_tag_t tag; 170 ber_len_t len; 171 char *last; 172 LDAPDerefRes *drhead = NULL, **drp; 173 174 if ( ld == NULL || ctrl == NULL || drp2 == NULL ) { 175 if ( ld ) 176 ld->ld_errno = LDAP_PARAM_ERROR; 177 return LDAP_PARAM_ERROR; 178 } 179 180 /* Create a BerElement from the berval returned in the control. */ 181 ber = ber_init( &ctrl->ldctl_value ); 182 183 if ( ber == NULL ) { 184 ld->ld_errno = LDAP_NO_MEMORY; 185 return ld->ld_errno; 186 } 187 188 /* Extract the count and cookie from the control. */ 189 drp = &drhead; 190 for ( tag = ber_first_element( ber, &len, &last ); 191 tag != LBER_DEFAULT; 192 tag = ber_next_element( ber, &len, last ) ) 193 { 194 LDAPDerefRes *dr; 195 LDAPDerefVal **dvp; 196 char *last2; 197 198 dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) ); 199 if ( dr == NULL ) { 200 ldap_derefresponse_free( drhead ); 201 *drp2 = NULL; 202 ld->ld_errno = LDAP_NO_MEMORY; 203 return ld->ld_errno; 204 } 205 dvp = &dr->attrVals; 206 207 tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal ); 208 if ( tag == LBER_ERROR ) { 209 goto done; 210 } 211 212 tag = ber_peek_tag( ber, &len ); 213 if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) { 214 for ( tag = ber_first_element( ber, &len, &last2 ); 215 tag != LBER_DEFAULT; 216 tag = ber_next_element( ber, &len, last2 ) ) 217 { 218 LDAPDerefVal *dv; 219 220 dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) ); 221 if ( dv == NULL ) { 222 ldap_derefresponse_free( drhead ); 223 LDAP_FREE( dr ); 224 *drp2 = NULL; 225 ld->ld_errno = LDAP_NO_MEMORY; 226 return ld->ld_errno; 227 } 228 229 tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals ); 230 if ( tag == LBER_ERROR ) { 231 goto done; 232 } 233 234 *dvp = dv; 235 dvp = &dv->next; 236 } 237 } 238 239 tag = ber_scanf( ber, "}" ); 240 if ( tag == LBER_ERROR ) { 241 goto done; 242 } 243 244 *drp = dr; 245 drp = &dr->next; 246 } 247 248 tag = 0; 249 250 done:; 251 ber_free( ber, 1 ); 252 253 if ( tag == LBER_ERROR ) { 254 if ( drhead != NULL ) { 255 ldap_derefresponse_free( drhead ); 256 } 257 258 *drp2 = NULL; 259 ld->ld_errno = LDAP_DECODING_ERROR; 260 261 } else { 262 *drp2 = drhead; 263 ld->ld_errno = LDAP_SUCCESS; 264 } 265 266 return ld->ld_errno; 267 } 268 269 int 270 ldap_parse_deref_control( 271 LDAP *ld, 272 LDAPControl **ctrls, 273 LDAPDerefRes **drp ) 274 { 275 LDAPControl *c; 276 277 if ( drp == NULL ) { 278 ld->ld_errno = LDAP_PARAM_ERROR; 279 return ld->ld_errno; 280 } 281 282 *drp = NULL; 283 284 if ( ctrls == NULL ) { 285 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 286 return ld->ld_errno; 287 } 288 289 c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL ); 290 if ( c == NULL ) { 291 /* No deref control was found. */ 292 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 293 return ld->ld_errno; 294 } 295 296 ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp ); 297 298 return ld->ld_errno; 299 } 300 301