1 #pragma ident "%Z%%M% %I% %E% SMI" 2 3 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 4 * 5 * The contents of this file are subject to the Netscape Public License 6 * Version 1.0 (the "NPL"); you may not use this file except in 7 * compliance with the NPL. You may obtain a copy of the NPL at 8 * http://www.mozilla.org/NPL/ 9 * 10 * Software distributed under the NPL is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 12 * for the specific language governing rights and limitations under the 13 * NPL. 14 * 15 * The Initial Developer of this code under the NPL is Netscape 16 * Communications Corporation. Portions created by Netscape are 17 * Copyright (C) 1998 Netscape Communications Corporation. All Rights 18 * Reserved. 19 */ 20 /* control.c - routines to handle ldapv3 controls */ 21 22 #include "ldap-int.h" 23 24 static LDAPControl *ldap_control_dup( LDAPControl *ctrl ); 25 static int ldap_control_copy_contents( LDAPControl *ctrl_dst, 26 LDAPControl *ctrl_src ); 27 28 /* 29 * Append a list of LDAPv3 controls to ber. If ctrls is NULL, use default 30 * set of controls from ld. 31 * Return an LDAP error code (LDAP_SUCCESS if all goes well). 32 * If closeseq is non-zero, we do an extra ber_put_seq() as well. 33 */ 34 int 35 nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq, 36 BerElement *ber ) 37 { 38 LDAPControl *c; 39 int rc, i; 40 41 rc = LDAP_ENCODING_ERROR; /* the most popular error */ 42 43 /* if no controls were passed in, use global list from LDAP * */ 44 LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK ); 45 if ( ctrls == NULL ) { 46 ctrls = ld->ld_servercontrols; 47 } 48 49 /* if there are no controls then we are done */ 50 if ( ctrls == NULL || ctrls[ 0 ] == NULL ) { 51 goto clean_exit; 52 } 53 54 /* 55 * If we're using LDAPv2 or earlier we can't send any controls, so 56 * we just ignore them unless one is marked critical, in which case 57 * we return an error. 58 */ 59 if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) { 60 for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) { 61 if ( ctrls[i]->ldctl_iscritical ) { 62 rc = LDAP_NOT_SUPPORTED; 63 goto error_exit; 64 } 65 } 66 goto clean_exit; 67 } 68 69 /* 70 * encode the controls as a Sequence of Sequence 71 */ 72 if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) { 73 goto error_exit; 74 } 75 76 for ( i = 0; ctrls[i] != NULL; i++ ) { 77 c = ctrls[i]; 78 79 if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) { 80 goto error_exit; 81 } 82 83 /* criticality is "BOOLEAN DEFAULT FALSE" */ 84 /* therefore, it should only be encoded if it exists AND is TRUE */ 85 if ( c->ldctl_iscritical ) { 86 if ( ber_printf( ber, "b", (int)c->ldctl_iscritical ) 87 == -1 ) { 88 goto error_exit; 89 } 90 } 91 92 if ( c->ldctl_value.bv_val != NULL ) { 93 if ( ber_printf( ber, "o", c->ldctl_value.bv_val, 94 (int)c->ldctl_value.bv_len /* XXX lossy cast */ ) 95 == -1 ) { 96 goto error_exit; 97 } 98 } 99 100 if ( ber_put_seq( ber ) == -1 ) { 101 goto error_exit; 102 } 103 } 104 105 if ( ber_put_seq( ber ) == -1 ) { 106 goto error_exit; 107 } 108 109 clean_exit: 110 LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK ); 111 if ( closeseq && ber_put_seq( ber ) == -1 ) { 112 goto error_exit; 113 } 114 return( LDAP_SUCCESS ); 115 116 error_exit: 117 LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK ); 118 LDAP_SET_LDERRNO( ld, rc, NULL, NULL ); 119 return( rc ); 120 } 121 122 123 /* 124 * Pull controls out of "ber" (if any present) and return them in "controlsp." 125 * Returns an LDAP error code. 126 */ 127 int 128 nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp ) 129 { 130 LDAPControl *newctrl; 131 ber_tag_t tag; 132 ber_len_t len; 133 int rc, maxcontrols, curcontrols; 134 char *last; 135 136 /* 137 * Each LDAPMessage can have a set of controls appended 138 * to it. Controls are used to extend the functionality 139 * of an LDAP operation (e.g., add an attribute size limit 140 * to the search operation). These controls look like this: 141 * 142 * Controls ::= SEQUENCE OF Control 143 * 144 * Control ::= SEQUENCE { 145 * controlType LDAPOID, 146 * criticality BOOLEAN DEFAULT FALSE, 147 * controlValue OCTET STRING 148 * } 149 */ 150 LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 ); 151 152 *controlsp = NULL; 153 154 /* 155 * check to see if controls were included 156 */ 157 if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) { 158 return( LDAP_DECODING_ERROR ); /* unexpected error */ 159 } 160 if ( len == 0 ) { 161 LDAPDebug( LDAP_DEBUG_TRACE, 162 "<= nsldapi_get_controls no controls\n", 0, 0, 0 ); 163 return( LDAP_SUCCESS ); /* no controls */ 164 } 165 if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) { 166 if ( tag == LBER_ERROR ) { 167 LDAPDebug( LDAP_DEBUG_TRACE, 168 "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n", 169 0, 0, 0 ); 170 return( LDAP_DECODING_ERROR ); /* decoding error */ 171 } 172 /* 173 * We found something other than controls. This should never 174 * happen in LDAPv3, but we don't treat this is a hard error -- 175 * we just ignore the extra stuff. 176 */ 177 LDAPDebug( LDAP_DEBUG_TRACE, 178 "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n", 179 tag, 0, 0 ); 180 return( LDAP_SUCCESS ); 181 } 182 183 maxcontrols = curcontrols = 0; 184 for ( tag = ber_first_element( ber, &len, &last ); 185 tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET; 186 tag = ber_next_element( ber, &len, last ) ) { 187 if ( curcontrols >= maxcontrols - 1 ) { 188 #define CONTROL_GRABSIZE 5 189 maxcontrols += CONTROL_GRABSIZE; 190 *controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC( 191 (char *)*controlsp, maxcontrols * 192 sizeof(struct ldapcontrol *) ); 193 if ( *controlsp == NULL ) { 194 rc = LDAP_NO_MEMORY; 195 goto free_and_return; 196 } 197 } 198 if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1, 199 sizeof(LDAPControl))) == NULL ) { 200 rc = LDAP_NO_MEMORY; 201 goto free_and_return; 202 } 203 204 (*controlsp)[curcontrols++] = newctrl; 205 (*controlsp)[curcontrols] = NULL; 206 207 if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid ) 208 == LBER_ERROR ) { 209 rc = LDAP_DECODING_ERROR; 210 goto free_and_return; 211 } 212 213 /* the criticality is optional */ 214 if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) { 215 int aint; 216 217 if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) { 218 rc = LDAP_DECODING_ERROR; 219 goto free_and_return; 220 } 221 newctrl->ldctl_iscritical = (char)aint; /* XXX lossy cast */ 222 } else { 223 /* absent is synonomous with FALSE */ 224 newctrl->ldctl_iscritical = 0; 225 } 226 227 /* the control value is optional */ 228 if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) { 229 if ( ber_scanf( ber, "o", &newctrl->ldctl_value ) 230 == LBER_ERROR ) { 231 rc = LDAP_DECODING_ERROR; 232 goto free_and_return; 233 } 234 } else { 235 (newctrl->ldctl_value).bv_val = NULL; 236 (newctrl->ldctl_value).bv_len = 0; 237 } 238 239 } 240 241 if ( tag == LBER_ERROR ) { 242 rc = LDAP_DECODING_ERROR; 243 goto free_and_return; 244 } 245 246 LDAPDebug( LDAP_DEBUG_TRACE, 247 "<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 ); 248 return( LDAP_SUCCESS ); 249 250 free_and_return:; 251 ldap_controls_free( *controlsp ); 252 *controlsp = NULL; 253 LDAPDebug( LDAP_DEBUG_TRACE, 254 "<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 ); 255 return( rc ); 256 } 257 258 259 void 260 LDAP_CALL 261 ldap_control_free( LDAPControl *ctrl ) 262 { 263 if ( ctrl != NULL ) { 264 if ( ctrl->ldctl_oid != NULL ) { 265 NSLDAPI_FREE( ctrl->ldctl_oid ); 266 } 267 if ( ctrl->ldctl_value.bv_val != NULL ) { 268 NSLDAPI_FREE( ctrl->ldctl_value.bv_val ); 269 } 270 NSLDAPI_FREE( (char *)ctrl ); 271 } 272 } 273 274 275 void 276 LDAP_CALL 277 ldap_controls_free( LDAPControl **ctrls ) 278 { 279 int i; 280 281 if ( ctrls != NULL ) { 282 for ( i = 0; ctrls[i] != NULL; i++ ) { 283 ldap_control_free( ctrls[i] ); 284 } 285 NSLDAPI_FREE( (char *)ctrls ); 286 } 287 } 288 289 290 291 #if 0 292 LDAPControl ** 293 LDAP_CALL 294 ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl ) 295 { 296 int nctrls = 0; 297 LDAPControl **ctrlp; 298 int i; 299 300 if ( NULL == ctrl ) 301 return ( NULL ); 302 303 /* Count the existing controls */ 304 if ( NULL != ctrl_src ) { 305 while( NULL != ctrl_src[nctrls] ) { 306 nctrls++; 307 } 308 } 309 310 /* allocate the new control structure */ 311 if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *) 312 * (nctrls + 2) ) ) == NULL ) { 313 return( NULL ); 314 } 315 memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) ); 316 317 for( i = 0; i < (nctrls + 1); i++ ) { 318 if ( i < nctrls ) { 319 ctrlp[i] = ldap_control_dup( ctrl_src[i] ); 320 } else { 321 ctrlp[i] = ldap_control_dup( ctrl ); 322 } 323 if ( NULL == ctrlp[i] ) { 324 ldap_controls_free( ctrlp ); 325 return( NULL ); 326 } 327 } 328 return ctrlp; 329 } 330 #endif /* 0 */ 331 332 333 /* 334 * Replace *ldctrls with a copy of newctrls. 335 * returns 0 if successful. 336 * return -1 if not and set error code inside LDAP *ld. 337 */ 338 int 339 nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls ) 340 { 341 int count; 342 343 if ( *ldctrls != NULL ) { 344 ldap_controls_free( *ldctrls ); 345 } 346 347 if ( newctrls == NULL || newctrls[0] == NULL ) { 348 *ldctrls = NULL; 349 return( 0 ); 350 } 351 352 for ( count = 0; newctrls[ count ] != NULL; ++count ) { 353 ; 354 } 355 356 if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) * 357 sizeof( LDAPControl *))) == NULL ) { 358 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL ); 359 return( -1 ); 360 } 361 (*ldctrls)[ count ] = NULL; 362 363 for ( count = 0; newctrls[ count ] != NULL; ++count ) { 364 if (( (*ldctrls)[ count ] = 365 ldap_control_dup( newctrls[ count ] )) == NULL ) { 366 ldap_controls_free( *ldctrls ); 367 *ldctrls = NULL; 368 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL ); 369 return( -1 ); 370 } 371 } 372 373 return( 0 ); 374 } 375 376 377 /* 378 * return a malloc'd copy of "ctrl" (NULL if memory allocation fails) 379 */ 380 static LDAPControl * 381 /* LDAP_CALL */ /* keep this routine internal for now */ 382 ldap_control_dup( LDAPControl *ctrl ) 383 { 384 LDAPControl *rctrl; 385 386 if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl ))) 387 == NULL ) { 388 return( NULL ); 389 } 390 391 if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) { 392 NSLDAPI_FREE( rctrl ); 393 return( NULL ); 394 } 395 396 return( rctrl ); 397 } 398 399 400 /* 401 * duplicate the contents of "ctrl_src" and place in "ctrl_dst" 402 */ 403 static int 404 /* LDAP_CALL */ /* keep this routine internal for now */ 405 ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src ) 406 { 407 size_t len; 408 409 if ( NULL == ctrl_dst || NULL == ctrl_src ) { 410 return( LDAP_PARAM_ERROR ); 411 } 412 413 ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical; 414 415 /* fill in the fields of this new control */ 416 if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid )) 417 == NULL ) { 418 return( LDAP_NO_MEMORY ); 419 } 420 421 len = (size_t)(ctrl_src->ldctl_value).bv_len; 422 if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) { 423 ctrl_dst->ldctl_value.bv_len = 0; 424 ctrl_dst->ldctl_value.bv_val = NULL; 425 } else { 426 ctrl_dst->ldctl_value.bv_len = len; 427 if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len )) 428 == NULL ) { 429 NSLDAPI_FREE( ctrl_dst->ldctl_oid ); 430 return( LDAP_NO_MEMORY ); 431 } 432 SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val, 433 ctrl_src->ldctl_value.bv_val, len ); 434 } 435 436 return ( LDAP_SUCCESS ); 437 } 438 439 440 441 /* 442 * build an allocated LDAPv3 control. Returns an LDAP error code. 443 */ 444 int 445 nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical, 446 LDAPControl **ctrlp ) 447 { 448 int rc; 449 struct berval *bvp; 450 451 if ( ber == NULL ) { 452 bvp = NULL; 453 } else { 454 /* allocate struct berval with contents of the BER encoding */ 455 rc = ber_flatten( ber, &bvp ); 456 if ( freeber ) { 457 ber_free( ber, 1 ); 458 } 459 if ( rc == -1 ) { 460 return( LDAP_NO_MEMORY ); 461 } 462 } 463 464 /* allocate the new control structure */ 465 if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl))) 466 == NULL ) { 467 if ( bvp != NULL ) { 468 ber_bvfree( bvp ); 469 } 470 return( LDAP_NO_MEMORY ); 471 } 472 473 /* fill in the fields of this new control */ 474 (*ctrlp)->ldctl_iscritical = iscritical; 475 if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) { 476 NSLDAPI_FREE( *ctrlp ); 477 if ( bvp != NULL ) { 478 ber_bvfree( bvp ); 479 } 480 return( LDAP_NO_MEMORY ); 481 } 482 483 if ( bvp == NULL ) { 484 (*ctrlp)->ldctl_value.bv_len = 0; 485 (*ctrlp)->ldctl_value.bv_val = NULL; 486 } else { 487 (*ctrlp)->ldctl_value = *bvp; /* struct copy */ 488 NSLDAPI_FREE( bvp ); /* free container, not contents! */ 489 } 490 491 return( LDAP_SUCCESS ); 492 } 493