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