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