384 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* See http://www.python-ldap.org/ for details.
 | |
|  * $Id: options.c,v 1.42 2014/09/12 12:02:21 stroeder Exp $ */
 | |
| 
 | |
| #include "common.h"
 | |
| #include "errors.h"
 | |
| #include "LDAPObject.h"
 | |
| #include "ldapcontrol.h"
 | |
| #include "options.h"
 | |
| 
 | |
| void
 | |
| set_timeval_from_double( struct timeval *tv, double d ) {
 | |
| 	tv->tv_usec = (long) ( fmod(d, 1.0) * 1000000.0 );
 | |
| 	tv->tv_sec = (long) floor(d);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Converts a return code from ldap_set_option() or ldap_get_option()
 | |
|  * into a python error, and returns NULL.
 | |
|  */
 | |
| static PyObject *
 | |
| option_error(int res, const char *fn)
 | |
| {
 | |
|     if (res == LDAP_OPT_ERROR)
 | |
|         PyErr_SetString(PyExc_ValueError, "option error");
 | |
|     else if (res == LDAP_PARAM_ERROR)
 | |
|         PyErr_SetString(PyExc_ValueError, "parameter error");
 | |
|     else if (res == LDAP_NO_MEMORY) 
 | |
|         PyErr_NoMemory();
 | |
|     else
 | |
|         PyErr_Format(PyExc_SystemError, "error %d from %s", res, fn);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets an LDAP option.
 | |
|  * Returns 0 on failure, 1 on success
 | |
|  */
 | |
| int
 | |
| LDAP_set_option(LDAPObject *self, int option, PyObject *value)
 | |
| {
 | |
|     int res;
 | |
|     int intval;
 | |
|     double doubleval;
 | |
|     char *strval;
 | |
|     struct timeval tv;
 | |
|     void *ptr;
 | |
|     LDAP *ld;
 | |
|     LDAPControl **controls = NULL;
 | |
| 
 | |
|     ld = self ? self->ldap : NULL;
 | |
| 
 | |
|     switch(option) {
 | |
|     case LDAP_OPT_API_INFO:
 | |
|     case LDAP_OPT_API_FEATURE_INFO:
 | |
| #ifdef HAVE_SASL
 | |
|     case LDAP_OPT_X_SASL_SSF:
 | |
| #endif
 | |
| 	    /* Read-only options */
 | |
| 	    PyErr_SetString(PyExc_ValueError, "read-only option");
 | |
| 	    return 0;
 | |
|     case LDAP_OPT_REFERRALS:
 | |
|     case LDAP_OPT_RESTART:
 | |
| #ifdef LDAP_OPT_X_SASL_NOCANON
 | |
|     case LDAP_OPT_X_SASL_NOCANON:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_CONNECT_ASYNC
 | |
|     case LDAP_OPT_CONNECT_ASYNC:
 | |
| #endif
 | |
| 	    /* Truth-value options */
 | |
| 	    ptr = PyObject_IsTrue(value) ? LDAP_OPT_ON : LDAP_OPT_OFF;
 | |
| 	    break;
 | |
| 
 | |
|     case LDAP_OPT_DEREF:
 | |
|     case LDAP_OPT_SIZELIMIT:
 | |
|     case LDAP_OPT_TIMELIMIT:
 | |
|     case LDAP_OPT_PROTOCOL_VERSION:
 | |
|     case LDAP_OPT_ERROR_NUMBER:
 | |
|     case LDAP_OPT_DEBUG_LEVEL:
 | |
| #ifdef HAVE_TLS
 | |
|     case LDAP_OPT_X_TLS:
 | |
|     case LDAP_OPT_X_TLS_REQUIRE_CERT:
 | |
| #ifdef LDAP_OPT_X_TLS_CRLCHECK
 | |
|     case LDAP_OPT_X_TLS_CRLCHECK:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_TLS_NEWCTX
 | |
|     case LDAP_OPT_X_TLS_NEWCTX:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
 | |
|     case LDAP_OPT_X_TLS_PROTOCOL_MIN:
 | |
| #endif
 | |
| #endif
 | |
| #ifdef HAVE_SASL
 | |
|     case LDAP_OPT_X_SASL_SSF_MIN:
 | |
|     case LDAP_OPT_X_SASL_SSF_MAX:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
 | |
|     case LDAP_OPT_X_KEEPALIVE_IDLE:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
 | |
|     case LDAP_OPT_X_KEEPALIVE_PROBES:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
 | |
|     case LDAP_OPT_X_KEEPALIVE_INTERVAL:
 | |
| #endif
 | |
| 
 | |
| 	    /* integer value options */
 | |
| 	    if (!PyArg_Parse(value, "i:set_option", &intval))
 | |
| 		return 0;
 | |
| 	    ptr = &intval;
 | |
| 	    break;
 | |
|     case LDAP_OPT_HOST_NAME:
 | |
|     case LDAP_OPT_URI:
 | |
| #ifdef LDAP_OPT_DEFBASE
 | |
|     case LDAP_OPT_DEFBASE:
 | |
| #endif
 | |
|     case LDAP_OPT_ERROR_STRING:
 | |
|     case LDAP_OPT_MATCHED_DN:
 | |
| #ifdef HAVE_TLS
 | |
|     case LDAP_OPT_X_TLS_CACERTFILE:
 | |
|     case LDAP_OPT_X_TLS_CACERTDIR:
 | |
|     case LDAP_OPT_X_TLS_CERTFILE:
 | |
|     case LDAP_OPT_X_TLS_KEYFILE:
 | |
|     case LDAP_OPT_X_TLS_CIPHER_SUITE:
 | |
|     case LDAP_OPT_X_TLS_RANDOM_FILE:
 | |
|     case LDAP_OPT_X_TLS_DHFILE:
 | |
| #ifdef LDAP_OPT_X_TLS_CRLFILE
 | |
|     case LDAP_OPT_X_TLS_CRLFILE:
 | |
| #endif
 | |
| #endif
 | |
| #ifdef HAVE_SASL
 | |
|     case LDAP_OPT_X_SASL_SECPROPS:
 | |
| #endif
 | |
| 	    /* String valued options */
 | |
| 	    if (!PyArg_Parse(value, "s:set_option", &strval))
 | |
| 		return 0;
 | |
| 	    ptr = strval;
 | |
| 	    break;
 | |
|     case LDAP_OPT_TIMEOUT:
 | |
|     case LDAP_OPT_NETWORK_TIMEOUT:
 | |
| 	    /* Float valued timeval options */
 | |
| 	    if (!PyArg_Parse(value, "d:set_option", &doubleval))
 | |
| 		return 0;
 | |
|             if (doubleval >= 0) {
 | |
| 	        set_timeval_from_double( &tv, doubleval );
 | |
|                 ptr = &tv;
 | |
|             } else {
 | |
|     	        ptr = NULL;
 | |
|             }
 | |
| 	    break;
 | |
|     case LDAP_OPT_SERVER_CONTROLS:
 | |
|     case LDAP_OPT_CLIENT_CONTROLS:
 | |
|             if (!LDAPControls_from_object(value, &controls))
 | |
|                 return 0;
 | |
|             ptr = controls;
 | |
|             break;
 | |
|     default:
 | |
| 	    PyErr_Format(PyExc_ValueError, "unknown option %d", option);
 | |
| 	    return 0;
 | |
|     }
 | |
| 	
 | |
|     if (self) LDAP_BEGIN_ALLOW_THREADS(self);
 | |
|     res = ldap_set_option(ld, option, ptr);
 | |
|     if (self) LDAP_END_ALLOW_THREADS(self);
 | |
| 
 | |
|     if ((option == LDAP_OPT_SERVER_CONTROLS) || (option == LDAP_OPT_CLIENT_CONTROLS))
 | |
|         LDAPControl_List_DEL(controls);
 | |
|     
 | |
|     if (res != LDAP_OPT_SUCCESS) {
 | |
|         option_error(res, "ldap_set_option");
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| PyObject *
 | |
| LDAP_get_option(LDAPObject *self, int option)
 | |
| {
 | |
|     int res;
 | |
|     int intval;
 | |
|     struct timeval *tv;
 | |
|     LDAPAPIInfo apiinfo;
 | |
|     LDAPControl **lcs;
 | |
|     LDAPControl *lc;
 | |
|     char *strval;
 | |
|     PyObject *extensions, *v, *tup;
 | |
|     Py_ssize_t i, num_extensions, num_controls;
 | |
|     LDAP *ld;
 | |
| 
 | |
|     ld = self ? self->ldap : NULL;
 | |
| 
 | |
|     switch(option) {
 | |
|     case LDAP_OPT_API_INFO:
 | |
| 	    apiinfo.ldapai_info_version = LDAP_API_INFO_VERSION;
 | |
| 	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
 | |
| 	    res = ldap_get_option( ld, option, &apiinfo );
 | |
| 	    if (self) LDAP_END_ALLOW_THREADS(self);
 | |
| 	    if (res != LDAP_OPT_SUCCESS)
 | |
| 		return option_error(res, "ldap_get_option");
 | |
|     
 | |
| 	    /* put the extensions into tuple form */
 | |
| 	    num_extensions = 0;
 | |
| 	    while (apiinfo.ldapai_extensions[num_extensions])
 | |
| 		num_extensions++;
 | |
| 	    extensions = PyTuple_New(num_extensions);
 | |
| 	    for (i = 0; i < num_extensions; i++)
 | |
| 		PyTuple_SET_ITEM(extensions, i,
 | |
| 		    PyUnicode_FromString(apiinfo.ldapai_extensions[i]));
 | |
| 
 | |
| 	    /* return api info as a dictionary */
 | |
| 	    v = Py_BuildValue("{s:i, s:i, s:i, s:s, s:i, s:O}",
 | |
| 		    "info_version",     apiinfo.ldapai_info_version,
 | |
| 		    "api_version",      apiinfo.ldapai_api_version,
 | |
| 		    "protocol_version", apiinfo.ldapai_protocol_version,
 | |
| 		    "vendor_name",      apiinfo.ldapai_vendor_name,
 | |
| 		    "vendor_version",   apiinfo.ldapai_vendor_version,
 | |
| 		    "extensions",       extensions);
 | |
| 
 | |
| 	    if (apiinfo.ldapai_vendor_name)
 | |
| 		ldap_memfree(apiinfo.ldapai_vendor_name);
 | |
| 	    for (i = 0; i < num_extensions; i++)
 | |
| 		ldap_memfree(apiinfo.ldapai_extensions[i]);
 | |
| 	    ldap_memfree(apiinfo.ldapai_extensions);
 | |
| 	    Py_DECREF(extensions);
 | |
| 
 | |
| 	    return v;
 | |
| 
 | |
| #ifdef HAVE_SASL
 | |
|     case LDAP_OPT_X_SASL_SSF:
 | |
| #endif
 | |
|     case LDAP_OPT_REFERRALS:
 | |
|     case LDAP_OPT_RESTART:
 | |
|     case LDAP_OPT_DEREF:
 | |
|     case LDAP_OPT_SIZELIMIT:
 | |
|     case LDAP_OPT_TIMELIMIT:
 | |
|     case LDAP_OPT_PROTOCOL_VERSION:
 | |
|     case LDAP_OPT_ERROR_NUMBER:
 | |
|     case LDAP_OPT_DEBUG_LEVEL:
 | |
|     case LDAP_OPT_DESC:
 | |
| #ifdef HAVE_TLS
 | |
|     case LDAP_OPT_X_TLS:
 | |
|     case LDAP_OPT_X_TLS_REQUIRE_CERT:
 | |
| #ifdef LDAP_OPT_X_TLS_CRLCHECK
 | |
|     case LDAP_OPT_X_TLS_CRLCHECK:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_TLS_PROTOCOL_MIN
 | |
|     case LDAP_OPT_X_TLS_PROTOCOL_MIN:
 | |
| #endif
 | |
| #endif
 | |
| #ifdef HAVE_SASL
 | |
|     case LDAP_OPT_X_SASL_SSF_MIN:
 | |
|     case LDAP_OPT_X_SASL_SSF_MAX:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_SASL_NOCANON
 | |
|     case LDAP_OPT_X_SASL_NOCANON:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_CONNECT_ASYNC
 | |
|     case LDAP_OPT_CONNECT_ASYNC:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_KEEPALIVE_IDLE
 | |
|     case LDAP_OPT_X_KEEPALIVE_IDLE:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_KEEPALIVE_PROBES
 | |
|     case LDAP_OPT_X_KEEPALIVE_PROBES:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_KEEPALIVE_INTERVAL
 | |
|     case LDAP_OPT_X_KEEPALIVE_INTERVAL:
 | |
| #endif
 | |
| 	    /* Integer-valued options */
 | |
| 	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
 | |
| 	    res = ldap_get_option(ld, option, &intval);
 | |
| 	    if (self) LDAP_END_ALLOW_THREADS(self);
 | |
| 	    if (res != LDAP_OPT_SUCCESS)
 | |
| 		return option_error(res, "ldap_get_option");
 | |
| 	    return PyLong_FromLong(intval);
 | |
| 
 | |
|     case LDAP_OPT_HOST_NAME:
 | |
|     case LDAP_OPT_URI:
 | |
| #ifdef LDAP_OPT_DEFBASE
 | |
|     case LDAP_OPT_DEFBASE:
 | |
| #endif
 | |
|     case LDAP_OPT_ERROR_STRING:
 | |
|     case LDAP_OPT_MATCHED_DN:
 | |
| #ifdef HAVE_TLS
 | |
|     case LDAP_OPT_X_TLS_CACERTFILE:
 | |
|     case LDAP_OPT_X_TLS_CACERTDIR:
 | |
|     case LDAP_OPT_X_TLS_CERTFILE:
 | |
|     case LDAP_OPT_X_TLS_KEYFILE:
 | |
|     case LDAP_OPT_X_TLS_CIPHER_SUITE:
 | |
|     case LDAP_OPT_X_TLS_RANDOM_FILE:
 | |
|     case LDAP_OPT_X_TLS_DHFILE:
 | |
| #ifdef LDAP_OPT_X_TLS_CRLFILE
 | |
|     case LDAP_OPT_X_TLS_CRLFILE:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_TLS_VERSION
 | |
|     case LDAP_OPT_X_TLS_VERSION:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_TLS_CIPHER
 | |
|     case LDAP_OPT_X_TLS_CIPHER:
 | |
| #endif
 | |
| #ifdef LDAP_OPT_X_TLS_PACKAGE
 | |
|     case LDAP_OPT_X_TLS_PACKAGE:
 | |
| #endif
 | |
| #endif
 | |
| #ifdef HAVE_SASL
 | |
|     case LDAP_OPT_X_SASL_SECPROPS:
 | |
|     case LDAP_OPT_X_SASL_MECH:
 | |
|     case LDAP_OPT_X_SASL_REALM:
 | |
|     case LDAP_OPT_X_SASL_AUTHCID:
 | |
|     case LDAP_OPT_X_SASL_AUTHZID:
 | |
| #ifdef LDAP_OPT_X_SASL_USERNAME
 | |
|     case LDAP_OPT_X_SASL_USERNAME:
 | |
| #endif
 | |
| #endif
 | |
| 	    /* String-valued options */
 | |
| 	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
 | |
| 	    res = ldap_get_option(ld, option, &strval);
 | |
| 	    if (self) LDAP_END_ALLOW_THREADS(self);
 | |
| 	    if (res != LDAP_OPT_SUCCESS)
 | |
| 		return option_error(res, "ldap_get_option");
 | |
| 	    if (strval == NULL) {
 | |
| 		Py_INCREF(Py_None);
 | |
| 		return Py_None;
 | |
| 	    }
 | |
| 	    v = PyUnicode_FromString(strval);
 | |
| 	    ldap_memfree(strval);
 | |
| 	    return v;
 | |
| 
 | |
|     case LDAP_OPT_TIMEOUT:
 | |
|     case LDAP_OPT_NETWORK_TIMEOUT:
 | |
| 	    /* Double-valued timeval options */
 | |
| 	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
 | |
| 	    res = ldap_get_option(ld, option, &tv);
 | |
| 	    if (self) LDAP_END_ALLOW_THREADS(self);
 | |
| 	    if (res != LDAP_OPT_SUCCESS)
 | |
| 		return option_error(res, "ldap_get_option");
 | |
| 	    if (tv == NULL) {
 | |
| 		Py_INCREF(Py_None);
 | |
| 		return Py_None;
 | |
| 	    }
 | |
| 	    v = PyFloat_FromDouble(
 | |
|               (double) tv->tv_sec + ( (double) tv->tv_usec / 1000000.0 )
 | |
|             );
 | |
| 	    ldap_memfree(tv);
 | |
| 	    return v;
 | |
| 
 | |
|     case LDAP_OPT_SERVER_CONTROLS:
 | |
|     case LDAP_OPT_CLIENT_CONTROLS:
 | |
| 	    if (self) LDAP_BEGIN_ALLOW_THREADS(self);
 | |
| 	    res = ldap_get_option(ld, option, &lcs);
 | |
| 	    if (self) LDAP_END_ALLOW_THREADS(self);
 | |
| 
 | |
| 	    if (res != LDAP_OPT_SUCCESS)
 | |
| 		return option_error(res, "ldap_get_option");
 | |
| 
 | |
|             if (lcs == NULL)
 | |
|                 return PyList_New(0);
 | |
|             
 | |
|             /* Get the number of controls */
 | |
|             num_controls = 0;
 | |
|             while (lcs[num_controls])
 | |
|                 num_controls++;
 | |
| 
 | |
|             /* We'll build a list of controls, with each control a tuple */
 | |
|             v = PyList_New(num_controls);
 | |
|             for (i = 0; i < num_controls; i++) {
 | |
|                 lc = lcs[i];
 | |
|                 tup = Py_BuildValue("(sbs)", 
 | |
|                                     lc->ldctl_oid,
 | |
|                                     lc->ldctl_iscritical,
 | |
|                                     lc->ldctl_value.bv_val);
 | |
|                 PyList_SET_ITEM(v, i, tup);
 | |
|             }
 | |
|             
 | |
|             ldap_controls_free(lcs);
 | |
| 
 | |
|             return v;
 | |
|             
 | |
|     default:
 | |
| 	    PyErr_Format(PyExc_ValueError, "unknown option %d", option);
 | |
| 	    return NULL;
 | |
|     }
 | |
| }
 | 
