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