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