1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15 16#include "portable.h" 17 18#include <stdio.h> 19#include <ac/stdlib.h> 20 21#include <ac/socket.h> 22#include <ac/string.h> 23#include <ac/time.h> 24 25#include "ldap-int.h" 26#include "ldap_log.h" 27 28/* 29 * LDAPv3 Extended Operation Request 30 * ExtendedRequest ::= [APPLICATION 23] SEQUENCE { 31 * requestName [0] LDAPOID, 32 * requestValue [1] OCTET STRING OPTIONAL 33 * } 34 * 35 * LDAPv3 Extended Operation Response 36 * ExtendedResponse ::= [APPLICATION 24] SEQUENCE { 37 * COMPONENTS OF LDAPResult, 38 * responseName [10] LDAPOID OPTIONAL, 39 * response [11] OCTET STRING OPTIONAL 40 * } 41 * 42 * (Source RFC 4511) 43 */ 44 45int 46ldap_extended_operation( 47 LDAP *ld, 48 LDAP_CONST char *reqoid, 49 struct berval *reqdata, 50 LDAPControl **sctrls, 51 LDAPControl **cctrls, 52 int *msgidp ) 53{ 54 BerElement *ber; 55 int rc; 56 ber_int_t id; 57 58 Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 ); 59 60 assert( ld != NULL ); 61 assert( LDAP_VALID( ld ) ); 62 assert( reqoid != NULL && *reqoid != '\0' ); 63 assert( msgidp != NULL ); 64 65 /* must be version 3 (or greater) */ 66 if ( ld->ld_version < LDAP_VERSION3 ) { 67 ld->ld_errno = LDAP_NOT_SUPPORTED; 68 return( ld->ld_errno ); 69 } 70 71 /* create a message to send */ 72 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { 73 ld->ld_errno = LDAP_NO_MEMORY; 74 return( ld->ld_errno ); 75 } 76 77 LDAP_NEXT_MSGID( ld, id ); 78 if ( reqdata != NULL ) { 79 rc = ber_printf( ber, "{it{tstON}", /* '}' */ 80 id, LDAP_REQ_EXTENDED, 81 LDAP_TAG_EXOP_REQ_OID, reqoid, 82 LDAP_TAG_EXOP_REQ_VALUE, reqdata ); 83 84 } else { 85 rc = ber_printf( ber, "{it{tsN}", /* '}' */ 86 id, LDAP_REQ_EXTENDED, 87 LDAP_TAG_EXOP_REQ_OID, reqoid ); 88 } 89 90 if( rc == -1 ) { 91 ld->ld_errno = LDAP_ENCODING_ERROR; 92 ber_free( ber, 1 ); 93 return( ld->ld_errno ); 94 } 95 96 /* Put Server Controls */ 97 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { 98 ber_free( ber, 1 ); 99 return ld->ld_errno; 100 } 101 102 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { 103 ld->ld_errno = LDAP_ENCODING_ERROR; 104 ber_free( ber, 1 ); 105 return( ld->ld_errno ); 106 } 107 108 /* send the message */ 109 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber, id ); 110 111 return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS ); 112} 113 114int 115ldap_extended_operation_s( 116 LDAP *ld, 117 LDAP_CONST char *reqoid, 118 struct berval *reqdata, 119 LDAPControl **sctrls, 120 LDAPControl **cctrls, 121 char **retoidp, 122 struct berval **retdatap ) 123{ 124 int rc; 125 int msgid; 126 LDAPMessage *res; 127 128 Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 ); 129 130 assert( ld != NULL ); 131 assert( LDAP_VALID( ld ) ); 132 assert( reqoid != NULL && *reqoid != '\0' ); 133 134 rc = ldap_extended_operation( ld, reqoid, reqdata, 135 sctrls, cctrls, &msgid ); 136 137 if ( rc != LDAP_SUCCESS ) { 138 return( rc ); 139 } 140 141 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) { 142 return( ld->ld_errno ); 143 } 144 145 if ( retoidp != NULL ) *retoidp = NULL; 146 if ( retdatap != NULL ) *retdatap = NULL; 147 148 rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 ); 149 150 if( rc != LDAP_SUCCESS ) { 151 ldap_msgfree( res ); 152 return rc; 153 } 154 155 return( ldap_result2error( ld, res, 1 ) ); 156} 157 158/* Parse an extended result */ 159int 160ldap_parse_extended_result ( 161 LDAP *ld, 162 LDAPMessage *res, 163 char **retoidp, 164 struct berval **retdatap, 165 int freeit ) 166{ 167 BerElement *ber; 168 ber_tag_t rc; 169 ber_tag_t tag; 170 ber_len_t len; 171 struct berval *resdata; 172 ber_int_t errcode; 173 char *resoid; 174 175 assert( ld != NULL ); 176 assert( LDAP_VALID( ld ) ); 177 assert( res != NULL ); 178 179 Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 ); 180 181 if( ld->ld_version < LDAP_VERSION3 ) { 182 ld->ld_errno = LDAP_NOT_SUPPORTED; 183 return ld->ld_errno; 184 } 185 186 if( res->lm_msgtype != LDAP_RES_EXTENDED ) { 187 ld->ld_errno = LDAP_PARAM_ERROR; 188 return ld->ld_errno; 189 } 190 191 if( retoidp != NULL ) *retoidp = NULL; 192 if( retdatap != NULL ) *retdatap = NULL; 193 194 if ( ld->ld_error ) { 195 LDAP_FREE( ld->ld_error ); 196 ld->ld_error = NULL; 197 } 198 199 if ( ld->ld_matched ) { 200 LDAP_FREE( ld->ld_matched ); 201 ld->ld_matched = NULL; 202 } 203 204 ber = ber_dup( res->lm_ber ); 205 206 if ( ber == NULL ) { 207 ld->ld_errno = LDAP_NO_MEMORY; 208 return ld->ld_errno; 209 } 210 211 rc = ber_scanf( ber, "{eAA" /*}*/, &errcode, 212 &ld->ld_matched, &ld->ld_error ); 213 214 if( rc == LBER_ERROR ) { 215 ld->ld_errno = LDAP_DECODING_ERROR; 216 ber_free( ber, 0 ); 217 return ld->ld_errno; 218 } 219 220 resoid = NULL; 221 resdata = NULL; 222 223 tag = ber_peek_tag( ber, &len ); 224 225 if( tag == LDAP_TAG_REFERRAL ) { 226 /* skip over referral */ 227 if( ber_scanf( ber, "x" ) == LBER_ERROR ) { 228 ld->ld_errno = LDAP_DECODING_ERROR; 229 ber_free( ber, 0 ); 230 return ld->ld_errno; 231 } 232 233 tag = ber_peek_tag( ber, &len ); 234 } 235 236 if( tag == LDAP_TAG_EXOP_RES_OID ) { 237 /* we have a resoid */ 238 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) { 239 ld->ld_errno = LDAP_DECODING_ERROR; 240 ber_free( ber, 0 ); 241 return ld->ld_errno; 242 } 243 244 assert( resoid[ 0 ] != '\0' ); 245 246 tag = ber_peek_tag( ber, &len ); 247 } 248 249 if( tag == LDAP_TAG_EXOP_RES_VALUE ) { 250 /* we have a resdata */ 251 if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) { 252 ld->ld_errno = LDAP_DECODING_ERROR; 253 ber_free( ber, 0 ); 254 if( resoid != NULL ) LDAP_FREE( resoid ); 255 return ld->ld_errno; 256 } 257 } 258 259 ber_free( ber, 0 ); 260 261 if( retoidp != NULL ) { 262 *retoidp = resoid; 263 } else { 264 LDAP_FREE( resoid ); 265 } 266 267 if( retdatap != NULL ) { 268 *retdatap = resdata; 269 } else { 270 ber_bvfree( resdata ); 271 } 272 273 ld->ld_errno = errcode; 274 275 if( freeit ) { 276 ldap_msgfree( res ); 277 } 278 279 return LDAP_SUCCESS; 280} 281 282 283/* Parse an extended partial */ 284int 285ldap_parse_intermediate ( 286 LDAP *ld, 287 LDAPMessage *res, 288 char **retoidp, 289 struct berval **retdatap, 290 LDAPControl ***serverctrls, 291 int freeit ) 292{ 293 BerElement *ber; 294 ber_tag_t tag; 295 ber_len_t len; 296 struct berval *resdata; 297 char *resoid; 298 299 assert( ld != NULL ); 300 assert( LDAP_VALID( ld ) ); 301 assert( res != NULL ); 302 303 Debug( LDAP_DEBUG_TRACE, "ldap_parse_intermediate\n", 0, 0, 0 ); 304 305 if( ld->ld_version < LDAP_VERSION3 ) { 306 ld->ld_errno = LDAP_NOT_SUPPORTED; 307 return ld->ld_errno; 308 } 309 310 if( res->lm_msgtype != LDAP_RES_INTERMEDIATE ) { 311 ld->ld_errno = LDAP_PARAM_ERROR; 312 return ld->ld_errno; 313 } 314 315 if( retoidp != NULL ) *retoidp = NULL; 316 if( retdatap != NULL ) *retdatap = NULL; 317 if( serverctrls != NULL ) *serverctrls = NULL; 318 319 ber = ber_dup( res->lm_ber ); 320 321 if ( ber == NULL ) { 322 ld->ld_errno = LDAP_NO_MEMORY; 323 return ld->ld_errno; 324 } 325 326 tag = ber_scanf( ber, "{" /*}*/ ); 327 328 if( tag == LBER_ERROR ) { 329 ld->ld_errno = LDAP_DECODING_ERROR; 330 ber_free( ber, 0 ); 331 return ld->ld_errno; 332 } 333 334 resoid = NULL; 335 resdata = NULL; 336 337 tag = ber_peek_tag( ber, &len ); 338 339 /* 340 * NOTE: accept intermediate and extended response tag values 341 * as older versions of slapd(8) incorrectly used extended 342 * response tags. 343 * Should be removed when 2.2 is moved to Historic. 344 */ 345 if( tag == LDAP_TAG_IM_RES_OID || tag == LDAP_TAG_EXOP_RES_OID ) { 346 /* we have a resoid */ 347 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) { 348 ld->ld_errno = LDAP_DECODING_ERROR; 349 ber_free( ber, 0 ); 350 return ld->ld_errno; 351 } 352 353 assert( resoid[ 0 ] != '\0' ); 354 355 tag = ber_peek_tag( ber, &len ); 356 } 357 358 if( tag == LDAP_TAG_IM_RES_VALUE || tag == LDAP_TAG_EXOP_RES_VALUE ) { 359 /* we have a resdata */ 360 if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) { 361 ld->ld_errno = LDAP_DECODING_ERROR; 362 ber_free( ber, 0 ); 363 if( resoid != NULL ) LDAP_FREE( resoid ); 364 return ld->ld_errno; 365 } 366 } 367 368 if ( serverctrls == NULL ) { 369 ld->ld_errno = LDAP_SUCCESS; 370 goto free_and_return; 371 } 372 373 if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) { 374 ld->ld_errno = LDAP_DECODING_ERROR; 375 goto free_and_return; 376 } 377 378 ld->ld_errno = ldap_pvt_get_controls( ber, serverctrls ); 379 380free_and_return: 381 ber_free( ber, 0 ); 382 383 if( retoidp != NULL ) { 384 *retoidp = resoid; 385 } else { 386 LDAP_FREE( resoid ); 387 } 388 389 if( retdatap != NULL ) { 390 *retdatap = resdata; 391 } else { 392 ber_bvfree( resdata ); 393 } 394 395 if( freeit ) { 396 ldap_msgfree( res ); 397 } 398 399 return ld->ld_errno; 400} 401 402