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,
|
|
PyString_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 PyInt_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 = PyString_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;
|
|
}
|
|
}
|