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