]> git.sur5r.net Git - openldap/blob - libraries/libldap/extended.c
4f3f464562fefe8bc7ef1c92b5487af0c8d327cf
[openldap] / libraries / libldap / extended.c
1 /*
2  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5
6 /*
7  * LDAPv3 Extended Operation Request
8  *      ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
9  *              requestName      [0] LDAPOID,
10  *              requestValue     [1] OCTET STRING OPTIONAL
11  *      }
12  *
13  * LDAPv3 Extended Operation Response
14  *      ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
15  *              COMPONENTS OF LDAPResult,
16  *              responseName     [10] LDAPOID OPTIONAL,
17  *              response         [11] OCTET STRING OPTIONAL
18  *      }
19  *
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/stdlib.h>
26
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
30
31 #include "ldap-int.h"
32
33 int
34 ldap_extended_operation(
35         LDAP                    *ld,
36         LDAP_CONST char *reqoid,
37         struct berval   *reqdata,
38         LDAPControl             **sctrls,
39         LDAPControl             **cctrls,
40         int                             *msgidp )
41 {
42         BerElement *ber;
43
44         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
45
46         assert( ld != NULL );
47         assert( LDAP_VALID( ld ) );
48         assert( reqoid != NULL || *reqoid == '\0' );
49         assert( msgidp != NULL );
50
51         /* must be version 3 (or greater) */
52         if ( ld->ld_version < LDAP_VERSION3 ) {
53                 ld->ld_errno = LDAP_NOT_SUPPORTED;
54                 return( ld->ld_errno );
55         }
56
57         if( reqoid == NULL || *reqoid == '\0' || msgidp == NULL ) {
58                 ld->ld_errno = LDAP_PARAM_ERROR;
59                 return( ld->ld_errno );
60         }
61
62         /* create a message to send */
63         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
64                 ld->ld_errno = LDAP_NO_MEMORY;
65                 return( ld->ld_errno );
66         }
67
68         if ( ber_printf( ber, "{it{tstO}", /* '}' */
69                 ++ld->ld_msgid, LDAP_REQ_EXTENDED, LDAP_TAG_EXOP_REQ_OID,
70                         reqoid, LDAP_TAG_EXOP_REQ_VALUE, reqdata ) == -1 )
71         {
72                 ld->ld_errno = LDAP_ENCODING_ERROR;
73                 ber_free( ber, 1 );
74                 return( ld->ld_errno );
75         }
76
77         /* Put Server Controls */
78         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
79                 ber_free( ber, 1 );
80                 return ld->ld_errno;
81         }
82
83         if ( ber_printf( ber, /*{*/ "}" ) == -1 ) {
84                 ld->ld_errno = LDAP_ENCODING_ERROR;
85                 ber_free( ber, 1 );
86                 return( ld->ld_errno );
87         }
88
89         /* send the message */
90         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber );
91
92         return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS );
93 }
94
95 int
96 ldap_extended_operation_s(
97         LDAP                    *ld,
98         LDAP_CONST char *reqoid,
99         struct berval   *reqdata,
100         LDAPControl             **sctrls,
101         LDAPControl             **cctrls,
102         char                    **retoidp,
103         struct berval   **retdatap )
104 {
105     int     rc;
106     int     msgid;
107     LDAPMessage *res;
108
109         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 );
110
111         assert( ld != NULL );
112         assert( LDAP_VALID( ld ) );
113         assert( reqoid != NULL || *reqoid == '\0' );
114         assert( retoidp != NULL || retdatap != NULL );
115
116         if( retoidp == NULL || retdatap == NULL ) {
117                 ld->ld_errno = LDAP_PARAM_ERROR;
118                 return( ld->ld_errno );
119         }
120
121     rc = ldap_extended_operation( ld, reqoid, reqdata,
122                 sctrls, cctrls, &msgid );
123         
124     if ( rc != LDAP_SUCCESS ) {
125         return( rc );
126         }
127  
128     if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) {
129         return( ld->ld_errno );
130         }
131
132         *retoidp = NULL;
133         *retdatap = NULL;
134
135         rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 );
136
137         if( rc != LDAP_SUCCESS ) {
138                 ldap_msgfree( res );
139                 return rc;
140         }
141
142     return( ldap_result2error( ld, res, 1 ) );
143 }
144
145 /* Parse an extended result */
146 int
147 ldap_parse_extended_result (
148         LDAP                    *ld,
149         LDAPMessage             *res,
150         char                    **retoidp,
151         struct berval   **retdatap,
152         int                             freeit )
153 {
154         BerElement *ber;
155         ber_tag_t rc;
156         ber_tag_t tag;
157         ber_len_t len;
158         struct berval *resdata;
159         ber_int_t errcode;
160         char *resoid;
161
162         assert( ld != NULL );
163         assert( LDAP_VALID( ld ) );
164         assert( res != NULL );
165
166         Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
167
168         if( ld->ld_version < LDAP_VERSION3 ) {
169                 ld->ld_errno = LDAP_NOT_SUPPORTED;
170                 return ld->ld_errno;
171         }
172
173         if( res->lm_msgtype == LDAP_RES_EXTENDED ) {
174                 ld->ld_errno = LDAP_PARAM_ERROR;
175                 return ld->ld_errno;
176         }
177
178         if( retoidp != NULL ) *retoidp = NULL;
179         if( retdatap != NULL ) *retdatap = NULL;
180
181         ber = ber_dup( res->lm_ber );
182
183         if ( ld->ld_error ) {
184                 LDAP_FREE( ld->ld_error );
185                 ld->ld_error = NULL;
186         }
187
188         if ( ld->ld_matched ) {
189                 LDAP_FREE( ld->ld_matched );
190                 ld->ld_matched = NULL;
191         }
192
193         rc = ber_scanf( ber, "{iaa" /*}*/, &errcode,
194                 &ld->ld_matched, &ld->ld_matched );
195
196         if( rc == LBER_ERROR ) {
197                 ld->ld_errno = LDAP_DECODING_ERROR;
198                 ber_free( ber, 0 );
199                 return ld->ld_errno;
200         }
201
202         resoid = NULL;
203         resdata = NULL;
204
205         tag = ber_peek_tag( ber, &len );
206
207         if( tag == LDAP_TAG_REFERRAL ) {
208                 /* skip over referral */
209                 tag = ber_scanf( ber, "x" );
210
211                 if( tag != LBER_ERROR ) {
212                         tag = ber_peek_tag( ber, &len );
213                 }
214         }
215
216         if( tag == LDAP_TAG_EXOP_RES_OID ) {
217                 /* we have a resoid */
218                 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
219                         ld->ld_errno = LDAP_DECODING_ERROR;
220                         ber_free( ber, 0 );
221                         return ld->ld_errno;
222                 }
223
224                 tag = ber_peek_tag( ber, &len );
225         }
226
227         if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
228                 /* we have a resdata */
229                 if( ber_scanf( ber, "O", &resoid ) == LBER_ERROR ) {
230                         ld->ld_errno = LDAP_DECODING_ERROR;
231                         ber_free( ber, 0 );
232                         if( resoid != NULL ) LDAP_FREE( resoid );
233                         return ld->ld_errno;
234                 }
235         }
236
237         if( retoidp != NULL ) {
238                 *retoidp = resoid;
239         } else {
240                 LDAP_FREE( resoid );
241         }
242
243         if( retdatap != NULL ) {
244                 *retdatap = resdata;
245         } else {
246                 ber_bvfree( resdata );
247         }
248
249         ld->ld_errno = errcode;
250
251         if( freeit ) {
252                 ldap_msgfree( res );
253         }
254
255         return LDAP_SUCCESS;
256 }