Back to index

openldap  2.4.31
extended.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include "portable.h"
00017 
00018 #include <stdio.h>
00019 #include <ac/stdlib.h>
00020 
00021 #include <ac/socket.h>
00022 #include <ac/string.h>
00023 #include <ac/time.h>
00024 
00025 #include "ldap-int.h"
00026 #include "ldap_log.h"
00027 
00028 /*
00029  * LDAPv3 Extended Operation Request
00030  *     ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
00031  *            requestName      [0] LDAPOID,
00032  *            requestValue     [1] OCTET STRING OPTIONAL
00033  *     }
00034  *
00035  * LDAPv3 Extended Operation Response
00036  *     ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
00037  *            COMPONENTS OF LDAPResult,
00038  *            responseName     [10] LDAPOID OPTIONAL,
00039  *            response         [11] OCTET STRING OPTIONAL
00040  *     }
00041  *
00042  * (Source RFC 4511)
00043  */
00044 
00045 int
00046 ldap_extended_operation(
00047        LDAP                 *ld,
00048        LDAP_CONST char      *reqoid,
00049        struct berval *reqdata,
00050        LDAPControl          **sctrls,
00051        LDAPControl          **cctrls,
00052        int                         *msgidp )
00053 {
00054        BerElement *ber;
00055        int rc;
00056        ber_int_t id;
00057 
00058        Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
00059 
00060        assert( ld != NULL );
00061        assert( LDAP_VALID( ld ) );
00062        assert( reqoid != NULL && *reqoid != '\0' );
00063        assert( msgidp != NULL );
00064 
00065        /* must be version 3 (or greater) */
00066        if ( ld->ld_version < LDAP_VERSION3 ) {
00067               ld->ld_errno = LDAP_NOT_SUPPORTED;
00068               return( ld->ld_errno );
00069        }
00070 
00071        /* create a message to send */
00072        if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
00073               ld->ld_errno = LDAP_NO_MEMORY;
00074               return( ld->ld_errno );
00075        }
00076 
00077        LDAP_NEXT_MSGID( ld, id );
00078        if ( reqdata != NULL ) {
00079               rc = ber_printf( ber, "{it{tstON}", /* '}' */
00080                      id, LDAP_REQ_EXTENDED,
00081                      LDAP_TAG_EXOP_REQ_OID, reqoid,
00082                      LDAP_TAG_EXOP_REQ_VALUE, reqdata );
00083 
00084        } else {
00085               rc = ber_printf( ber, "{it{tsN}", /* '}' */
00086                      id, LDAP_REQ_EXTENDED,
00087                      LDAP_TAG_EXOP_REQ_OID, reqoid );
00088        }
00089 
00090        if( rc == -1 ) {
00091               ld->ld_errno = LDAP_ENCODING_ERROR;
00092               ber_free( ber, 1 );
00093               return( ld->ld_errno );
00094        }
00095 
00096        /* Put Server Controls */
00097        if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
00098               ber_free( ber, 1 );
00099               return ld->ld_errno;
00100        }
00101 
00102        if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
00103               ld->ld_errno = LDAP_ENCODING_ERROR;
00104               ber_free( ber, 1 );
00105               return( ld->ld_errno );
00106        }
00107 
00108        /* send the message */
00109        *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber, id );
00110 
00111        return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS );
00112 }
00113 
00114 int
00115 ldap_extended_operation_s(
00116        LDAP                 *ld,
00117        LDAP_CONST char      *reqoid,
00118        struct berval *reqdata,
00119        LDAPControl          **sctrls,
00120        LDAPControl          **cctrls,
00121        char                 **retoidp,
00122        struct berval **retdatap )
00123 {
00124     int     rc;
00125     int     msgid;
00126     LDAPMessage *res;
00127 
00128        Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 );
00129 
00130        assert( ld != NULL );
00131        assert( LDAP_VALID( ld ) );
00132        assert( reqoid != NULL && *reqoid != '\0' );
00133 
00134     rc = ldap_extended_operation( ld, reqoid, reqdata,
00135               sctrls, cctrls, &msgid );
00136         
00137     if ( rc != LDAP_SUCCESS ) {
00138         return( rc );
00139        }
00140  
00141     if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 || !res ) {
00142         return( ld->ld_errno );
00143        }
00144 
00145        if ( retoidp != NULL ) *retoidp = NULL;
00146        if ( retdatap != NULL ) *retdatap = NULL;
00147 
00148        rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 );
00149 
00150        if( rc != LDAP_SUCCESS ) {
00151               ldap_msgfree( res );
00152               return rc;
00153        }
00154 
00155     return( ldap_result2error( ld, res, 1 ) );
00156 }
00157 
00158 /* Parse an extended result */
00159 int
00160 ldap_parse_extended_result (
00161        LDAP                 *ld,
00162        LDAPMessage          *res,
00163        char                 **retoidp,
00164        struct berval **retdatap,
00165        int                         freeit )
00166 {
00167        BerElement *ber;
00168        ber_tag_t rc;
00169        ber_tag_t tag;
00170        ber_len_t len;
00171        struct berval *resdata;
00172        ber_int_t errcode;
00173        char *resoid;
00174 
00175        assert( ld != NULL );
00176        assert( LDAP_VALID( ld ) );
00177        assert( res != NULL );
00178 
00179        Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
00180 
00181        if( ld->ld_version < LDAP_VERSION3 ) {
00182               ld->ld_errno = LDAP_NOT_SUPPORTED;
00183               return ld->ld_errno;
00184        }
00185 
00186        if( res->lm_msgtype != LDAP_RES_EXTENDED ) {
00187               ld->ld_errno = LDAP_PARAM_ERROR;
00188               return ld->ld_errno;
00189        }
00190 
00191        if( retoidp != NULL ) *retoidp = NULL;
00192        if( retdatap != NULL ) *retdatap = NULL;
00193 
00194        if ( ld->ld_error ) {
00195               LDAP_FREE( ld->ld_error );
00196               ld->ld_error = NULL;
00197        }
00198 
00199        if ( ld->ld_matched ) {
00200               LDAP_FREE( ld->ld_matched );
00201               ld->ld_matched = NULL;
00202        }
00203 
00204        ber = ber_dup( res->lm_ber );
00205 
00206        if ( ber == NULL ) {
00207               ld->ld_errno = LDAP_NO_MEMORY;
00208               return ld->ld_errno;
00209        }
00210 
00211        rc = ber_scanf( ber, "{eAA" /*}*/, &errcode,
00212               &ld->ld_matched, &ld->ld_error );
00213 
00214        if( rc == LBER_ERROR ) {
00215               ld->ld_errno = LDAP_DECODING_ERROR;
00216               ber_free( ber, 0 );
00217               return ld->ld_errno;
00218        }
00219 
00220        resoid = NULL;
00221        resdata = NULL;
00222 
00223        tag = ber_peek_tag( ber, &len );
00224 
00225        if( tag == LDAP_TAG_REFERRAL ) {
00226               /* skip over referral */
00227               if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
00228                      ld->ld_errno = LDAP_DECODING_ERROR;
00229                      ber_free( ber, 0 );
00230                      return ld->ld_errno;
00231               }
00232 
00233               tag = ber_peek_tag( ber, &len );
00234        }
00235 
00236        if( tag == LDAP_TAG_EXOP_RES_OID ) {
00237               /* we have a resoid */
00238               if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
00239                      ld->ld_errno = LDAP_DECODING_ERROR;
00240                      ber_free( ber, 0 );
00241                      return ld->ld_errno;
00242               }
00243 
00244               assert( resoid[ 0 ] != '\0' );
00245 
00246               tag = ber_peek_tag( ber, &len );
00247        }
00248 
00249        if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
00250               /* we have a resdata */
00251               if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
00252                      ld->ld_errno = LDAP_DECODING_ERROR;
00253                      ber_free( ber, 0 );
00254                      if( resoid != NULL ) LDAP_FREE( resoid );
00255                      return ld->ld_errno;
00256               }
00257        }
00258 
00259        ber_free( ber, 0 );
00260 
00261        if( retoidp != NULL ) {
00262               *retoidp = resoid;
00263        } else {
00264               LDAP_FREE( resoid );
00265        }
00266 
00267        if( retdatap != NULL ) {
00268               *retdatap = resdata;
00269        } else {
00270               ber_bvfree( resdata );
00271        }
00272 
00273        ld->ld_errno = errcode;
00274 
00275        if( freeit ) {
00276               ldap_msgfree( res );
00277        }
00278 
00279        return LDAP_SUCCESS;
00280 }
00281 
00282 
00283 /* Parse an extended partial */
00284 int
00285 ldap_parse_intermediate (
00286        LDAP                 *ld,
00287        LDAPMessage          *res,
00288        char                 **retoidp,
00289        struct berval **retdatap,
00290        LDAPControl          ***serverctrls,
00291        int                         freeit )
00292 {
00293        BerElement *ber;
00294        ber_tag_t tag;
00295        ber_len_t len;
00296        struct berval *resdata;
00297        char *resoid;
00298 
00299        assert( ld != NULL );
00300        assert( LDAP_VALID( ld ) );
00301        assert( res != NULL );
00302 
00303        Debug( LDAP_DEBUG_TRACE, "ldap_parse_intermediate\n", 0, 0, 0 );
00304 
00305        if( ld->ld_version < LDAP_VERSION3 ) {
00306               ld->ld_errno = LDAP_NOT_SUPPORTED;
00307               return ld->ld_errno;
00308        }
00309 
00310        if( res->lm_msgtype != LDAP_RES_INTERMEDIATE ) {
00311               ld->ld_errno = LDAP_PARAM_ERROR;
00312               return ld->ld_errno;
00313        }
00314 
00315        if( retoidp != NULL ) *retoidp = NULL;
00316        if( retdatap != NULL ) *retdatap = NULL;
00317        if( serverctrls != NULL ) *serverctrls = NULL;
00318 
00319        ber = ber_dup( res->lm_ber );
00320 
00321        if ( ber == NULL ) {
00322               ld->ld_errno = LDAP_NO_MEMORY;
00323               return ld->ld_errno;
00324        }
00325 
00326        tag = ber_scanf( ber, "{" /*}*/ );
00327 
00328        if( tag == LBER_ERROR ) {
00329               ld->ld_errno = LDAP_DECODING_ERROR;
00330               ber_free( ber, 0 );
00331               return ld->ld_errno;
00332        }
00333 
00334        resoid = NULL;
00335        resdata = NULL;
00336 
00337        tag = ber_peek_tag( ber, &len );
00338 
00339        /*
00340         * NOTE: accept intermediate and extended response tag values
00341         * as older versions of slapd(8) incorrectly used extended
00342         * response tags.
00343         * Should be removed when 2.2 is moved to Historic.
00344         */
00345        if( tag == LDAP_TAG_IM_RES_OID || tag == LDAP_TAG_EXOP_RES_OID ) {
00346               /* we have a resoid */
00347               if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
00348                      ld->ld_errno = LDAP_DECODING_ERROR;
00349                      ber_free( ber, 0 );
00350                      return ld->ld_errno;
00351               }
00352 
00353               assert( resoid[ 0 ] != '\0' );
00354 
00355               tag = ber_peek_tag( ber, &len );
00356        }
00357 
00358        if( tag == LDAP_TAG_IM_RES_VALUE || tag == LDAP_TAG_EXOP_RES_VALUE ) {
00359               /* we have a resdata */
00360               if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
00361                      ld->ld_errno = LDAP_DECODING_ERROR;
00362                      ber_free( ber, 0 );
00363                      if( resoid != NULL ) LDAP_FREE( resoid );
00364                      return ld->ld_errno;
00365               }
00366        }
00367 
00368        if ( serverctrls == NULL ) {
00369               ld->ld_errno = LDAP_SUCCESS;
00370               goto free_and_return;
00371        }
00372 
00373        if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) {
00374               ld->ld_errno = LDAP_DECODING_ERROR;
00375               goto free_and_return;
00376        }
00377 
00378        ld->ld_errno = ldap_pvt_get_controls( ber, serverctrls );
00379 
00380 free_and_return:
00381        ber_free( ber, 0 );
00382 
00383        if( retoidp != NULL ) {
00384               *retoidp = resoid;
00385        } else {
00386               LDAP_FREE( resoid );
00387        }
00388 
00389        if( retdatap != NULL ) {
00390               *retdatap = resdata;
00391        } else {
00392               ber_bvfree( resdata );
00393        }
00394 
00395        if( freeit ) {
00396               ldap_msgfree( res );
00397        }
00398 
00399        return ld->ld_errno;
00400 }
00401