1 /*
2  * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * The contents of this file are subject to the Netscape Public
8  * License Version 1.1 (the "License"); you may not use this file
9  * except in compliance with the License. You may obtain a copy of
10  * the License at http://www.mozilla.org/NPL/
11  *
12  * Software distributed under the License is distributed on an "AS
13  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14  * implied. See the License for the specific language governing
15  * rights and limitations under the License.
16  *
17  * The Original Code is Mozilla Communicator client code, released
18  * March 31, 1998.
19  *
20  * The Initial Developer of the Original Code is Netscape
21  * Communications Corporation. Portions created by Netscape are
22  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
23  * Rights Reserved.
24  *
25  * Contributor(s):
26  */
27 #include "ldap-int.h"
28 
29 #define LDAP_GET_BITOPT( ld, bit ) \
30 	((ld)->ld_options & bit ) != 0 ? 1 : 0
31 
32 static int nsldapi_get_api_info( LDAPAPIInfo *aip );
33 static int nsldapi_get_feature_info( LDAPAPIFeatureInfo *fip );
34 
35 
36 int
37 LDAP_CALL
ldap_get_option(LDAP * ld,int option,void * optdata)38 ldap_get_option( LDAP *ld, int option, void *optdata )
39 {
40 	int		rc = 0;
41 
42 	if ( !nsldapi_initialized ) {
43 		nsldapi_initialize_defaults();
44 	}
45 
46     /*
47      * optdata MUST be a valid pointer...
48      */
49     if (NULL == optdata)
50     {
51         return(LDAP_PARAM_ERROR);
52     }
53 	/*
54 	 * process global options (not associated with an LDAP session handle)
55 	 */
56 	if ( option == LDAP_OPT_MEMALLOC_FN_PTRS ) {
57 		/* struct copy */
58 		*((struct ldap_memalloc_fns *)optdata) = nsldapi_memalloc_fns;
59 		return( 0 );
60 	}
61 
62 	if ( option == LDAP_OPT_API_INFO ) {
63 		rc = nsldapi_get_api_info( (LDAPAPIInfo *)optdata );
64 		if ( rc != LDAP_SUCCESS ) {
65 			if ( ld != NULL ) {
66 				LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
67 			}
68 			return( -1 );
69 		}
70 		return( 0 );
71 	}
72     /*
73      * LDAP_OPT_DEBUG_LEVEL is global
74      */
75     if (LDAP_OPT_DEBUG_LEVEL == option)
76     {
77 #ifdef LDAP_DEBUG
78         *((int *) optdata) = ldap_debug;
79 #endif /* LDAP_DEBUG */
80         return ( 0 );
81     }
82 
83 	/*
84 	 * if ld is NULL, arrange to return options from our default settings
85 	 */
86 	if ( ld == NULL ) {
87 		ld = &nsldapi_ld_defaults;
88 	}
89 
90 	if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
91 		return( -1 );	/* punt */
92 	}
93 
94 
95 	if (ld != &nsldapi_ld_defaults)
96 		LDAP_MUTEX_LOCK( ld, LDAP_OPTION_LOCK );
97 	switch( option ) {
98 #ifdef LDAP_DNS
99 	case LDAP_OPT_DNS:
100 		*((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_DNS );
101 		break;
102 #endif
103 
104 	case LDAP_OPT_REFERRALS:
105 		*((int *) optdata) =
106 		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_REFERRALS );
107 		break;
108 
109 #ifdef LDAP_SSLIO_HOOKS
110 	case LDAP_OPT_SSL:
111 		*((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_SSL );
112 		break;
113 #endif
114 	case LDAP_OPT_RESTART:
115 		*((int *) optdata) = LDAP_GET_BITOPT( ld, LDAP_BITOPT_RESTART );
116 		break;
117 
118 	case LDAP_OPT_RECONNECT:
119 		*((int *) optdata) =
120 		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_RECONNECT );
121 		break;
122 
123 #ifdef LDAP_ASYNC_IO
124 	case LDAP_OPT_ASYNC_CONNECT:
125 		*((int *) optdata) =
126 		    LDAP_GET_BITOPT( ld, LDAP_BITOPT_ASYNC );
127 		break;
128 #endif /* LDAP_ASYNC_IO */
129 
130 	/* stuff in the sockbuf */
131         case LDAP_X_OPT_SOCKBUF:
132                 *((Sockbuf **) optdata) = ld->ld_sbp;
133                 break;
134 	case LDAP_OPT_DESC:
135 		if ( ber_sockbuf_get_option( ld->ld_sbp,
136 		    LBER_SOCKBUF_OPT_DESC, optdata ) != 0 ) {
137 			LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
138 			rc = -1;
139 		}
140 		break;
141 
142 	/* fields in the LDAP structure */
143 	case LDAP_OPT_DEREF:
144 		*((int *) optdata) = ld->ld_deref;
145 		break;
146 	case LDAP_OPT_SIZELIMIT:
147 		*((int *) optdata) = ld->ld_sizelimit;
148                 break;
149 	case LDAP_OPT_TIMELIMIT:
150 		*((int *) optdata) = ld->ld_timelimit;
151                 break;
152 	case LDAP_OPT_REFERRAL_HOP_LIMIT:
153 		 *((int *) optdata) = ld->ld_refhoplimit;
154 		break;
155 	case LDAP_OPT_PROTOCOL_VERSION:
156 		 *((int *) optdata) = ld->ld_version;
157 		break;
158 	case LDAP_OPT_SERVER_CONTROLS:
159 		/* fall through */
160 	case LDAP_OPT_CLIENT_CONTROLS:
161 		*((LDAPControl ***)optdata) = NULL;
162 		/* nsldapi_dup_controls returns -1 and sets lderrno on error */
163 		rc = nsldapi_dup_controls( ld, (LDAPControl ***)optdata,
164 		    ( option == LDAP_OPT_SERVER_CONTROLS ) ?
165 		    ld->ld_servercontrols : ld->ld_clientcontrols );
166 		break;
167 
168 	/* rebind proc */
169 	case LDAP_OPT_REBIND_FN:
170 		*((LDAP_REBINDPROC_CALLBACK **) optdata) = ld->ld_rebind_fn;
171 		break;
172 	case LDAP_OPT_REBIND_ARG:
173 		*((void **) optdata) = ld->ld_rebind_arg;
174 		break;
175 
176 #ifdef LDAP_SSLIO_HOOKS
177 	/* i/o function pointers */
178 	case LDAP_OPT_IO_FN_PTRS:
179 		if ( ld->ld_io_fns_ptr == NULL ) {
180 			memset( optdata, 0, sizeof( struct ldap_io_fns ));
181 		} else {
182 			/* struct copy */
183 			*((struct ldap_io_fns *)optdata) = *(ld->ld_io_fns_ptr);
184 		}
185 		break;
186 
187 	/* extended i/o function pointers */
188 	case LDAP_X_OPT_EXTIO_FN_PTRS:
189 	  if ( ((struct ldap_x_ext_io_fns *) optdata)->lextiof_size == LDAP_X_EXTIO_FNS_SIZE_REV0) {
190 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_close = ld->ld_extclose_fn;
191 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_connect = ld->ld_extconnect_fn;
192 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_read = ld->ld_extread_fn;
193 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_write = ld->ld_extwrite_fn;
194 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_poll = ld->ld_extpoll_fn;
195 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_newhandle = ld->ld_extnewhandle_fn;
196 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_disposehandle = ld->ld_extdisposehandle_fn;
197 	    ((struct ldap_x_ext_io_fns_rev0 *) optdata)->lextiof_session_arg = ld->ld_ext_session_arg;
198 	  } else if ( ((struct ldap_x_ext_io_fns *) optdata)->lextiof_size ==
199 		      LDAP_X_EXTIO_FNS_SIZE ) {
200 	    /* struct copy */
201 	    *((struct ldap_x_ext_io_fns *) optdata) = ld->ld_ext_io_fns;
202 	  } else {
203 	    LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
204 	    rc = -1;
205 	  }
206 		break;
207 #endif /* LDAP_SSLIO_HOOKS */
208 
209 	/* thread function pointers */
210 	case LDAP_OPT_THREAD_FN_PTRS:
211 		/* struct copy */
212 		*((struct ldap_thread_fns *) optdata) = ld->ld_thread;
213 		break;
214 
215 	/* DNS function pointers */
216 	case LDAP_OPT_DNS_FN_PTRS:
217 		/* struct copy */
218 		*((struct ldap_dns_fns *) optdata) = ld->ld_dnsfn;
219 		break;
220 
221 	/* cache function pointers */
222 	case LDAP_OPT_CACHE_FN_PTRS:
223 		/* struct copy */
224 		*((struct ldap_cache_fns *) optdata) = ld->ld_cache;
225 		break;
226 	case LDAP_OPT_CACHE_STRATEGY:
227 		*((int *) optdata) = ld->ld_cache_strategy;
228 		break;
229 	case LDAP_OPT_CACHE_ENABLE:
230 		*((int *) optdata) = ld->ld_cache_on;
231 		break;
232 
233 	case LDAP_OPT_ERROR_NUMBER:
234 		*((int *) optdata) = LDAP_GET_LDERRNO( ld, NULL, NULL );
235 		break;
236 
237 	case LDAP_OPT_ERROR_STRING:
238 		(void)LDAP_GET_LDERRNO( ld, NULL, (char **)optdata );
239 		*((char **) optdata) = nsldapi_strdup( *((char **) optdata ));
240 		break;
241 
242 	case LDAP_OPT_MATCHED_DN:
243 		(void)LDAP_GET_LDERRNO( ld, (char **)optdata, NULL );
244 		*((char **) optdata) = nsldapi_strdup( *((char **) optdata ));
245 		break;
246 
247 	case LDAP_OPT_PREFERRED_LANGUAGE:
248 		if ( NULL != ld->ld_preferred_language ) {
249 			*((char **) optdata) =
250 			    nsldapi_strdup(ld->ld_preferred_language);
251 		} else {
252 			*((char **) optdata) = NULL;
253 		}
254 		break;
255 
256 	case LDAP_OPT_API_FEATURE_INFO:
257 		rc = nsldapi_get_feature_info( (LDAPAPIFeatureInfo *)optdata );
258 		if ( rc != LDAP_SUCCESS ) {
259 			LDAP_SET_LDERRNO( ld, rc, NULL, NULL );
260 			rc = -1;
261 		}
262 		break;
263 
264 	case LDAP_OPT_HOST_NAME:
265 		*((char **) optdata) = nsldapi_strdup( ld->ld_defhost );
266 		break;
267 
268         case LDAP_X_OPT_CONNECT_TIMEOUT:
269                 *((int *) optdata) = ld->ld_connect_timeout;
270                 break;
271 
272 #ifdef LDAP_SASLIO_HOOKS
273         /* SASL options */
274         case LDAP_OPT_X_SASL_MECH:
275                 *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_mech);
276                 break;
277         case LDAP_OPT_X_SASL_REALM:
278                 *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_realm);
279                 break;
280         case LDAP_OPT_X_SASL_AUTHCID:
281                 *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_authcid);
282                 break;
283         case LDAP_OPT_X_SASL_AUTHZID:
284                 *((char **) optdata) = nsldapi_strdup(ld->ld_def_sasl_authzid);
285                 break;
286         case LDAP_OPT_X_SASL_SSF:
287                 {
288                         int sc;
289                         sasl_ssf_t      *ssf;
290                         sasl_conn_t     *ctx;
291                         if( ld->ld_defconn == NULL ||
292                             ld->ld_defconn->lconn_sb == NULL ) {
293                                 return -1;
294                         }
295                         ctx = (sasl_conn_t *)(ld->ld_defconn->lconn_sb->sb_sasl_ctx);
296                         if ( ctx == NULL ) {
297                                 return -1;
298                         }
299                         sc = sasl_getprop( ctx, SASL_SSF, (const void **) &ssf );
300                         if ( sc != SASL_OK ) {
301                                 return -1;
302                         }
303                         *((sasl_ssf_t *) optdata) = *ssf;
304                 }
305                 break;
306         case LDAP_OPT_X_SASL_SSF_MIN:
307                 *((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.min_ssf;
308                 break;
309         case LDAP_OPT_X_SASL_SSF_MAX:
310                 *((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.max_ssf;
311                 break;
312         case LDAP_OPT_X_SASL_MAXBUFSIZE:
313                 *((sasl_ssf_t *) optdata) = ld->ld_sasl_secprops.maxbufsize;
314                 break;
315         case LDAP_OPT_X_SASL_SSF_EXTERNAL:
316         case LDAP_OPT_X_SASL_SECPROPS:
317                 /*
318                  * These options are write only.  Making these options
319                  * read/write would expose semi-private interfaces of libsasl
320                  * for which there are no cross platform/standardized
321                  * definitions.
322                  */
323                 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
324                 rc = -1;
325                 break;
326 #endif
327 
328 	default:
329 		LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
330 		rc = -1;
331 	}
332 	if (ld != &nsldapi_ld_defaults)
333 		LDAP_MUTEX_UNLOCK( ld, LDAP_OPTION_LOCK  );
334 	return( rc );
335 }
336 
337 
338 /*
339  * Table of extended API features we support.
340  * The first field is the version of the info. strcuture itself; we do not
341  * use the ones from this table so it is okay to leave as zero.
342  */
343 static LDAPAPIFeatureInfo nsldapi_extensions[] = {
344     { 0, "SERVER_SIDE_SORT",		LDAP_API_FEATURE_SERVER_SIDE_SORT },
345     { 0, "VIRTUAL_LIST_VIEW",		LDAP_API_FEATURE_VIRTUAL_LIST_VIEW },
346     { 0, "PERSISTENT_SEARCH",		LDAP_API_FEATURE_PERSISTENT_SEARCH },
347     { 0, "PROXY_AUTHORIZATION",		LDAP_API_FEATURE_PROXY_AUTHORIZATION },
348     { 0, "X_LDERRNO",			LDAP_API_FEATURE_X_LDERRNO },
349     { 0, "X_MEMCACHE",			LDAP_API_FEATURE_X_MEMCACHE },
350     { 0, "X_IO_FUNCTIONS",		LDAP_API_FEATURE_X_IO_FUNCTIONS },
351     { 0, "X_EXTIO_FUNCTIONS",		LDAP_API_FEATURE_X_EXTIO_FUNCTIONS },
352     { 0, "X_DNS_FUNCTIONS",		LDAP_API_FEATURE_X_DNS_FUNCTIONS },
353     { 0, "X_MEMALLOC_FUNCTIONS",	LDAP_API_FEATURE_X_MEMALLOC_FUNCTIONS },
354     { 0, "X_THREAD_FUNCTIONS",		LDAP_API_FEATURE_X_THREAD_FUNCTIONS },
355     { 0, "X_EXTHREAD_FUNCTIONS",	LDAP_API_FEATURE_X_EXTHREAD_FUNCTIONS },
356     { 0, "X_GETLANGVALUES",		LDAP_API_FEATURE_X_GETLANGVALUES },
357     { 0, "X_CLIENT_SIDE_SORT",		LDAP_API_FEATURE_X_CLIENT_SIDE_SORT },
358     { 0, "X_URL_FUNCTIONS",		LDAP_API_FEATURE_X_URL_FUNCTIONS },
359     { 0, "X_FILTER_FUNCTIONS",		LDAP_API_FEATURE_X_FILTER_FUNCTIONS },
360 };
361 
362 #define NSLDAPI_EXTENSIONS_COUNT	\
363 	(sizeof(nsldapi_extensions)/sizeof(LDAPAPIFeatureInfo))
364 
365 /*
366  * Retrieve information about this implementation of the LDAP API.
367  * Returns an LDAP error code.
368  */
369 static int
nsldapi_get_api_info(LDAPAPIInfo * aip)370 nsldapi_get_api_info( LDAPAPIInfo *aip )
371 {
372 	int	i;
373 
374 	if ( aip == NULL ) {
375 		return( LDAP_PARAM_ERROR );
376 	}
377 
378 	aip->ldapai_api_version = LDAP_API_VERSION;
379 
380 	if ( aip->ldapai_info_version != LDAP_API_INFO_VERSION ) {
381 		aip->ldapai_info_version = LDAP_API_INFO_VERSION;
382 		return( LDAP_PARAM_ERROR );
383 	}
384 
385 	aip->ldapai_protocol_version = LDAP_VERSION_MAX;
386 	aip->ldapai_vendor_version = LDAP_VENDOR_VERSION;
387 
388 	if (( aip->ldapai_vendor_name = nsldapi_strdup( LDAP_VENDOR_NAME ))
389 	    == NULL ) {
390 		return( LDAP_NO_MEMORY );
391 	}
392 
393 	if ( NSLDAPI_EXTENSIONS_COUNT < 1 ) {
394 		aip->ldapai_extensions = NULL;
395 	} else {
396 		if (( aip->ldapai_extensions = NSLDAPI_CALLOC(
397 		    NSLDAPI_EXTENSIONS_COUNT + 1, sizeof(char *))) == NULL ) {
398 			NSLDAPI_FREE( aip->ldapai_vendor_name );
399 			aip->ldapai_vendor_name = NULL;
400 			return( LDAP_NO_MEMORY );
401 		}
402 
403 		for ( i = 0; i < NSLDAPI_EXTENSIONS_COUNT; ++i ) {
404 			if (( aip->ldapai_extensions[i] = nsldapi_strdup(
405 			    nsldapi_extensions[i].ldapaif_name )) == NULL ) {
406 				ldap_value_free( aip->ldapai_extensions );
407 				NSLDAPI_FREE( aip->ldapai_vendor_name );
408 				aip->ldapai_extensions = NULL;
409 				aip->ldapai_vendor_name = NULL;
410 				return( LDAP_NO_MEMORY );
411 			}
412 		}
413 	}
414 
415 	return( LDAP_SUCCESS );
416 }
417 
418 
419 /*
420  * Retrieves information about a specific extended feature of the LDAP API/
421  * Returns an LDAP error code.
422  */
423 static int
nsldapi_get_feature_info(LDAPAPIFeatureInfo * fip)424 nsldapi_get_feature_info( LDAPAPIFeatureInfo *fip )
425 {
426 	int	i;
427 
428 	if ( fip == NULL || fip->ldapaif_name == NULL ) {
429 		return( LDAP_PARAM_ERROR );
430 	}
431 
432 	if ( fip->ldapaif_info_version != LDAP_FEATURE_INFO_VERSION ) {
433 		fip->ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
434 		return( LDAP_PARAM_ERROR );
435 	}
436 
437 	for ( i = 0; i < NSLDAPI_EXTENSIONS_COUNT; ++i ) {
438 		if ( strcmp( fip->ldapaif_name,
439 		    nsldapi_extensions[i].ldapaif_name ) == 0 ) {
440 			fip->ldapaif_version =
441 			    nsldapi_extensions[i].ldapaif_version;
442 			break;
443 		}
444 	}
445 
446 	return(( i < NSLDAPI_EXTENSIONS_COUNT ) ? LDAP_SUCCESS
447 	    : LDAP_PARAM_ERROR );
448 }
449