xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/extended.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: extended.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/libldap/extended.c,v 1.39.2.5 2009/01/22 00:00:54 kurt Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2009 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 
18 #include "portable.h"
19 
20 #include <stdio.h>
21 #include <ac/stdlib.h>
22 
23 #include <ac/socket.h>
24 #include <ac/string.h>
25 #include <ac/time.h>
26 
27 #include "ldap-int.h"
28 #include "ldap_log.h"
29 
30 /*
31  * LDAPv3 Extended Operation Request
32  *	ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
33  *		requestName      [0] LDAPOID,
34  *		requestValue     [1] OCTET STRING OPTIONAL
35  *	}
36  *
37  * LDAPv3 Extended Operation Response
38  *	ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
39  *		COMPONENTS OF LDAPResult,
40  *		responseName     [10] LDAPOID OPTIONAL,
41  *		response         [11] OCTET STRING OPTIONAL
42  *	}
43  *
44  * (Source RFC 4511)
45  */
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 || !res ) {
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 	rc = ber_scanf( ber, "{eAA" /*}*/, &errcode,
214 		&ld->ld_matched, &ld->ld_error );
215 
216 	if( rc == LBER_ERROR ) {
217 		ld->ld_errno = LDAP_DECODING_ERROR;
218 		ber_free( ber, 0 );
219 		return ld->ld_errno;
220 	}
221 
222 	resoid = NULL;
223 	resdata = NULL;
224 
225 	tag = ber_peek_tag( ber, &len );
226 
227 	if( tag == LDAP_TAG_REFERRAL ) {
228 		/* skip over referral */
229 		if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
230 			ld->ld_errno = LDAP_DECODING_ERROR;
231 			ber_free( ber, 0 );
232 			return ld->ld_errno;
233 		}
234 
235 		tag = ber_peek_tag( ber, &len );
236 	}
237 
238 	if( tag == LDAP_TAG_EXOP_RES_OID ) {
239 		/* we have a resoid */
240 		if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
241 			ld->ld_errno = LDAP_DECODING_ERROR;
242 			ber_free( ber, 0 );
243 			return ld->ld_errno;
244 		}
245 
246 		assert( resoid[ 0 ] != '\0' );
247 
248 		tag = ber_peek_tag( ber, &len );
249 	}
250 
251 	if( tag == LDAP_TAG_EXOP_RES_VALUE ) {
252 		/* we have a resdata */
253 		if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
254 			ld->ld_errno = LDAP_DECODING_ERROR;
255 			ber_free( ber, 0 );
256 			if( resoid != NULL ) LDAP_FREE( resoid );
257 			return ld->ld_errno;
258 		}
259 	}
260 
261 	ber_free( ber, 0 );
262 
263 	if( retoidp != NULL ) {
264 		*retoidp = resoid;
265 	} else {
266 		LDAP_FREE( resoid );
267 	}
268 
269 	if( retdatap != NULL ) {
270 		*retdatap = resdata;
271 	} else {
272 		ber_bvfree( resdata );
273 	}
274 
275 	ld->ld_errno = errcode;
276 
277 	if( freeit ) {
278 		ldap_msgfree( res );
279 	}
280 
281 	return LDAP_SUCCESS;
282 }
283 
284 
285 /* Parse an extended partial */
286 int
287 ldap_parse_intermediate (
288 	LDAP			*ld,
289 	LDAPMessage		*res,
290 	char			**retoidp,
291 	struct berval	**retdatap,
292 	LDAPControl		***serverctrls,
293 	int				freeit )
294 {
295 	BerElement *ber;
296 	ber_tag_t tag;
297 	ber_len_t len;
298 	struct berval *resdata;
299 	char *resoid;
300 
301 	assert( ld != NULL );
302 	assert( LDAP_VALID( ld ) );
303 	assert( res != NULL );
304 
305 	Debug( LDAP_DEBUG_TRACE, "ldap_parse_intermediate\n", 0, 0, 0 );
306 
307 	if( ld->ld_version < LDAP_VERSION3 ) {
308 		ld->ld_errno = LDAP_NOT_SUPPORTED;
309 		return ld->ld_errno;
310 	}
311 
312 	if( res->lm_msgtype != LDAP_RES_INTERMEDIATE ) {
313 		ld->ld_errno = LDAP_PARAM_ERROR;
314 		return ld->ld_errno;
315 	}
316 
317 	if( retoidp != NULL ) *retoidp = NULL;
318 	if( retdatap != NULL ) *retdatap = NULL;
319 	if( serverctrls != NULL ) *serverctrls = NULL;
320 
321 	ber = ber_dup( res->lm_ber );
322 
323 	if ( ber == NULL ) {
324 		ld->ld_errno = LDAP_NO_MEMORY;
325 		return ld->ld_errno;
326 	}
327 
328 	tag = ber_scanf( ber, "{" /*}*/ );
329 
330 	if( tag == LBER_ERROR ) {
331 		ld->ld_errno = LDAP_DECODING_ERROR;
332 		ber_free( ber, 0 );
333 		return ld->ld_errno;
334 	}
335 
336 	resoid = NULL;
337 	resdata = NULL;
338 
339 	tag = ber_peek_tag( ber, &len );
340 
341 	/*
342 	 * NOTE: accept intermediate and extended response tag values
343 	 * as older versions of slapd(8) incorrectly used extended
344 	 * response tags.
345 	 * Should be removed when 2.2 is moved to Historic.
346 	 */
347 	if( tag == LDAP_TAG_IM_RES_OID || tag == LDAP_TAG_EXOP_RES_OID ) {
348 		/* we have a resoid */
349 		if( ber_scanf( ber, "a", &resoid ) == LBER_ERROR ) {
350 			ld->ld_errno = LDAP_DECODING_ERROR;
351 			ber_free( ber, 0 );
352 			return ld->ld_errno;
353 		}
354 
355 		assert( resoid[ 0 ] != '\0' );
356 
357 		tag = ber_peek_tag( ber, &len );
358 	}
359 
360 	if( tag == LDAP_TAG_IM_RES_VALUE || tag == LDAP_TAG_EXOP_RES_VALUE ) {
361 		/* we have a resdata */
362 		if( ber_scanf( ber, "O", &resdata ) == LBER_ERROR ) {
363 			ld->ld_errno = LDAP_DECODING_ERROR;
364 			ber_free( ber, 0 );
365 			if( resoid != NULL ) LDAP_FREE( resoid );
366 			return ld->ld_errno;
367 		}
368 	}
369 
370 	if ( serverctrls == NULL ) {
371 		ld->ld_errno = LDAP_SUCCESS;
372 		goto free_and_return;
373 	}
374 
375 	if ( ber_scanf( ber, /*{*/ "}" ) == LBER_ERROR ) {
376 		ld->ld_errno = LDAP_DECODING_ERROR;
377 		goto free_and_return;
378 	}
379 
380 	ld->ld_errno = ldap_pvt_get_controls( ber, serverctrls );
381 
382 free_and_return:
383 	ber_free( ber, 0 );
384 
385 	if( retoidp != NULL ) {
386 		*retoidp = resoid;
387 	} else {
388 		LDAP_FREE( resoid );
389 	}
390 
391 	if( retdatap != NULL ) {
392 		*retdatap = resdata;
393 	} else {
394 		ber_bvfree( resdata );
395 	}
396 
397 	if( freeit ) {
398 		ldap_msgfree( res );
399 	}
400 
401 	return ld->ld_errno;
402 }
403 
404