1 /* $NetBSD: deref.c,v 1.2 2020/08/11 13:15:37 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2020 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.2 2020/08/11 13:15:37 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 dvp = &dr->attrVals; 200 201 tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal ); 202 if ( tag == LBER_ERROR ) { 203 goto done; 204 } 205 206 tag = ber_peek_tag( ber, &len ); 207 if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) { 208 for ( tag = ber_first_element( ber, &len, &last2 ); 209 tag != LBER_DEFAULT; 210 tag = ber_next_element( ber, &len, last2 ) ) 211 { 212 LDAPDerefVal *dv; 213 214 dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) ); 215 216 tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals ); 217 if ( tag == LBER_ERROR ) { 218 goto done; 219 } 220 221 *dvp = dv; 222 dvp = &dv->next; 223 } 224 } 225 226 tag = ber_scanf( ber, "}" ); 227 if ( tag == LBER_ERROR ) { 228 goto done; 229 } 230 231 *drp = dr; 232 drp = &dr->next; 233 } 234 235 tag = 0; 236 237 done:; 238 ber_free( ber, 1 ); 239 240 if ( tag == LBER_ERROR ) { 241 if ( drhead != NULL ) { 242 ldap_derefresponse_free( drhead ); 243 } 244 245 *drp2 = NULL; 246 ld->ld_errno = LDAP_DECODING_ERROR; 247 248 } else { 249 *drp2 = drhead; 250 ld->ld_errno = LDAP_SUCCESS; 251 } 252 253 return ld->ld_errno; 254 } 255 256 int 257 ldap_parse_deref_control( 258 LDAP *ld, 259 LDAPControl **ctrls, 260 LDAPDerefRes **drp ) 261 { 262 LDAPControl *c; 263 264 if ( drp == NULL ) { 265 ld->ld_errno = LDAP_PARAM_ERROR; 266 return ld->ld_errno; 267 } 268 269 *drp = NULL; 270 271 if ( ctrls == NULL ) { 272 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 273 return ld->ld_errno; 274 } 275 276 c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL ); 277 if ( c == NULL ) { 278 /* No deref control was found. */ 279 ld->ld_errno = LDAP_CONTROL_NOT_FOUND; 280 return ld->ld_errno; 281 } 282 283 ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp ); 284 285 return ld->ld_errno; 286 } 287 288