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