Back to index

lightning-sunbird  0.9+nobinonly
control.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /* control.c - routines to handle ldapv3 controls */
00038 
00039 #include "ldap-int.h"
00040 
00041 static LDAPControl *ldap_control_dup( LDAPControl *ctrl );
00042 static int ldap_control_copy_contents( LDAPControl *ctrl_dst,
00043     LDAPControl *ctrl_src );
00044 
00045 /*
00046  * Append a list of LDAPv3 controls to ber.  If ctrls is NULL, use default
00047  * set of controls from ld.
00048  * Return an LDAP error code (LDAP_SUCCESS if all goes well).
00049  * If closeseq is non-zero, we do an extra ber_put_seq() as well.
00050  */
00051 int
00052 nsldapi_put_controls( LDAP *ld, LDAPControl **ctrls, int closeseq,
00053     BerElement *ber )
00054 {
00055        LDAPControl   *c;
00056        int           rc, i;
00057 
00058        rc = LDAP_ENCODING_ERROR;   /* the most popular error */
00059 
00060        /* if no controls were passed in, use global list from LDAP * */
00061        LDAP_MUTEX_LOCK( ld, LDAP_CTRL_LOCK );
00062        if ( ctrls == NULL ) {
00063               ctrls = ld->ld_servercontrols;
00064        }
00065 
00066        /* if there are no controls then we are done */
00067        if ( ctrls == NULL || ctrls[ 0 ] == NULL ) {
00068               goto clean_exit;
00069        }
00070 
00071        /*
00072         * If we're using LDAPv2 or earlier we can't send any controls, so
00073         * we just ignore them unless one is marked critical, in which case
00074         * we return an error.
00075         */
00076        if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
00077               for ( i = 0; ctrls != NULL && ctrls[i] != NULL; i++ ) {
00078                      if ( ctrls[i]->ldctl_iscritical ) {
00079                             rc = LDAP_NOT_SUPPORTED;
00080                             goto error_exit;
00081                      }
00082               }
00083               goto clean_exit;
00084        }
00085 
00086        /*
00087         * encode the controls as a Sequence of Sequence
00088         */
00089        if ( ber_printf( ber, "t{", LDAP_TAG_CONTROLS ) == -1 ) {
00090               goto error_exit;
00091        }
00092 
00093        for ( i = 0; ctrls[i] != NULL; i++ ) {
00094               c = ctrls[i];
00095 
00096               if ( ber_printf( ber, "{s", c->ldctl_oid ) == -1 ) {
00097                      goto error_exit;
00098               }
00099 
00100               /* criticality is "BOOLEAN DEFAULT FALSE" */
00101               /* therefore, it should only be encoded if it exists AND is TRUE */
00102               if ( c->ldctl_iscritical ) {
00103                      if ( ber_printf( ber, "b", (int)c->ldctl_iscritical )
00104                          == -1 ) {
00105                             goto error_exit;
00106                      }
00107               }
00108 
00109               if ( c->ldctl_value.bv_val != NULL ) {
00110                      if ( ber_printf( ber, "o", c->ldctl_value.bv_val,
00111                          (int)c->ldctl_value.bv_len /* XXX lossy cast */ )
00112                          == -1 ) {
00113                             goto error_exit;
00114                      }
00115               }
00116 
00117               if ( ber_put_seq( ber ) == -1 ) {
00118                      goto error_exit;
00119               }
00120        }
00121 
00122        if ( ber_put_seq( ber ) == -1 ) {
00123               goto error_exit;
00124        }
00125 
00126 clean_exit:
00127        LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
00128        if ( closeseq && ber_put_seq( ber ) == -1 ) {
00129               goto error_exit;
00130        }
00131        return( LDAP_SUCCESS );
00132 
00133 error_exit:
00134        LDAP_MUTEX_UNLOCK( ld, LDAP_CTRL_LOCK );
00135        LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
00136        return( rc );
00137 }
00138 
00139 
00140 /*
00141  * Pull controls out of "ber" (if any present) and return them in "controlsp."
00142  * Returns an LDAP error code.
00143  */
00144 int
00145 nsldapi_get_controls( BerElement *ber, LDAPControl ***controlsp )
00146 {
00147        LDAPControl          *newctrl;
00148        unsigned long        tag, len;
00149        int                  rc, maxcontrols, curcontrols;
00150        char                 *last;
00151 
00152        /*
00153         * Each LDAPMessage can have a set of controls appended
00154         * to it. Controls are used to extend the functionality
00155         * of an LDAP operation (e.g., add an attribute size limit
00156         * to the search operation). These controls look like this:
00157         *
00158         *     Controls ::= SEQUENCE OF Control
00159         *
00160         *     Control ::= SEQUENCE {
00161         *            controlType   LDAPOID,
00162         *            criticality   BOOLEAN DEFAULT FALSE,
00163         *            controlValue  OCTET STRING
00164         *     }
00165         */
00166        LDAPDebug( LDAP_DEBUG_TRACE, "=> nsldapi_get_controls\n", 0, 0, 0 );
00167 
00168        *controlsp = NULL;
00169 
00170        /*
00171          * check to see if controls were included
00172         */
00173        if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
00174               return( LDAP_DECODING_ERROR );     /* unexpected error */
00175        }
00176        if ( len == 0 ) {
00177               LDAPDebug( LDAP_DEBUG_TRACE,
00178                   "<= nsldapi_get_controls no controls\n", 0, 0, 0 );
00179               return( LDAP_SUCCESS );                   /* no controls */
00180        }
00181        if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
00182               if ( tag == LBER_ERROR ) {
00183                      LDAPDebug( LDAP_DEBUG_TRACE,
00184                          "<= nsldapi_get_controls LDAP_PROTOCOL_ERROR\n",
00185                          0, 0, 0 );
00186                      return( LDAP_DECODING_ERROR );     /* decoding error */
00187               }
00188               /*
00189                * We found something other than controls.  This should never
00190                * happen in LDAPv3, but we don't treat this is a hard error --
00191                * we just ignore the extra stuff.
00192                */
00193               LDAPDebug( LDAP_DEBUG_TRACE,
00194                   "<= nsldapi_get_controls ignoring unrecognized data in message (tag 0x%x)\n",
00195                   tag, 0, 0 );
00196               return( LDAP_SUCCESS );
00197        }
00198 
00199        maxcontrols = curcontrols = 0;
00200        for ( tag = ber_first_element( ber, &len, &last );
00201            tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
00202            tag = ber_next_element( ber, &len, last ) ) {
00203               if ( curcontrols >= maxcontrols - 1 ) {
00204 #define CONTROL_GRABSIZE    5
00205                      maxcontrols += CONTROL_GRABSIZE;
00206                      *controlsp = (struct ldapcontrol **)NSLDAPI_REALLOC(
00207                          (char *)*controlsp, maxcontrols *
00208                          sizeof(struct ldapcontrol *) );
00209                      if ( *controlsp == NULL ) {
00210                          rc = LDAP_NO_MEMORY;
00211                          goto free_and_return;
00212                      }
00213               }
00214               if (( newctrl = (struct ldapcontrol *)NSLDAPI_CALLOC( 1,
00215                   sizeof(LDAPControl))) == NULL ) {
00216                      rc = LDAP_NO_MEMORY;
00217                      goto free_and_return;
00218               }
00219               
00220               (*controlsp)[curcontrols++] = newctrl;
00221               (*controlsp)[curcontrols] = NULL;
00222 
00223               if ( ber_scanf( ber, "{a", &newctrl->ldctl_oid )
00224                   == LBER_ERROR ) {
00225                      rc = LDAP_DECODING_ERROR;
00226                      goto free_and_return;
00227               }
00228 
00229               /* the criticality is optional */
00230               if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
00231                      int           aint;
00232 
00233                      if ( ber_scanf( ber, "b", &aint ) == LBER_ERROR ) {
00234                             rc = LDAP_DECODING_ERROR;
00235                             goto free_and_return;
00236                      }
00237                      newctrl->ldctl_iscritical = (char)aint;   /* XXX lossy cast */
00238               } else {
00239                      /* absent is synonomous with FALSE */
00240                      newctrl->ldctl_iscritical = 0;
00241               }
00242 
00243               /* the control value is optional */
00244               if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
00245                      if ( ber_scanf( ber, "o", &newctrl->ldctl_value )
00246                          == LBER_ERROR ) {
00247                             rc = LDAP_DECODING_ERROR;
00248                             goto free_and_return;
00249                      }
00250               } else {
00251                      (newctrl->ldctl_value).bv_val = NULL;
00252                      (newctrl->ldctl_value).bv_len = 0;
00253               }
00254 
00255        }
00256 
00257        if ( tag == LBER_ERROR ) {
00258               rc = LDAP_DECODING_ERROR;
00259               goto free_and_return;
00260        }
00261 
00262        LDAPDebug( LDAP_DEBUG_TRACE,
00263            "<= nsldapi_get_controls found %d controls\n", curcontrols, 0, 0 );
00264        return( LDAP_SUCCESS );
00265 
00266 free_and_return:;
00267        ldap_controls_free( *controlsp );
00268        *controlsp = NULL;
00269        LDAPDebug( LDAP_DEBUG_TRACE,
00270            "<= nsldapi_get_controls error 0x%x\n", rc, 0, 0 );
00271        return( rc );
00272 }
00273 
00274 
00275 void
00276 LDAP_CALL
00277 ldap_control_free( LDAPControl *ctrl )
00278 {
00279        if ( ctrl != NULL ) {
00280               if ( ctrl->ldctl_oid != NULL ) {
00281                      NSLDAPI_FREE( ctrl->ldctl_oid );
00282               }
00283               if ( ctrl->ldctl_value.bv_val != NULL ) {
00284                      NSLDAPI_FREE( ctrl->ldctl_value.bv_val );
00285               }
00286               NSLDAPI_FREE( (char *)ctrl );
00287        }
00288 }
00289 
00290 
00291 void
00292 LDAP_CALL
00293 ldap_controls_free( LDAPControl **ctrls )
00294 {
00295        int    i;
00296 
00297        if ( ctrls != NULL ) {
00298               for ( i = 0; ctrls[i] != NULL; i++ ) {
00299                      ldap_control_free( ctrls[i] );
00300               }
00301               NSLDAPI_FREE( (char *)ctrls );
00302        }
00303 }
00304 
00305 
00306 
00307 #if 0
00308 LDAPControl **
00309 LDAP_CALL
00310 ldap_control_append( LDAPControl **ctrl_src, LDAPControl *ctrl )
00311 {
00312     int nctrls = 0;
00313        LDAPControl **ctrlp;
00314        int i;
00315 
00316        if ( NULL == ctrl )
00317            return ( NULL );
00318 
00319        /* Count the existing controls */
00320        if ( NULL != ctrl_src ) {
00321               while( NULL != ctrl_src[nctrls] ) {
00322                      nctrls++;
00323               }
00324        }
00325 
00326        /* allocate the new control structure */
00327        if ( ( ctrlp = (LDAPControl **)NSLDAPI_MALLOC( sizeof(LDAPControl *)
00328            * (nctrls + 2) ) ) == NULL ) {
00329               return( NULL );
00330        }
00331        memset( ctrlp, 0, sizeof(*ctrlp) * (nctrls + 2) );
00332 
00333        for( i = 0; i < (nctrls + 1); i++ ) {
00334            if ( i < nctrls ) {
00335                   ctrlp[i] = ldap_control_dup( ctrl_src[i] );
00336            } else {
00337                   ctrlp[i] = ldap_control_dup( ctrl );
00338            }
00339            if ( NULL == ctrlp[i] ) {
00340                   ldap_controls_free( ctrlp );
00341                   return( NULL );
00342            }
00343        }
00344        return ctrlp;
00345 }
00346 #endif /* 0 */
00347 
00348 
00349 /*
00350  * Replace *ldctrls with a copy of newctrls.
00351  * returns 0 if successful.
00352  * return -1 if not and set error code inside LDAP *ld.
00353  */
00354 int
00355 nsldapi_dup_controls( LDAP *ld, LDAPControl ***ldctrls, LDAPControl **newctrls )
00356 {
00357        int    count;
00358 
00359        if ( *ldctrls != NULL ) {
00360               ldap_controls_free( *ldctrls );
00361        }
00362 
00363        if ( newctrls == NULL || newctrls[0] == NULL ) {
00364               *ldctrls = NULL;
00365               return( 0 );
00366        }
00367 
00368        for ( count = 0; newctrls[ count ] != NULL; ++count ) {
00369               ;
00370        }
00371 
00372        if (( *ldctrls = (LDAPControl **)NSLDAPI_MALLOC(( count + 1 ) *
00373            sizeof( LDAPControl *))) == NULL ) {
00374               LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
00375               return( -1 );
00376        }
00377        (*ldctrls)[ count ] = NULL;
00378 
00379        for ( count = 0; newctrls[ count ] != NULL; ++count ) {
00380               if (( (*ldctrls)[ count ] =
00381                   ldap_control_dup( newctrls[ count ] )) == NULL ) {
00382                      ldap_controls_free( *ldctrls );
00383                      *ldctrls = NULL;
00384                      LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
00385                      return( -1 );
00386               }
00387        }
00388 
00389        return( 0 );
00390 }
00391 
00392 
00393 /*
00394  * return a malloc'd copy of "ctrl" (NULL if memory allocation fails)
00395  */
00396 static LDAPControl *
00397 /* LDAP_CALL */             /* keep this routine internal for now */
00398 ldap_control_dup( LDAPControl *ctrl )
00399 {
00400        LDAPControl   *rctrl;
00401 
00402        if (( rctrl = (LDAPControl *)NSLDAPI_MALLOC( sizeof( LDAPControl )))
00403            == NULL ) {
00404               return( NULL );
00405        }
00406 
00407        if ( ldap_control_copy_contents( rctrl, ctrl ) != LDAP_SUCCESS ) {
00408               NSLDAPI_FREE( rctrl );
00409               return( NULL );
00410        }
00411 
00412        return( rctrl );
00413 }
00414 
00415 
00416 /*
00417  * duplicate the contents of "ctrl_src" and place in "ctrl_dst"
00418  */
00419 static int
00420 /* LDAP_CALL */             /* keep this routine internal for now */
00421 ldap_control_copy_contents( LDAPControl *ctrl_dst, LDAPControl *ctrl_src )
00422 {
00423        size_t len;
00424 
00425        if ( NULL == ctrl_dst || NULL == ctrl_src ) {
00426               return( LDAP_PARAM_ERROR );
00427        }
00428 
00429        ctrl_dst->ldctl_iscritical = ctrl_src->ldctl_iscritical;
00430 
00431        /* fill in the fields of this new control */
00432        if (( ctrl_dst->ldctl_oid = nsldapi_strdup( ctrl_src->ldctl_oid ))
00433            == NULL ) {
00434               return( LDAP_NO_MEMORY );
00435        }
00436 
00437        len = (size_t)(ctrl_src->ldctl_value).bv_len;
00438        if ( ctrl_src->ldctl_value.bv_val == NULL || len <= 0 ) {
00439               ctrl_dst->ldctl_value.bv_len = 0;
00440               ctrl_dst->ldctl_value.bv_val = NULL;
00441        } else {
00442               ctrl_dst->ldctl_value.bv_len = len;
00443               if (( ctrl_dst->ldctl_value.bv_val = NSLDAPI_MALLOC( len ))
00444                   == NULL ) {
00445                      NSLDAPI_FREE( ctrl_dst->ldctl_oid );
00446                      return( LDAP_NO_MEMORY );
00447               }
00448               SAFEMEMCPY( ctrl_dst->ldctl_value.bv_val,
00449                   ctrl_src->ldctl_value.bv_val, len );
00450        }
00451 
00452        return ( LDAP_SUCCESS );
00453 }
00454 
00455 
00456 
00457 /*
00458  * build an allocated LDAPv3 control.  Returns an LDAP error code.
00459  */
00460 int
00461 nsldapi_build_control( char *oid, BerElement *ber, int freeber, char iscritical,
00462     LDAPControl **ctrlp )
00463 {
00464        int           rc;
00465        struct berval *bvp;
00466 
00467        if ( ber == NULL ) {
00468               bvp = NULL;
00469        } else {
00470               /* allocate struct berval with contents of the BER encoding */
00471               rc = ber_flatten( ber, &bvp );
00472               if ( freeber ) {
00473                      ber_free( ber, 1 );
00474               }
00475               if ( rc == -1 ) {
00476                      return( LDAP_NO_MEMORY );
00477               }
00478        }
00479 
00480        /* allocate the new control structure */
00481        if (( *ctrlp = (LDAPControl *)NSLDAPI_MALLOC( sizeof(LDAPControl)))
00482            == NULL ) {
00483               if ( bvp != NULL ) {
00484                      ber_bvfree( bvp );
00485               }
00486               return( LDAP_NO_MEMORY );
00487        }
00488 
00489        /* fill in the fields of this new control */
00490        (*ctrlp)->ldctl_iscritical = iscritical;  
00491        if (( (*ctrlp)->ldctl_oid = nsldapi_strdup( oid )) == NULL ) {
00492               NSLDAPI_FREE( *ctrlp ); 
00493               if ( bvp != NULL ) {
00494                      ber_bvfree( bvp );
00495               }
00496               return( LDAP_NO_MEMORY );
00497        }                           
00498 
00499        if ( bvp == NULL ) {
00500               (*ctrlp)->ldctl_value.bv_len = 0;
00501               (*ctrlp)->ldctl_value.bv_val = NULL;
00502        } else {
00503               (*ctrlp)->ldctl_value = *bvp;      /* struct copy */
00504               NSLDAPI_FREE( bvp ); /* free container, not contents! */
00505        }
00506 
00507        return( LDAP_SUCCESS );
00508 }