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