diff --git a/Modules/ldapcontrol.c b/Modules/ldapcontrol.c new file mode 100644 index 0000000..14a8625 --- /dev/null +++ b/Modules/ldapcontrol.c @@ -0,0 +1,377 @@ +/* See http://www.python-ldap.org/ for details. + * $Id: ldapcontrol.c,v 1.20 2011/10/26 18:38:06 stroeder Exp $ */ + +#include "common.h" +#include "LDAPObject.h" +#include "ldapcontrol.h" +#include "berval.h" +#include "errors.h" + +#include "lber.h" + +/* Prints to stdout the contents of an array of LDAPControl objects */ + +/* XXX: This is a debugging tool, and the printf generates some warnings + * about pointer types. I left it here in case something breaks and we + * need to inspect an LDAPControl structure. + +static void +LDAPControl_DumpList( LDAPControl** lcs ) { + LDAPControl** lcp; + LDAPControl* lc; + for ( lcp = lcs; *lcp; lcp++ ) { + lc = *lcp; + printf("OID: %s\nCriticality: %d\nBER length: %d\nBER value: %x\n", + lc->ldctl_oid, lc->ldctl_iscritical, lc->ldctl_value.bv_len, + lc->ldctl_value.bv_val); + } +} */ + +/* Free a single LDAPControl object created by Tuple_to_LDAPControl */ + +static void +LDAPControl_DEL( LDAPControl* lc ) +{ + if (lc == NULL) + return; + + if (lc->ldctl_oid) + PyMem_DEL(lc->ldctl_oid); + PyMem_DEL(lc); +} + +/* Free an array of LDAPControl objects created by LDAPControls_from_object */ + +void +LDAPControl_List_DEL( LDAPControl** lcs ) +{ + LDAPControl** lcp; + if (lcs == NULL) + return; + + for ( lcp = lcs; *lcp; lcp++ ) + LDAPControl_DEL( *lcp ); + + PyMem_DEL( lcs ); +} + +/* Takes a tuple of the form: + * (OID: string, Criticality: int/boolean, Value: string/None) + * and converts it into an LDAPControl structure. + * + * The Value string should represent an ASN.1 encoded structure. + */ + +static LDAPControl* +Tuple_to_LDAPControl( PyObject* tup ) +{ + char *oid; + char iscritical; + struct berval berbytes; + PyObject *bytes; + LDAPControl *lc = NULL; + Py_ssize_t len; + + if (!PyTuple_Check(tup)) { + PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO", + "expected a tuple", tup)); + return NULL; + } + + if (!PyArg_ParseTuple( tup, "sbO", &oid, &iscritical, &bytes )) + return NULL; + + lc = PyMem_NEW(LDAPControl, 1); + if (lc == NULL) { + PyErr_NoMemory(); + return NULL; + } + + lc->ldctl_iscritical = iscritical; + + len = strlen(oid); + lc->ldctl_oid = PyMem_NEW(char, len + 1); + if (lc->ldctl_oid == NULL) { + PyErr_NoMemory(); + LDAPControl_DEL(lc); + return NULL; + } + memcpy(lc->ldctl_oid, oid, len + 1); + + /* The berval can either be None or a String */ + if (PyNone_Check(bytes)) { + berbytes.bv_len = 0; + berbytes.bv_val = NULL; + } + else if (PyString_Check(bytes)) { + berbytes.bv_len = PyString_Size(bytes); + berbytes.bv_val = PyString_AsString(bytes); + } + else { + PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO", + "expected a string", bytes)); + LDAPControl_DEL(lc); + return NULL; + } + + lc->ldctl_value = berbytes; + + return lc; +} + +/* Convert a list of tuples (of a format acceptable to the Tuple_to_LDAPControl + * function) into an array of LDAPControl objects. */ + +int +LDAPControls_from_object(PyObject* list, LDAPControl ***controls_ret) +{ + Py_ssize_t len, i; + LDAPControl** ldcs; + LDAPControl* ldc; + PyObject* item; + + if (!PySequence_Check(list)) { + PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO", + "expected a list", list)); + return 0; + } + + len = PySequence_Length(list); + ldcs = PyMem_NEW(LDAPControl*, len + 1); + if (ldcs == NULL) { + PyErr_NoMemory(); + return 0; + } + + for (i = 0; i < len; i++) { + item = PySequence_GetItem(list, i); + if (item == NULL) { + PyMem_DEL(ldcs); + return 0; + } + + ldc = Tuple_to_LDAPControl(item); + if (ldc == NULL) { + Py_DECREF(item); + PyMem_DEL(ldcs); + return 0; + } + + ldcs[i] = ldc; + Py_DECREF(item); + } + + ldcs[len] = NULL; + *controls_ret = ldcs; + return 1; +} + +PyObject* +LDAPControls_to_List(LDAPControl **ldcs) +{ + PyObject *res = 0, *pyctrl; + LDAPControl **tmp = ldcs; + Py_ssize_t num_ctrls = 0, i; + + if (tmp) + while (*tmp++) num_ctrls++; + + if (!(res = PyList_New(num_ctrls))) + goto endlbl; + + for (i = 0; i < num_ctrls; i++) { + if (!(pyctrl = Py_BuildValue("sbO&", ldcs[i]->ldctl_oid, + ldcs[i]->ldctl_iscritical, + LDAPberval_to_object, + &ldcs[i]->ldctl_value))) { + goto endlbl; + } + PyList_SET_ITEM(res, i, pyctrl); + } + Py_INCREF(res); + + endlbl: + Py_XDECREF(res); + return res; +} + + + +/* --------------- en-/decoders ------------- */ + +/* Matched Values, aka, Values Return Filter */ +static PyObject* +encode_rfc3876(PyObject *self, PyObject *args) +{ + PyObject *res = 0; + int err; + BerElement *vrber = 0; + char *vrFilter; + struct berval *ctrl_val; + + if (!PyArg_ParseTuple(args, "s:encode_valuesreturnfilter_control", &vrFilter)) { + goto endlbl; + } + + if (!(vrber = ber_alloc_t(LBER_USE_DER))) { + LDAPerr(LDAP_NO_MEMORY); + goto endlbl; + } + + err = ldap_put_vrFilter(vrber, vrFilter); + if (err == -1) { + LDAPerr(LDAP_FILTER_ERROR); + goto endlbl; + } + + err = ber_flatten(vrber, &ctrl_val); + if (err == -1) { + LDAPerr(LDAP_NO_MEMORY); + goto endlbl; + } + + res = LDAPberval_to_object(ctrl_val); + +endlbl: + if (vrber) + ber_free(vrber, 1); + + return res; +} + +static PyObject* +encode_rfc2696(PyObject *self, PyObject *args) +{ + PyObject *res = 0; + BerElement *ber = 0; + struct berval cookie, *ctrl_val; + Py_ssize_t cookie_len; + unsigned long size; + ber_tag_t tag; + + if (!PyArg_ParseTuple(args, "is#:encode_page_control", &size, + &cookie.bv_val, &cookie_len)) { + goto endlbl; + } + cookie.bv_len = (ber_len_t) cookie_len; + + if (!(ber = ber_alloc_t(LBER_USE_DER))) { + LDAPerr(LDAP_NO_MEMORY); + goto endlbl; + } + + tag = ber_printf(ber, "{i", size); + if (tag == LBER_ERROR) { + LDAPerr(LDAP_ENCODING_ERROR); + goto endlbl; + } + + if (!cookie.bv_len) + tag = ber_printf(ber, "o", "", 0); + else + tag = ber_printf(ber, "O", &cookie); + if (tag == LBER_ERROR) { + LDAPerr(LDAP_ENCODING_ERROR); + goto endlbl; + } + + tag = ber_printf(ber, /*{ */ "N}"); + if (tag == LBER_ERROR) { + LDAPerr(LDAP_ENCODING_ERROR); + goto endlbl; + } + + if (-1 == ber_flatten(ber, &ctrl_val)) { + LDAPerr(LDAP_NO_MEMORY); + goto endlbl; + } + + res = LDAPberval_to_object(ctrl_val); + + endlbl: + if (ber) + ber_free(ber, 1); + return res; +} + + +static PyObject* +decode_rfc2696(PyObject *self, PyObject *args) +{ + PyObject *res = 0; + BerElement *ber = 0; + struct berval ldctl_value; + ber_tag_t tag; + struct berval *cookiep; + unsigned long count; + Py_ssize_t ldctl_value_len; + + if (!PyArg_ParseTuple(args, "s#:decode_page_control", + &ldctl_value.bv_val, &ldctl_value_len)) { + goto endlbl; + } + ldctl_value.bv_len = (ber_len_t) ldctl_value_len; + + if (!(ber = ber_init(&ldctl_value))) { + LDAPerr(LDAP_NO_MEMORY); + goto endlbl; + } + + tag = ber_scanf(ber, "{iO", &count, &cookiep); + if (tag == LBER_ERROR) { + LDAPerr(LDAP_DECODING_ERROR); + goto endlbl; + } + + res = Py_BuildValue("(lO&)", count, LDAPberval_to_object, cookiep); + + endlbl: + if (ber) + ber_free(ber, 1); + return res; +} + +static PyObject* +encode_assertion_control(PyObject *self, PyObject *args) +{ + int err; + PyObject *res = 0; + char *assertion_filterstr; + struct berval ctrl_val; + LDAP *ld = NULL; + + if (!PyArg_ParseTuple(args, "s:encode_assertion_control", + &assertion_filterstr)) { + goto endlbl; + } + + err = ldap_create(&ld); + if (err != LDAP_SUCCESS) + return LDAPerror(ld, "ldap_create"); + + err = ldap_create_assertion_control_value(ld,assertion_filterstr,&ctrl_val); + if (err != LDAP_SUCCESS) + return LDAPerror(ld, "ldap_create_assertion_control_value"); + + res = LDAPberval_to_object(&ctrl_val); + + endlbl: + + return res; +} + +static PyMethodDef methods[] = { + {"encode_page_control", encode_rfc2696, METH_VARARGS }, + {"decode_page_control", decode_rfc2696, METH_VARARGS }, + {"encode_valuesreturnfilter_control", encode_rfc3876, METH_VARARGS }, + {"encode_assertion_control", encode_assertion_control, METH_VARARGS }, + { NULL, NULL } +}; + +void +LDAPinit_control(PyObject *d) +{ + LDAPadd_methods(d, methods); +} + + diff --git a/Modules/message.c b/Modules/message.c new file mode 100644 index 0000000..7cc7072 --- /dev/null +++ b/Modules/message.c @@ -0,0 +1,257 @@ +/* See http://www.python-ldap.org/ for details. + * $Id: message.c,v 1.19 2011/10/26 18:38:06 stroeder Exp $ */ + +#include "common.h" +#include "message.h" +#include "berval.h" +#include "errors.h" +#include "ldapcontrol.h" +#include "constants.h" + +/* + * Converts an LDAP message into a Python structure. + * + * On success, returns a list of dictionaries. + * On failure, returns NULL, and sets an error. + * + * The message m is always freed, regardless of return value. + * + * If add_ctrls is non-zero, per-entry/referral/partial/intermediate + * controls will be added as a third item to each entry tuple + * + * If add_intermediates is non-zero, intermediate/partial results will + * be returned + */ +PyObject * +LDAPmessage_to_python(LDAP *ld, LDAPMessage *m, int add_ctrls, int add_intermediates) +{ + /* we convert an LDAP message into a python structure. + * It is always a list of dictionaries. + * We always free m. + */ + + PyObject *result, *pyctrls = 0; + LDAPMessage* entry; + LDAPControl **serverctrls = 0; + int rc; + + result = PyList_New(0); + if (result == NULL) { + ldap_msgfree( m ); + return NULL; + } + + for(entry = ldap_first_entry(ld,m); + entry != NULL; + entry = ldap_next_entry(ld,entry)) + { + char *dn; + char *attr; + BerElement *ber = NULL; + PyObject* entrytuple; + PyObject* attrdict; + + dn = ldap_get_dn( ld, entry ); + if (dn == NULL) { + Py_DECREF(result); + ldap_msgfree( m ); + return LDAPerror( ld, "ldap_get_dn" ); + } + + attrdict = PyDict_New(); + if (attrdict == NULL) { + Py_DECREF(result); + ldap_msgfree( m ); + ldap_memfree(dn); + return NULL; + } + + rc = ldap_get_entry_controls( ld, entry, &serverctrls ); + if (rc) { + Py_DECREF(result); + ldap_msgfree( m ); + ldap_memfree(dn); + return LDAPerror( ld, "ldap_get_entry_controls" ); + } + + /* convert serverctrls to list of tuples */ + if ( ! ( pyctrls = LDAPControls_to_List( serverctrls ) ) ) { + int err = LDAP_NO_MEMORY; + ldap_set_option( ld, LDAP_OPT_ERROR_NUMBER, &err ); + Py_DECREF(result); + ldap_msgfree( m ); + ldap_memfree(dn); + ldap_controls_free(serverctrls); + return LDAPerror( ld, "LDAPControls_to_List" ); + } + ldap_controls_free(serverctrls); + + /* Fill attrdict with lists */ + for( attr = ldap_first_attribute( ld, entry, &ber ); + attr != NULL; + attr = ldap_next_attribute( ld, entry, ber ) + ) { + PyObject* valuelist; + struct berval ** bvals = + ldap_get_values_len( ld, entry, attr ); + + /* Find which list to append to */ + if ( PyMapping_HasKeyString( attrdict, attr ) ) { + valuelist = PyMapping_GetItemString( attrdict, attr ); + } else { + valuelist = PyList_New(0); + if (valuelist != NULL && PyMapping_SetItemString(attrdict, + attr, valuelist) == -1) { + Py_DECREF(valuelist); + valuelist = NULL; /* catch error later */ + } + } + + if (valuelist == NULL) { + Py_DECREF(attrdict); + Py_DECREF(result); + if (ber != NULL) + ber_free(ber, 0); + ldap_msgfree( m ); + ldap_memfree(attr); + ldap_memfree(dn); + Py_XDECREF(pyctrls); + return NULL; + } + + if (bvals != NULL) { + Py_ssize_t i; + for (i=0; bvals[i]; i++) { + PyObject *valuestr; + + valuestr = LDAPberval_to_object(bvals[i]); + if (PyList_Append( valuelist, valuestr ) == -1) { + Py_DECREF(attrdict); + Py_DECREF(result); + Py_DECREF(valuestr); + Py_DECREF(valuelist); + if (ber != NULL) + ber_free(ber, 0); + ldap_msgfree( m ); + ldap_memfree(attr); + ldap_memfree(dn); + Py_XDECREF(pyctrls); + return NULL; + } + Py_DECREF(valuestr); + } + ldap_value_free_len(bvals); + } + Py_DECREF( valuelist ); + ldap_memfree(attr); + } + + if (add_ctrls) { + entrytuple = Py_BuildValue("(sOO)", dn, attrdict, pyctrls); + } else { + entrytuple = Py_BuildValue("(sO)", dn, attrdict); + } + ldap_memfree(dn); + Py_DECREF(attrdict); + Py_XDECREF(pyctrls); + PyList_Append(result, entrytuple); + Py_DECREF(entrytuple); + if (ber != NULL) + ber_free(ber, 0); + } + for(entry = ldap_first_reference(ld,m); + entry != NULL; + entry = ldap_next_reference(ld,entry)) + { + char **refs = NULL; + PyObject* entrytuple; + PyObject* reflist = PyList_New(0); + + if (reflist == NULL) { + Py_DECREF(result); + ldap_msgfree( m ); + return NULL; + } + if (ldap_parse_reference(ld, entry, &refs, &serverctrls, 0) != LDAP_SUCCESS) { + Py_DECREF(reflist); + Py_DECREF(result); + ldap_msgfree( m ); + return LDAPerror( ld, "ldap_parse_reference" ); + } + /* convert serverctrls to list of tuples */ + if ( ! ( pyctrls = LDAPControls_to_List( serverctrls ) ) ) { + int err = LDAP_NO_MEMORY; + ldap_set_option( ld, LDAP_OPT_ERROR_NUMBER, &err ); + Py_DECREF(reflist); + Py_DECREF(result); + ldap_msgfree( m ); + ldap_controls_free(serverctrls); + return LDAPerror( ld, "LDAPControls_to_List" ); + } + ldap_controls_free(serverctrls); + if (refs) { + Py_ssize_t i; + for (i=0; refs[i] != NULL; i++) { + PyObject *refstr = PyString_FromString(refs[i]); + PyList_Append(reflist, refstr); + Py_DECREF(refstr); + } + ber_memvfree( (void **) refs ); + } + if (add_ctrls) { + entrytuple = Py_BuildValue("(sOO)", NULL, reflist, pyctrls); + } else { + entrytuple = Py_BuildValue("(sO)", NULL, reflist); + } + Py_DECREF(reflist); + Py_XDECREF(pyctrls); + PyList_Append(result, entrytuple); + Py_DECREF(entrytuple); + } + if (add_intermediates) { + for(entry = ldap_first_message(ld,m); + entry != NULL; + entry = ldap_next_message(ld,entry)) + { + /* list of tuples */ + /* each tuple is OID, Berval, controllist */ + if ( LDAP_RES_INTERMEDIATE == ldap_msgtype( entry ) ) { + PyObject* valtuple; + PyObject *valuestr; + char *retoid = 0; + struct berval *retdata = 0; + + if (ldap_parse_intermediate( ld, entry, &retoid, &retdata, &serverctrls, 0 ) != LDAP_SUCCESS) { + Py_DECREF(result); + ldap_msgfree( m ); + return LDAPerror( ld, "ldap_parse_intermediate" ); + } + /* convert serverctrls to list of tuples */ + if ( ! ( pyctrls = LDAPControls_to_List( serverctrls ) ) ) { + int err = LDAP_NO_MEMORY; + ldap_set_option( ld, LDAP_OPT_ERROR_NUMBER, &err ); + Py_DECREF(result); + ldap_msgfree( m ); + ldap_controls_free(serverctrls); + ldap_memfree( retoid ); + ber_bvfree( retdata ); + return LDAPerror( ld, "LDAPControls_to_List" ); + } + ldap_controls_free(serverctrls); + + valuestr = LDAPberval_to_object(retdata); + ber_bvfree( retdata ); + valtuple = Py_BuildValue("(sOO)", retoid, + valuestr ? valuestr : Py_None, + pyctrls); + ldap_memfree( retoid ); + Py_DECREF(valuestr); + Py_XDECREF(pyctrls); + PyList_Append(result, valtuple); + Py_DECREF(valtuple); + } + } + } + ldap_msgfree( m ); + return result; +}