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 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 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 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