1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  *
3  * The contents of this file are subject to the Netscape Public License
4  * Version 1.0 (the "NPL"); you may not use this file except in
5  * compliance with the NPL.  You may obtain a copy of the NPL at
6  * http://www.mozilla.org/NPL/
7  *
8  * Software distributed under the NPL is distributed on an "AS IS" basis,
9  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
10  * for the specific language governing rights and limitations under the
11  * NPL.
12  *
13  * The Initial Developer of this code under the NPL is Netscape
14  * Communications Corporation.  Portions created by Netscape are
15  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
16  * Reserved.
17  */
18 #include "ldap-int.h"
19 
20 /*
21  * ldap_extended_operation - initiate an arbitrary ldapv3 extended operation.
22  * the oid and data of the extended operation are supplied. Returns an
23  * LDAP error code.
24  *
25  * Example:
26  *	struct berval	exdata;
27  *	char		*exoid;
28  *	int		err, msgid;
29  *	... fill in oid and data ...
30  *	err = ldap_extended_operation( ld, exoid, &exdata, NULL, NULL, &msgid );
31  */
32 
33 int
34 LDAP_CALL
ldap_extended_operation(LDAP * ld,const char * exoid,const struct berval * exdata,LDAPControl ** serverctrls,LDAPControl ** clientctrls,int * msgidp)35 ldap_extended_operation(
36     LDAP		*ld,
37     const char		*exoid,
38     const struct berval	*exdata,
39     LDAPControl		**serverctrls,
40     LDAPControl		**clientctrls,
41     int			*msgidp
42 )
43 {
44 	BerElement	*ber;
45 	int		rc, msgid;
46 
47 	/*
48 	 * the ldapv3 extended operation request looks like this:
49 	 *
50 	 *	ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
51 	 *		requestName	LDAPOID,
52 	 *		requestValue	OCTET STRING
53 	 *	}
54 	 *
55 	 * all wrapped up in an LDAPMessage sequence.
56 	 */
57 
58 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_extended_operation\n", 0, 0, 0 );
59 
60 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
61 		return( LDAP_PARAM_ERROR );
62 	}
63 
64 
65 	/* only ldapv3 or higher can do extended operations */
66 	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
67 		rc = LDAP_NOT_SUPPORTED;
68 		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
69 		return( rc );
70 	}
71 
72 	if ( msgidp == NULL || exoid == NULL || *exoid == '\0' ||
73 			exdata == NULL || exdata->bv_val == NULL ) {
74 		rc = LDAP_PARAM_ERROR;
75 		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
76 		return( rc );
77 	}
78 
79 	LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
80 	msgid = ++ld->ld_msgid;
81 	LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
82 
83 #if 0
84 	if ( ld->ld_cache_on && ld->ld_cache_extendedop != NULL ) {
85 		LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
86 		if ( (rc = (ld->ld_cache_extendedop)( ld, msgid,
87 		    LDAP_REQ_EXTENDED, exoid, cred )) != 0 ) {
88 			LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
89 			return( rc );
90 		}
91 		LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
92 	}
93 #endif
94 
95 	/* create a message to send */
96 	if (( rc = nsldapi_alloc_ber_with_options( ld, &ber ))
97 	    != LDAP_SUCCESS ) {
98 		return( rc );
99 	}
100 
101 	/* fill it in */
102 	if ( ber_printf( ber, "{it{tsto}", msgid, LDAP_REQ_EXTENDED,
103 	    LDAP_TAG_EXOP_REQ_OID, exoid, LDAP_TAG_EXOP_REQ_VALUE,
104 	    exdata->bv_val, (int)exdata->bv_len /* XXX lossy cast */ ) == -1 ) {
105 		rc = LDAP_ENCODING_ERROR;
106 		LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
107 		ber_free( ber, 1 );
108 		return( rc );
109 	}
110 
111 	if (( rc = nsldapi_put_controls( ld, serverctrls, 1, ber ))
112 	    != LDAP_SUCCESS ) {
113 		ber_free( ber, 1 );
114 		return( rc );
115 	}
116 
117 	/* send the message */
118 	rc = nsldapi_send_initial_request( ld, msgid, LDAP_REQ_EXTENDED, NULL,
119 		ber );
120 	*msgidp = rc;
121 	return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
122 }
123 
124 
125 /*
126  * ldap_extended_operation_s - perform an arbitrary ldapv3 extended operation.
127  * the oid and data of the extended operation are supplied. LDAP_SUCCESS
128  * is returned upon success, the ldap error code otherwise.
129  *
130  * Example:
131  *	struct berval	exdata, exretval;
132  *	char		*exoid;
133  *	int		rc;
134  *	... fill in oid and data ...
135  *	rc = ldap_extended_operation_s( ld, exoid, &exdata, &exretval );
136  */
137 int
138 LDAP_CALL
ldap_extended_operation_s(LDAP * ld,const char * requestoid,const struct berval * requestdata,LDAPControl ** serverctrls,LDAPControl ** clientctrls,char ** retoidp,struct berval ** retdatap)139 ldap_extended_operation_s(
140     LDAP		*ld,
141     const char		*requestoid,
142     const struct berval	*requestdata,
143     LDAPControl		**serverctrls,
144     LDAPControl		**clientctrls,
145     char		**retoidp,
146     struct berval	**retdatap
147 )
148 {
149 	int		err, msgid;
150 	LDAPMessage	*result;
151 
152 	if (( err = ldap_extended_operation( ld, requestoid, requestdata,
153 	    serverctrls, clientctrls, &msgid )) != LDAP_SUCCESS ) {
154 		return( err );
155 	}
156 
157 	if ( ldap_result( ld, msgid, 1, (struct timeval *) 0, &result )
158 	    == -1 ) {
159 		return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
160 	}
161 
162 	if (( err = ldap_parse_extended_result( ld, result, retoidp, retdatap,
163 		0 )) != LDAP_SUCCESS ) {
164 	    ldap_msgfree( result );
165 	    return( err );
166 	}
167 
168 	return( ldap_result2error( ld, result, 1 ) );
169 }
170 
171 
172 /*
173  * Pull the oid returned by the server and the data out of an extended
174  * operation result.  Return an LDAP error code.
175  */
176 int
177 LDAP_CALL
ldap_parse_extended_result(LDAP * ld,LDAPMessage * res,char ** retoidp,struct berval ** retdatap,int freeit)178 ldap_parse_extended_result(
179     LDAP		*ld,
180     LDAPMessage		*res,
181     char		**retoidp,	/* may be NULL */
182     struct berval	**retdatap,	/* may be NULL */
183     int			freeit
184 )
185 {
186 	struct berelement	ber;
187 	ber_len_t		len;
188 	ber_int_t		err;
189 	char			*m, *e, *roid;
190 	struct berval		*rdata;
191 
192 	LDAPDebug( LDAP_DEBUG_TRACE, "ldap_parse_extended_result\n", 0, 0, 0 );
193 
194 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
195 		return( LDAP_PARAM_ERROR );
196 	}
197 
198         if ( !NSLDAPI_VALID_LDAPMESSAGE_EXRESULT_POINTER( res )) {
199 		return( LDAP_PARAM_ERROR );
200 	}
201 
202 	m = e = NULL;
203 	ber = *(res->lm_ber);
204 	if ( NSLDAPI_LDAP_VERSION( ld ) < LDAP_VERSION3 ) {
205 		LDAP_SET_LDERRNO( ld, LDAP_NOT_SUPPORTED, NULL, NULL );
206 		return( LDAP_NOT_SUPPORTED );
207 	}
208 
209 	if ( ber_scanf( &ber, "{iaa", &err, &m, &e ) == LBER_ERROR ) {
210 		goto decoding_error;
211 	}
212 	roid = NULL;
213 	if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_EXOP_RES_OID ) {
214 		if ( ber_scanf( &ber, "a", &roid ) == LBER_ERROR ) {
215 			goto decoding_error;
216 		}
217 	}
218 	if ( retoidp != NULL ) {
219 		*retoidp = roid;
220 	} else if ( roid != NULL ) {
221 		NSLDAPI_FREE( roid );
222 	}
223 
224 	rdata = NULL;
225 	if ( ber_peek_tag( &ber, &len ) == LDAP_TAG_EXOP_RES_VALUE ) {
226 		if ( ber_scanf( &ber, "O", &rdata ) == LBER_ERROR ) {
227 			goto decoding_error;
228 		}
229 	}
230 	if ( retdatap != NULL ) {
231 		*retdatap = rdata;
232 	} else if ( rdata != NULL ) {
233 		ber_bvfree( rdata );
234 	}
235 
236 	LDAP_SET_LDERRNO( ld, err, m, e );
237 
238 	if ( freeit ) {
239 		ldap_msgfree( res );
240 	}
241 
242 	return( LDAP_SUCCESS );
243 
244 decoding_error:;
245 	LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
246 	return( LDAP_DECODING_ERROR );
247 }
248