]> git.sur5r.net Git - openldap/blob - libraries/libldap/extended.c
49256185929d5fa0b553e01952754d0c4b0f6f79
[openldap] / libraries / libldap / extended.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 /*
8  * LDAPv3 Extended Operation Request
9  *      ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
10  *              requestName      [0] LDAPOID,
11  *              requestValue     [1] OCTET STRING OPTIONAL
12  *      }
13  *
14  * LDAPv3 Extended Operation Response
15  *      ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
16  *              COMPONENTS OF LDAPResult,
17  *              responseName     [10] LDAPOID OPTIONAL,
18  *              response         [11] OCTET STRING OPTIONAL
19  *      }
20  *
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26 #include <ac/stdlib.h>
27
28 #include <ac/socket.h>
29 #include <ac/string.h>
30 #include <ac/time.h>
31
32 #include "ldap-int.h"
33
34 int
35 ldap_extended_operation(
36         LDAP                    *ld,
37         LDAP_CONST char *reqoid,
38         struct berval   *reqdata,
39         LDAPControl             **sctrls,
40         LDAPControl             **cctrls,
41         int                             *msgidp )
42 {
43         BerElement *ber;
44         int rc;
45
46         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
47
48         assert( ld != NULL );
49         assert( LDAP_VALID( ld ) );
50         assert( reqoid != NULL || *reqoid == '\0' );
51         assert( msgidp != NULL );
52
53         /* must be version 3 (or greater) */
54         if ( ld->ld_version < LDAP_VERSION3 ) {
55                 ld->ld_errno = LDAP_NOT_SUPPORTED;
56                 return( ld->ld_errno );
57         }
58
59         if( reqoid == NULL || *reqoid == '\0' || msgidp == NULL ) {
60                 ld->ld_errno = LDAP_PARAM_ERROR;
61                 return( ld->ld_errno );
62         }
63
64         /* create a message to send */
65         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
66                 ld->ld_errno = LDAP_NO_MEMORY;
67                 return( ld->ld_errno );
68         }
69
70         if ( reqdata != NULL ) {
71                 rc = ber_printf( ber, "{it{tstON}", /* '}' */
72                         ++ld->ld_msgid, LDAP_REQ_EXTENDED,
73                         LDAP_TAG_EXOP_REQ_OID, reqoid,
74                         LDAP_TAG_EXOP_REQ_VALUE, reqdata );
75
76         } else {
77                 rc = ber_printf( ber, "{it{tsN}", /* '}' */
78                         ++ld->ld_msgid, LDAP_REQ_EXTENDED,
79                         LDAP_TAG_EXOP_REQ_OID, reqoid );
80         }
81
82         if( rc == -1 ) {
83                 ld->ld_errno = LDAP_ENCODING_ERROR;
84                 ber_free( ber, 1 );
85                 return( ld->ld_errno );
86         }
87
88         /* Put Server Controls */
89         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
90                 ber_free( ber, 1 );
91                 return ld->ld_errno;
92         }
93
94         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
95                 ld->ld_errno = LDAP_ENCODING_ERROR;
96                 ber_free( ber, 1 );
97                 return( ld->ld_errno );
98         }
99
100         /* send the message */
101         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber );
102
103         return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS );
104 }
105
106 int
107 ldap_extended_operation_s(
108         LDAP                    *ld,
109         LDAP_CONST char *reqoid,
110         struct berval   *reqdata,
111         LDAPControl             **sctrls,
112         LDAPControl             **cctrls,
113         char                    **retoidp,
114         struct berval   **retdatap )
115 {
116     int     rc;
117     int     msgid;
118     LDAPMessage *res;
119
120         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 );
121
122         assert( ld != NULL );
123         assert( LDAP_VALID( ld ) );
124         assert( reqoid != NULL || *reqoid == '\0' );
125         assert( retoidp != NULL || retdatap != NULL );
126
127         if( retoidp == NULL || retdatap == NULL ) {
128                 ld->ld_errno = LDAP_PARAM_ERROR;
129                 return( ld->ld_errno );
130         }
131
132     rc = ldap_extended_operation( ld, reqoid, reqdata,
133                 sctrls, cctrls, &msgid );
134         
135     if ( rc != LDAP_SUCCESS ) {
136         return( rc );
137         }
138  
139     if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) {
140         return( ld->ld_errno );
141         }
142
143         *retoidp = NULL;
144         *retdatap = NULL;
145
146         rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 );
147
148         if( rc != LDAP_SUCCESS ) {
149                 ldap_msgfree( res );
150                 return rc;
151         }
152
153     return( ldap_result2error( ld, res, 1 ) );
154 }
155
156 /* Parse an extended result */
157 int
158 ldap_parse_extended_result (
159         LDAP                    *ld,
160         LDAPMessage             *res,
161         char                    **retoidp,
162         struct berval   **retdatap,
163         int                             freeit )
164 {
165         BerElement *ber;
166         ber_tag_t rc;
167         ber_tag_t tag;
168         ber_len_t len;
169         struct berval *resdata;
170         ber_int_t errcode;
171         char *resoid;
172
173         assert( ld != NULL );
174         assert( LDAP_VALID( ld ) );
175         assert( res != NULL );
176
177         Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
178
179         if( ld->ld_version < LDAP_VERSION3 ) {
180                 ld->ld_errno = LDAP_NOT_SUPPORTED;
181                 return ld->ld_errno;
182         }
183
184         if( res->lm_msgtype != LDAP_RES_EXTENDED ) {
185                 ld->ld_errno = LDAP_PARAM_ERROR;
186                 return ld->ld_errno;
187         }
188
189         if( retoidp != NULL ) *retoidp = NULL;
190         if( retdatap != NULL ) *retdatap = NULL;
191
192         if ( ld->ld_error ) {
193                 LDAP_FREE( ld->ld_error );
194                 ld->ld_error = NULL;
195         }
196
197         if ( ld->ld_matched ) {
198                 LDAP_FREE( ld->ld_matched );
199                 ld->ld_matched = NULL;
200         }
201
202         ber = ber_dup( res->lm_ber );
203
204         if ( ber == NULL ) {
205                 ld->ld_errno = LDAP_NO_MEMORY;
206                 return ld->ld_errno;
207         }
208
209         rc = ber_scanf( ber, "{iaa" /*}*/, &errcode,
210                 &ld->ld_matched, &ld->ld_error );
211
212         if( rc == LBER_ERROR ) {
213                 ld->ld_errno = LDAP_DECODING_ERROR;
214                 ber_free( ber, 0 );
215                 return ld->ld_errno;
216         }
217
218         resoid = NULL;
219         resdata = NULL;
220
221         tag = ber_peek_tag( ber, &len );
222
223         if( tag == LDAP_TAG_REFERRAL ) {
224                 /* skip over referral */
225                 if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
226                         ld->ld_errno = LDAP_DECODING_ERROR;
227                         ber_free( ber, 0 );
228                         return ld->ld_errno;
229                 }
230
231                 tag = ber_peek_tag( ber, &len );
232         }
233
234         if( tag == LDAP_TAG_EXOP_RES_OID ) {
235                 /* we have a resoid */
236                 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
237                         ld->ld_errno = LDAP_DECODING_ERROR;
238                         ber_free( ber, 0 );
239                         return ld->ld_errno;
240                 }
241
242                 tag = ber_peek_tag( ber, &len );
243         }
244
245         if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
246                 /* we have a resdata */
247                 if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
248                         ld->ld_errno = LDAP_DECODING_ERROR;
249                         ber_free( ber, 0 );
250                         if( resoid != NULL ) LDAP_FREE( resoid );
251                         return ld->ld_errno;
252                 }
253         }
254
255         ber_free( ber, 0 );
256
257         if( retoidp != NULL ) {
258                 *retoidp = resoid;
259         } else {
260                 LDAP_FREE( resoid );
261         }
262
263         if( retdatap != NULL ) {
264                 *retdatap = resdata;
265         } else {
266                 ber_bvfree( resdata );
267         }
268
269         ld->ld_errno = errcode;
270
271         if( freeit ) {
272                 ldap_msgfree( res );
273         }
274
275         return LDAP_SUCCESS;
276 }
277
278
279 /* Parse an extended partial */
280 int
281 ldap_parse_extended_partial (
282         LDAP                    *ld,
283         LDAPMessage             *res,
284         char                    **retoidp,
285         struct berval   **retdatap,
286         LDAPControl             ***serverctrls,
287         int                             freeit )
288 {
289         BerElement *ber;
290         ber_tag_t rc;
291         ber_tag_t tag;
292         ber_len_t len;
293         struct berval *resdata;
294         char *resoid;
295
296         assert( ld != NULL );
297         assert( LDAP_VALID( ld ) );
298         assert( res != NULL );
299
300         Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
301
302         if( ld->ld_version < LDAP_VERSION3 ) {
303                 ld->ld_errno = LDAP_NOT_SUPPORTED;
304                 return ld->ld_errno;
305         }
306
307         if( res->lm_msgtype != LDAP_RES_EXTENDED_PARTIAL ) {
308                 ld->ld_errno = LDAP_PARAM_ERROR;
309                 return ld->ld_errno;
310         }
311
312         if( retoidp != NULL ) *retoidp = NULL;
313         if( retdatap != NULL ) *retdatap = NULL;
314
315         ber = ber_dup( res->lm_ber );
316
317         if ( ber == NULL ) {
318                 ld->ld_errno = LDAP_NO_MEMORY;
319                 return ld->ld_errno;
320         }
321
322         rc = ber_scanf( ber, "{" /*}*/ );
323
324         if( rc == LBER_ERROR ) {
325                 ld->ld_errno = LDAP_DECODING_ERROR;
326                 ber_free( ber, 0 );
327                 return ld->ld_errno;
328         }
329
330         resoid = NULL;
331         resdata = NULL;
332
333         tag = ber_peek_tag( ber, &len );
334
335         if( tag == LDAP_TAG_EXOP_RES_OID ) {
336                 /* we have a resoid */
337                 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
338                         ld->ld_errno = LDAP_DECODING_ERROR;
339                         ber_free( ber, 0 );
340                         return ld->ld_errno;
341                 }
342
343                 tag = ber_peek_tag( ber, &len );
344         }
345
346         if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
347                 /* we have a resdata */
348                 if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
349                         ld->ld_errno = LDAP_DECODING_ERROR;
350                         ber_free( ber, 0 );
351                         if( resoid != NULL ) LDAP_FREE( resoid );
352                         return ld->ld_errno;
353                 }
354         }
355
356         if ( serverctrls == NULL ) {
357                 rc = LDAP_SUCCESS;
358                 goto free_and_return;
359         }
360
361         if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) {
362                 rc = LDAP_DECODING_ERROR;
363                 goto free_and_return;
364         }
365
366         rc = ldap_int_get_controls( ber, serverctrls );
367
368 free_and_return:
369         ber_free( ber, 0 );
370
371         if( retoidp != NULL ) {
372                 *retoidp = resoid;
373         } else {
374                 LDAP_FREE( resoid );
375         }
376
377         if( retdatap != NULL ) {
378                 *retdatap = resdata;
379         } else {
380                 ber_bvfree( resdata );
381         }
382
383         if( freeit ) {
384                 ldap_msgfree( res );
385         }
386
387         return LDAP_SUCCESS;
388 }