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