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