]> git.sur5r.net Git - openldap/blob - libraries/libldap/extended.c
a8ca02b29ef469a8ebdb3df7387c5ee35520f735
[openldap] / libraries / libldap / extended.c
1 /*
2  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5
6 /*
7  * LDAPv3 Extended Operation Request
8  *      ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
9  *              requestName      [0] LDAPOID,
10  *              requestValue     [1] OCTET STRING OPTIONAL
11  *      }
12  *
13  * LDAPv3 Extended Operation Response
14  *      ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
15  *              COMPONENTS OF LDAPResult,
16  *              responseName     [10] LDAPOID OPTIONAL,
17  *              response         [11] OCTET STRING OPTIONAL
18  *      }
19  *
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/stdlib.h>
26
27 #include <ac/socket.h>
28 #include <ac/string.h>
29 #include <ac/time.h>
30
31 #include "ldap-int.h"
32
33 int
34 ldap_extended_operation(
35         LDAP                    *ld,
36         LDAP_CONST char *reqoid,
37         struct berval   *reqdata,
38         LDAPControl             **sctrls,
39         LDAPControl             **cctrls,
40         int                             *msgidp )
41 {
42         BerElement *ber;
43         int rc;
44
45         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
46
47         assert( ld != NULL );
48         assert( LDAP_VALID( ld ) );
49         assert( reqoid != NULL || *reqoid == '\0' );
50         assert( msgidp != NULL );
51
52         /* must be version 3 (or greater) */
53         if ( ld->ld_version < LDAP_VERSION3 ) {
54                 ld->ld_errno = LDAP_NOT_SUPPORTED;
55                 return( ld->ld_errno );
56         }
57
58         if( reqoid == NULL || *reqoid == '\0' || msgidp == NULL ) {
59                 ld->ld_errno = LDAP_PARAM_ERROR;
60                 return( ld->ld_errno );
61         }
62
63         /* create a message to send */
64         if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
65                 ld->ld_errno = LDAP_NO_MEMORY;
66                 return( ld->ld_errno );
67         }
68
69         if ( reqdata != NULL ) {
70                 rc = ber_printf( ber, "{it{tstO}", /* '}' */
71                         ++ld->ld_msgid, LDAP_REQ_EXTENDED,
72                         LDAP_TAG_EXOP_REQ_OID, reqoid,
73                         LDAP_TAG_EXOP_REQ_VALUE, reqdata );
74
75         } else {
76                 rc = ber_printf( ber, "{it{ts}", /* '}' */
77                         ++ld->ld_msgid, LDAP_REQ_EXTENDED,
78                         LDAP_TAG_EXOP_REQ_OID, reqoid );
79         }
80
81         if( rc == -1 ) {
82                 ld->ld_errno = LDAP_ENCODING_ERROR;
83                 ber_free( ber, 1 );
84                 return( ld->ld_errno );
85         }
86
87         /* Put Server Controls */
88         if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
89                 ber_free( ber, 1 );
90                 return ld->ld_errno;
91         }
92
93         if ( ber_printf( ber, /*{*/ "}" ) == -1 ) {
94                 ld->ld_errno = LDAP_ENCODING_ERROR;
95                 ber_free( ber, 1 );
96                 return( ld->ld_errno );
97         }
98
99         /* send the message */
100         *msgidp = ldap_send_initial_request( ld, LDAP_REQ_EXTENDED, NULL, ber );
101
102         return( *msgidp < 0 ? ld->ld_errno : LDAP_SUCCESS );
103 }
104
105 int
106 ldap_extended_operation_s(
107         LDAP                    *ld,
108         LDAP_CONST char *reqoid,
109         struct berval   *reqdata,
110         LDAPControl             **sctrls,
111         LDAPControl             **cctrls,
112         char                    **retoidp,
113         struct berval   **retdatap )
114 {
115     int     rc;
116     int     msgid;
117     LDAPMessage *res;
118
119         Debug( LDAP_DEBUG_TRACE, "ldap_extended_operation_s\n", 0, 0, 0 );
120
121         assert( ld != NULL );
122         assert( LDAP_VALID( ld ) );
123         assert( reqoid != NULL || *reqoid == '\0' );
124         assert( retoidp != NULL || retdatap != NULL );
125
126         if( retoidp == NULL || retdatap == NULL ) {
127                 ld->ld_errno = LDAP_PARAM_ERROR;
128                 return( ld->ld_errno );
129         }
130
131     rc = ldap_extended_operation( ld, reqoid, reqdata,
132                 sctrls, cctrls, &msgid );
133         
134     if ( rc != LDAP_SUCCESS ) {
135         return( rc );
136         }
137  
138     if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, &res ) == -1 ) {
139         return( ld->ld_errno );
140         }
141
142         *retoidp = NULL;
143         *retdatap = NULL;
144
145         rc = ldap_parse_extended_result( ld, res, retoidp, retdatap, 0 );
146
147         if( rc != LDAP_SUCCESS ) {
148                 ldap_msgfree( res );
149                 return rc;
150         }
151
152     return( ldap_result2error( ld, res, 1 ) );
153 }
154
155 /* Parse an extended result */
156 int
157 ldap_parse_extended_result (
158         LDAP                    *ld,
159         LDAPMessage             *res,
160         char                    **retoidp,
161         struct berval   **retdatap,
162         int                             freeit )
163 {
164         BerElement *ber;
165         ber_tag_t rc;
166         ber_tag_t tag;
167         ber_len_t len;
168         struct berval *resdata;
169         ber_int_t errcode;
170         char *resoid;
171
172         assert( ld != NULL );
173         assert( LDAP_VALID( ld ) );
174         assert( res != NULL );
175
176         Debug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
177
178         if( ld->ld_version < LDAP_VERSION3 ) {
179                 ld->ld_errno = LDAP_NOT_SUPPORTED;
180                 return ld->ld_errno;
181         }
182
183         if( res->lm_msgtype == LDAP_RES_EXTENDED ) {
184                 ld->ld_errno = LDAP_PARAM_ERROR;
185                 return ld->ld_errno;
186         }
187
188         if( retoidp != NULL ) *retoidp = NULL;
189         if( retdatap != NULL ) *retdatap = NULL;
190
191         ber = ber_dup( res->lm_ber );
192
193         if ( ld->ld_error ) {
194                 LDAP_FREE( ld->ld_error );
195                 ld->ld_error = NULL;
196         }
197
198         if ( ld->ld_matched ) {
199                 LDAP_FREE( ld->ld_matched );
200                 ld->ld_matched = NULL;
201         }
202
203         rc = ber_scanf( ber, "{iaa" /*}*/, &errcode,
204                 &ld->ld_matched, &ld->ld_matched );
205
206         if( rc == LBER_ERROR ) {
207                 ld->ld_errno = LDAP_DECODING_ERROR;
208                 ber_free( ber, 0 );
209                 return ld->ld_errno;
210         }
211
212         resoid = NULL;
213         resdata = NULL;
214
215         tag = ber_peek_tag( ber, &len );
216
217         if( tag == LDAP_TAG_REFERRAL ) {
218                 /* skip over referral */
219                 tag = ber_scanf( ber, "x" );
220
221                 if( tag != LBER_ERROR ) {
222                         tag = ber_peek_tag( ber, &len );
223                 }
224         }
225
226         if( tag == LDAP_TAG_EXOP_RES_OID ) {
227                 /* we have a resoid */
228                 if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
229                         ld->ld_errno = LDAP_DECODING_ERROR;
230                         ber_free( ber, 0 );
231                         return ld->ld_errno;
232                 }
233
234                 tag = ber_peek_tag( ber, &len );
235         }
236
237         if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
238                 /* we have a resdata */
239                 if( ber_scanf( ber, "O", &resoid ) == LBER_ERROR ) {
240                         ld->ld_errno = LDAP_DECODING_ERROR;
241                         ber_free( ber, 0 );
242                         if( resoid != NULL ) LDAP_FREE( resoid );
243                         return ld->ld_errno;
244                 }
245         }
246
247         if( retoidp != NULL ) {
248                 *retoidp = resoid;
249         } else {
250                 LDAP_FREE( resoid );
251         }
252
253         if( retdatap != NULL ) {
254                 *retdatap = resdata;
255         } else {
256                 ber_bvfree( resdata );
257         }
258
259         ld->ld_errno = errcode;
260
261         if( freeit ) {
262                 ldap_msgfree( res );
263         }
264
265         return LDAP_SUCCESS;
266 }