]> git.sur5r.net Git - openldap/blob - libraries/libldap/extended.c
Happy new year!
[openldap] / libraries / libldap / extended.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 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         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
61
62         assert( ld != NULL );
63         assert( LDAP_VALID( ld ) );
64         assert( reqoid != NULL && *reqoid != '\0' );
65         assert( msgidp != NULL );
66
67         /* must be version 3 (or greater) */
68         if ( ld->ld_version < LDAP_VERSION3 ) {
69                 ld->ld_errno = LDAP_NOT_SUPPORTED;
70                 return( ld->ld_errno );
71         }
72
73         /* create a message to send */
74         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
75                 ld->ld_errno = LDAP_NO_MEMORY;
76                 return( ld->ld_errno );
77         }
78
79         LDAP_NEXT_MSGID( ld, id );
80         if ( reqdata != NULL ) {
81                 rc = ber_printf( ber, "{it{tstON}", /* '}' */
82                         id, LDAP_REQ_EXTENDED,
83                         LDAP_TAG_EXOP_REQ_OID, reqoid,
84                         LDAP_TAG_EXOP_REQ_VALUE, reqdata );
85
86         } else {
87                 rc = ber_printf( ber, "{it{tsN}", /* '}' */
88                         id, LDAP_REQ_EXTENDED,
89                         LDAP_TAG_EXOP_REQ_OID, reqoid );
90         }
91
92         if( rc == -1 ) {
93                 ld->ld_errno = LDAP_ENCODING_ERROR;
94                 ber_free( ber, 1 );
95                 return( ld->ld_errno );
96         }
97
98         /* Put Server Controls */
99         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
100                 ber_free( ber, 1 );
101                 return ld->ld_errno;
102         }
103
104         if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
105                 ld->ld_errno = LDAP_ENCODING_ERROR;
106                 ber_free( ber, 1 );
107                 return( ld->ld_errno );
108         }
109
110         /* send the message */
111         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber, id );
112
113         return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS );
114 }
115
116 int
117 ldap_extended_operation_s(
118         LDAP                    *ld,
119         LDAP_CONST char *reqoid,
120         struct berval   *reqdata,
121         LDAPControl             **sctrls,
122         LDAPControl             **cctrls,
123         char                    **retoidp,
124         struct berval   **retdatap )
125 {
126     int     rc;
127     int     msgid;
128     LDAPMessage *res;
129
130         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 );
131
132         assert( ld != NULL );
133         assert( LDAP_VALID( ld ) );
134         assert( reqoid != NULL && *reqoid != '\0' );
135
136     rc = ldap_extended_operation( ld, reqoid, reqdata,
137                 sctrls, cctrls, &msgid );
138         
139     if ( rc != LDAP_SUCCESS ) {
140         return( rc );
141         }
142  
143     if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res ) == -1 ) {
144         return( ld->ld_errno );
145         }
146
147         if ( retoidp != NULL ) *retoidp = NULL;
148         if ( retdatap != NULL ) *retdatap = NULL;
149
150         rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 );
151
152         if( rc != LDAP_SUCCESS ) {
153                 ldap_msgfree( res );
154                 return rc;
155         }
156
157     return( ldap_result2error( ld, res, 1 ) );
158 }
159
160 /* Parse an extended result */
161 int
162 ldap_parse_extended_result (
163         LDAP                    *ld,
164         LDAPMessage             *res,
165         char                    **retoidp,
166         struct berval   **retdatap,
167         int                             freeit )
168 {
169         BerElement *ber;
170         ber_tag_t rc;
171         ber_tag_t tag;
172         ber_len_t len;
173         struct berval *resdata;
174         ber_int_t errcode;
175         char *resoid;
176
177         assert( ld != NULL );
178         assert( LDAP_VALID( ld ) );
179         assert( res != NULL );
180
181         Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
182
183         if( ld->ld_version < LDAP_VERSION3 ) {
184                 ld->ld_errno = LDAP_NOT_SUPPORTED;
185                 return ld->ld_errno;
186         }
187
188         if( res->lm_msgtype != LDAP_RES_EXTENDED ) {
189                 ld->ld_errno = LDAP_PARAM_ERROR;
190                 return ld->ld_errno;
191         }
192
193         if( retoidp != NULL ) *retoidp = NULL;
194         if( retdatap != NULL ) *retdatap = NULL;
195
196         if ( ld->ld_error ) {
197                 LDAP_FREE( ld->ld_error );
198                 ld->ld_error = NULL;
199         }
200
201         if ( ld->ld_matched ) {
202                 LDAP_FREE( ld->ld_matched );
203                 ld->ld_matched = NULL;
204         }
205
206         ber = ber_dup( res->lm_ber );
207
208         if ( ber == NULL ) {
209                 ld->ld_errno = LDAP_NO_MEMORY;
210                 return ld->ld_errno;
211         }
212
213 #ifdef LDAP_NULL_IS_NULL
214         rc = ber_scanf( ber, "{eAA" /*}*/, &errcode,
215                 &ld->ld_matched, &ld->ld_error );
216 #else /* ! LDAP_NULL_IS_NULL */
217         rc = ber_scanf( ber, "{eaa" /*}*/, &errcode,
218                 &ld->ld_matched, &ld->ld_error );
219 #endif /* ! LDAP_NULL_IS_NULL */
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 #ifdef LDAP_NULL_IS_NULL
252                 assert( resoid[ 0 ] != '\0' );
253 #endif /* LDAP_NULL_IS_NULL */
254
255                 tag = ber_peek_tag( ber, &len );
256         }
257
258         if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
259                 /* we have a resdata */
260                 if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
261                         ld->ld_errno = LDAP_DECODING_ERROR;
262                         ber_free( ber, 0 );
263                         if( resoid != NULL ) LDAP_FREE( resoid );
264                         return ld->ld_errno;
265                 }
266         }
267
268         ber_free( ber, 0 );
269
270         if( retoidp != NULL ) {
271                 *retoidp = resoid;
272         } else {
273                 LDAP_FREE( resoid );
274         }
275
276         if( retdatap != NULL ) {
277                 *retdatap = resdata;
278         } else {
279                 ber_bvfree( resdata );
280         }
281
282         ld->ld_errno = errcode;
283
284         if( freeit ) {
285                 ldap_msgfree( res );
286         }
287
288         return LDAP_SUCCESS;
289 }
290
291
292 /* Parse an extended partial */
293 int
294 ldap_parse_intermediate (
295         LDAP                    *ld,
296         LDAPMessage             *res,
297         char                    **retoidp,
298         struct berval   **retdatap,
299         LDAPControl             ***serverctrls,
300         int                             freeit )
301 {
302         BerElement *ber;
303         ber_tag_t rc;
304         ber_tag_t tag;
305         ber_len_t len;
306         struct berval *resdata;
307         char *resoid;
308
309         assert( ld != NULL );
310         assert( LDAP_VALID( ld ) );
311         assert( res != NULL );
312
313         Debug( LDAP_DEBUG_TRACE, "ldap_parse_intermediate\n", 0, 0, 0 );
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         /*
349          * NOTE: accept intermediate and extended response tag values
350          * as older versions of slapd(8) incorrectly used extended
351          * response tags.
352          * Should be removed when 2.2 is moved to Historic.
353          */
354         if( tag == LDAP_TAG_IM_RES_OID || tag == LDAP_TAG_EXOP_RES_OID ) {
355                 /* we have a resoid */
356                 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
357                         ld->ld_errno = LDAP_DECODING_ERROR;
358                         ber_free( ber, 0 );
359                         return ld->ld_errno;
360                 }
361
362 #ifdef LDAP_NULL_IS_NULL
363                 assert( resoid[ 0 ] != '\0' );
364 #endif /* LDAP_NULL_IS_NULL */
365
366                 tag = ber_peek_tag( ber, &len );
367         }
368
369         if( tag == LDAP_TAG_IM_RES_VALUE || tag == LDAP_TAG_EXOP_RES_VALUE ) {
370                 /* we have a resdata */
371                 if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
372                         ld->ld_errno = LDAP_DECODING_ERROR;
373                         ber_free( ber, 0 );
374                         if( resoid != NULL ) LDAP_FREE( resoid );
375                         return ld->ld_errno;
376                 }
377         }
378
379         if ( serverctrls == NULL ) {
380                 rc = LDAP_SUCCESS;
381                 goto free_and_return;
382         }
383
384         if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) {
385                 rc = LDAP_DECODING_ERROR;
386                 goto free_and_return;
387         }
388
389         rc = ldap_pvt_get_controls( ber, serverctrls );
390
391 free_and_return:
392         ber_free( ber, 0 );
393
394         if( retoidp != NULL ) {
395                 *retoidp = resoid;
396         } else {
397                 LDAP_FREE( resoid );
398         }
399
400         if( retdatap != NULL ) {
401                 *retdatap = resdata;
402         } else {
403                 ber_bvfree( resdata );
404         }
405
406         if( freeit ) {
407                 ldap_msgfree( res );
408         }
409
410         return LDAP_SUCCESS;
411 }
412