LDAPObject.c 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303
  1. /* See http://www.python-ldap.org/ for details.
  2. * $Id: LDAPObject.c,v 1.88 2009/10/08 18:22:44 stroeder Exp $ */
  3. #include "common.h"
  4. #include "patchlevel.h"
  5. #include <math.h>
  6. #include <limits.h>
  7. #include "errors.h"
  8. #include "constants.h"
  9. #include "LDAPObject.h"
  10. #include "ldapcontrol.h"
  11. #include "message.h"
  12. #include "berval.h"
  13. #include "options.h"
  14. #ifdef HAVE_SASL
  15. #include <sasl.h>
  16. #endif
  17. static void free_attrs(char***);
  18. /* constructor */
  19. LDAPObject*
  20. newLDAPObject( LDAP* l )
  21. {
  22. LDAPObject* self = (LDAPObject*) PyObject_NEW(LDAPObject, &LDAP_Type);
  23. if (self == NULL)
  24. return NULL;
  25. self->ldap = l;
  26. self->_save = NULL;
  27. self->valid = 1;
  28. return self;
  29. }
  30. /* destructor */
  31. static void
  32. dealloc( LDAPObject* self )
  33. {
  34. if (self->ldap) {
  35. if (self->valid) {
  36. LDAP_BEGIN_ALLOW_THREADS( self );
  37. ldap_unbind_ext( self->ldap, NULL, NULL );
  38. LDAP_END_ALLOW_THREADS( self );
  39. self->valid = 0;
  40. }
  41. self->ldap = NULL;
  42. }
  43. PyObject_DEL(self);
  44. }
  45. /*------------------------------------------------------------
  46. * utility functions
  47. */
  48. /*
  49. * check to see if the LDAPObject is valid,
  50. * ie has been opened, and not closed. An exception is set if not valid.
  51. */
  52. static int
  53. not_valid( LDAPObject* l ) {
  54. if (l->valid) {
  55. return 0;
  56. } else {
  57. PyErr_SetString( LDAPexception_class, "LDAP connection invalid" );
  58. return 1;
  59. }
  60. }
  61. /* free a LDAPMod (complete or partially) allocated in Tuple_to_LDAPMod() */
  62. static void
  63. LDAPMod_DEL( LDAPMod* lm )
  64. {
  65. Py_ssize_t i;
  66. if (lm->mod_type)
  67. PyMem_DEL(lm->mod_type);
  68. if (lm->mod_bvalues) {
  69. for (i = 0; lm->mod_bvalues[i]; i++) {
  70. PyMem_DEL(lm->mod_bvalues[i]);
  71. }
  72. PyMem_DEL(lm->mod_bvalues);
  73. }
  74. PyMem_DEL(lm);
  75. }
  76. /*
  77. * convert a tuple of the form (int,str,[str,...])
  78. * or (str, [str,...]) if no_op is true, into an LDAPMod structure.
  79. * See ldap_modify(3) for details.
  80. *
  81. * NOTE: the resulting LDAPMod structure has pointers directly into
  82. * the Python string storage, so LDAPMod structures MUST have a
  83. * shorter lifetime than the tuple passed in.
  84. */
  85. /* XXX - there is no way to pass complex-structured BER objects in here! */
  86. static LDAPMod*
  87. Tuple_to_LDAPMod( PyObject* tup, int no_op )
  88. {
  89. int op;
  90. char *type;
  91. PyObject *list, *item;
  92. LDAPMod *lm = NULL;
  93. Py_ssize_t i, len, nstrs;
  94. if (!PyTuple_Check(tup)) {
  95. PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO",
  96. "expected a tuple", tup));
  97. return NULL;
  98. }
  99. if (no_op) {
  100. if (!PyArg_ParseTuple( tup, "sO", &type, &list ))
  101. return NULL;
  102. op = 0;
  103. } else {
  104. if (!PyArg_ParseTuple( tup, "isO", &op, &type, &list ))
  105. return NULL;
  106. }
  107. lm = PyMem_NEW(LDAPMod, 1);
  108. if (lm == NULL)
  109. goto nomem;
  110. lm->mod_op = op | LDAP_MOD_BVALUES;
  111. lm->mod_bvalues = NULL;
  112. len = strlen(type);
  113. lm->mod_type = PyMem_NEW(char, len + 1);
  114. if (lm->mod_type == NULL)
  115. goto nomem;
  116. memcpy(lm->mod_type, type, len + 1);
  117. if (list == Py_None) {
  118. /* None indicates a NULL mod_bvals */
  119. } else if (PyString_Check(list)) {
  120. /* Single string is a singleton list */
  121. lm->mod_bvalues = PyMem_NEW(struct berval *, 2);
  122. if (lm->mod_bvalues == NULL)
  123. goto nomem;
  124. lm->mod_bvalues[0] = PyMem_NEW(struct berval, 1);
  125. if (lm->mod_bvalues[0] == NULL)
  126. goto nomem;
  127. lm->mod_bvalues[1] = NULL;
  128. lm->mod_bvalues[0]->bv_len = PyString_Size(list);
  129. lm->mod_bvalues[0]->bv_val = PyString_AsString(list);
  130. } else if (PySequence_Check(list)) {
  131. nstrs = PySequence_Length(list);
  132. lm->mod_bvalues = PyMem_NEW(struct berval *, nstrs + 1);
  133. if (lm->mod_bvalues == NULL)
  134. goto nomem;
  135. for (i = 0; i < nstrs; i++) {
  136. lm->mod_bvalues[i] = PyMem_NEW(struct berval, 1);
  137. if (lm->mod_bvalues[i] == NULL)
  138. goto nomem;
  139. lm->mod_bvalues[i+1] = NULL;
  140. item = PySequence_GetItem(list, i);
  141. if (item == NULL)
  142. goto error;
  143. if (!PyString_Check(item)) {
  144. PyErr_SetObject( PyExc_TypeError, Py_BuildValue( "sO",
  145. "expected a string in the list", item));
  146. Py_DECREF(item);
  147. goto error;
  148. }
  149. lm->mod_bvalues[i]->bv_len = PyString_Size(item);
  150. lm->mod_bvalues[i]->bv_val = PyString_AsString(item);
  151. Py_DECREF(item);
  152. }
  153. if (nstrs == 0)
  154. lm->mod_bvalues[0] = NULL;
  155. }
  156. return lm;
  157. nomem:
  158. PyErr_NoMemory();
  159. error:
  160. if (lm)
  161. LDAPMod_DEL(lm);
  162. return NULL;
  163. }
  164. /* free the structure allocated in List_to_LDAPMods() */
  165. static void
  166. LDAPMods_DEL( LDAPMod** lms ) {
  167. LDAPMod** lmp;
  168. for ( lmp = lms; *lmp; lmp++ )
  169. LDAPMod_DEL( *lmp );
  170. PyMem_DEL(lms);
  171. }
  172. /*
  173. * convert a list of tuples into a LDAPMod*[] array structure
  174. * NOTE: list of tuples must live longer than the LDAPMods
  175. */
  176. static LDAPMod**
  177. List_to_LDAPMods( PyObject *list, int no_op ) {
  178. Py_ssize_t i, len;
  179. LDAPMod** lms;
  180. PyObject *item;
  181. if (!PySequence_Check(list)) {
  182. PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
  183. "expected list of tuples", list ));
  184. return NULL;
  185. }
  186. len = PySequence_Length(list);
  187. if (len < 0) {
  188. PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
  189. "expected list of tuples", list ));
  190. return NULL;
  191. }
  192. lms = PyMem_NEW(LDAPMod *, len + 1);
  193. if (lms == NULL)
  194. goto nomem;
  195. for (i = 0; i < len; i++) {
  196. lms[i] = NULL;
  197. item = PySequence_GetItem(list, i);
  198. if (item == NULL)
  199. goto error;
  200. lms[i] = Tuple_to_LDAPMod(item, no_op);
  201. Py_DECREF(item);
  202. if (lms[i] == NULL)
  203. goto error;
  204. }
  205. lms[len] = NULL;
  206. return lms;
  207. nomem:
  208. PyErr_NoMemory();
  209. error:
  210. if (lms)
  211. LDAPMods_DEL(lms);
  212. return NULL;
  213. }
  214. /*
  215. * convert a python list of strings into an attr list (char*[]).
  216. * returns 1 if successful, 0 if not (with exception set)
  217. * XXX the strings should live longer than the resulting attrs pointer.
  218. */
  219. int
  220. attrs_from_List( PyObject *attrlist, char***attrsp ) {
  221. char **attrs = NULL;
  222. Py_ssize_t i, len;
  223. PyObject *item;
  224. if (attrlist == Py_None) {
  225. /* None means a NULL attrlist */
  226. } else if (PyString_Check(attrlist)) {
  227. /* caught by John Benninghoff <johnb@netscape.com> */
  228. PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
  229. "expected *list* of strings, not a string", attrlist ));
  230. goto error;
  231. } else if (PySequence_Check(attrlist)) {
  232. len = PySequence_Length(attrlist);
  233. attrs = PyMem_NEW(char *, len + 1);
  234. if (attrs == NULL)
  235. goto nomem;
  236. for (i = 0; i < len; i++) {
  237. attrs[i] = NULL;
  238. item = PySequence_GetItem(attrlist, i);
  239. if (item == NULL)
  240. goto error;
  241. if (!PyString_Check(item)) {
  242. PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO",
  243. "expected string in list", item));
  244. Py_DECREF(item);
  245. goto error;
  246. }
  247. attrs[i] = PyString_AsString(item);
  248. Py_DECREF(item);
  249. }
  250. attrs[len] = NULL;
  251. } else {
  252. PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
  253. "expected list of strings or None", attrlist ));
  254. goto error;
  255. }
  256. *attrsp = attrs;
  257. return 1;
  258. nomem:
  259. PyErr_NoMemory();
  260. error:
  261. free_attrs(&attrs);
  262. return 0;
  263. }
  264. /* free memory allocated from above routine */
  265. static void
  266. free_attrs( char*** attrsp ) {
  267. char **attrs = *attrsp;
  268. if (attrs != NULL) {
  269. PyMem_DEL(attrs);
  270. *attrsp = NULL;
  271. }
  272. }
  273. /*------------------------------------------------------------
  274. * methods
  275. */
  276. /* ldap_unbind_ext */
  277. static PyObject*
  278. l_ldap_unbind_ext( LDAPObject* self, PyObject* args )
  279. {
  280. PyObject *serverctrls = Py_None;
  281. PyObject *clientctrls = Py_None;
  282. LDAPControl** server_ldcs = NULL;
  283. LDAPControl** client_ldcs = NULL;
  284. int ldaperror;
  285. if (!PyArg_ParseTuple( args, "|OO", &serverctrls, &clientctrls)) return NULL;
  286. if (not_valid(self)) return NULL;
  287. if (!PyNone_Check(serverctrls)) {
  288. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  289. return NULL;
  290. }
  291. if (!PyNone_Check(clientctrls)) {
  292. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  293. return NULL;
  294. }
  295. LDAP_BEGIN_ALLOW_THREADS( self );
  296. ldaperror = ldap_unbind_ext( self->ldap, server_ldcs, client_ldcs );
  297. LDAP_END_ALLOW_THREADS( self );
  298. LDAPControl_List_DEL( server_ldcs );
  299. LDAPControl_List_DEL( client_ldcs );
  300. if ( ldaperror!=LDAP_SUCCESS )
  301. return LDAPerror( self->ldap, "ldap_unbind_ext" );
  302. self->valid = 0;
  303. Py_INCREF(Py_None);
  304. return Py_None;
  305. }
  306. /* ldap_abandon_ext */
  307. static PyObject*
  308. l_ldap_abandon_ext( LDAPObject* self, PyObject* args )
  309. {
  310. int msgid;
  311. PyObject *serverctrls = Py_None;
  312. PyObject *clientctrls = Py_None;
  313. LDAPControl** server_ldcs = NULL;
  314. LDAPControl** client_ldcs = NULL;
  315. int ldaperror;
  316. if (!PyArg_ParseTuple( args, "i|OO", &msgid, &serverctrls, &clientctrls)) return NULL;
  317. if (not_valid(self)) return NULL;
  318. if (!PyNone_Check(serverctrls)) {
  319. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  320. return NULL;
  321. }
  322. if (!PyNone_Check(clientctrls)) {
  323. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  324. return NULL;
  325. }
  326. LDAP_BEGIN_ALLOW_THREADS( self );
  327. ldaperror = ldap_abandon_ext( self->ldap, msgid, server_ldcs, client_ldcs );
  328. LDAP_END_ALLOW_THREADS( self );
  329. LDAPControl_List_DEL( server_ldcs );
  330. LDAPControl_List_DEL( client_ldcs );
  331. if ( ldaperror!=LDAP_SUCCESS )
  332. return LDAPerror( self->ldap, "ldap_abandon_ext" );
  333. Py_INCREF(Py_None);
  334. return Py_None;
  335. }
  336. /* ldap_add_ext */
  337. static PyObject *
  338. l_ldap_add_ext( LDAPObject* self, PyObject *args )
  339. {
  340. char *dn;
  341. PyObject *modlist;
  342. PyObject *serverctrls = Py_None;
  343. PyObject *clientctrls = Py_None;
  344. LDAPControl** server_ldcs = NULL;
  345. LDAPControl** client_ldcs = NULL;
  346. int msgid;
  347. int ldaperror;
  348. LDAPMod **mods;
  349. if (!PyArg_ParseTuple( args, "sO|OO", &dn, &modlist, &serverctrls, &clientctrls )) return NULL;
  350. if (not_valid(self)) return NULL;
  351. mods = List_to_LDAPMods( modlist, 1 );
  352. if (mods == NULL)
  353. return NULL;
  354. if (!PyNone_Check(serverctrls)) {
  355. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  356. return NULL;
  357. }
  358. if (!PyNone_Check(clientctrls)) {
  359. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  360. return NULL;
  361. }
  362. LDAP_BEGIN_ALLOW_THREADS( self );
  363. ldaperror = ldap_add_ext( self->ldap, dn, mods, server_ldcs, client_ldcs, &msgid);
  364. LDAP_END_ALLOW_THREADS( self );
  365. LDAPMods_DEL( mods );
  366. LDAPControl_List_DEL( server_ldcs );
  367. LDAPControl_List_DEL( client_ldcs );
  368. if ( ldaperror!=LDAP_SUCCESS )
  369. return LDAPerror( self->ldap, "ldap_add_ext" );
  370. return PyInt_FromLong(msgid);
  371. }
  372. /* ldap_simple_bind */
  373. static PyObject*
  374. l_ldap_simple_bind( LDAPObject* self, PyObject* args )
  375. {
  376. char *who;
  377. int msgid;
  378. int ldaperror;
  379. Py_ssize_t cred_len;
  380. PyObject *serverctrls = Py_None;
  381. PyObject *clientctrls = Py_None;
  382. LDAPControl** server_ldcs = NULL;
  383. LDAPControl** client_ldcs = NULL;
  384. struct berval cred;
  385. if (!PyArg_ParseTuple( args, "ss#|OO", &who, &cred.bv_val, &cred_len, &serverctrls, &clientctrls )) return NULL;
  386. cred.bv_len = (ber_len_t) cred_len;
  387. if (not_valid(self)) return NULL;
  388. if (!PyNone_Check(serverctrls)) {
  389. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  390. return NULL;
  391. }
  392. if (!PyNone_Check(clientctrls)) {
  393. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  394. return NULL;
  395. }
  396. LDAP_BEGIN_ALLOW_THREADS( self );
  397. ldaperror = ldap_sasl_bind( self->ldap, who, LDAP_SASL_SIMPLE, &cred, server_ldcs, client_ldcs, &msgid);
  398. LDAP_END_ALLOW_THREADS( self );
  399. LDAPControl_List_DEL( server_ldcs );
  400. LDAPControl_List_DEL( client_ldcs );
  401. if ( ldaperror!=LDAP_SUCCESS )
  402. return LDAPerror( self->ldap, "ldap_simple_bind" );
  403. return PyInt_FromLong( msgid );
  404. }
  405. #ifdef HAVE_SASL
  406. /* The following functions implement SASL binds. A new method
  407. sasl_interactive_bind_s(bind_dn, sasl_mechanism) has been introduced.
  408. * The bind_dn argument will be passed to the c library; however,
  409. normally it is not needed and should be an empty string.
  410. * The sasl_mechanism argument is an instance of a class that
  411. implements a callback interface. For convenience, it should be
  412. derived from the sasl class (which lives in the ldap.sasl module).
  413. See the module documentation for more information.
  414. Check your /usr/lib/sasl/ directory for locally installed SASL
  415. auth modules ("mechanisms"), or try
  416. ldapsearch -b "" -s base -LLL -x supportedSASLMechanisms
  417. (perhaps with an additional -h and -p argument for ldap host and
  418. port). The latter will show you which SASL mechanisms are known
  419. to the LDAP server. If you do not want to set up Kerberos, you
  420. can still use SASL binds. Your authentication data should then be
  421. stored in /etc/sasldb (see saslpasswd(8)). If the LDAP server
  422. does not find the sasldb, it wont allow for DIGEST-MD5 and
  423. CRAM-MD5. One important thing to get started with sasldb: you
  424. should first add a dummy user (saslpasswd -c dummy), and this
  425. will give you some strange error messages. Then delete the dummy
  426. user (saslpasswd -d dummy), and now you can start adding users to
  427. your sasldb (again, use the -c switch). Strange, eh?
  428. * The sasl_mechanism object must implement a method, which will be
  429. called by the sasl lib several times. The prototype of the
  430. callback looks like this: callback(id, challenge, prompt,
  431. defresult) has to return a string (or maybe None). The id
  432. argument specifies, which information should be passed back to
  433. the SASL lib (see SASL_CB_xxx in sasl.h)
  434. A nice "Howto get LDAPv3 up and running with Kerberos and SSL" can
  435. be found at http://www.bayour.com/LDAPv3-HOWTO.html. Instead of
  436. MIT Kerberos, I used Heimdal for my tests (since it is included
  437. with SuSE Linux).
  438. Todo:
  439. * Find a better interface than the python callback. This is
  440. really ugly. Perhaps one could make use of a sasl class, like
  441. in the perl ldap module.
  442. * Thread safety?
  443. * Memory Management?
  444. * Write more docs
  445. * ...
  446. */
  447. static int interaction ( unsigned flags,
  448. sasl_interact_t *interact,
  449. PyObject* SASLObject )
  450. {
  451. /* const char *dflt = interact->defresult; */
  452. PyObject *result;
  453. char *c_result;
  454. result = PyObject_CallMethod(SASLObject,
  455. "callback",
  456. "isss",
  457. interact->id, /* see sasl.h */
  458. interact->challenge,
  459. interact->prompt,
  460. interact->defresult);
  461. if (result == NULL)
  462. /*searching for a better error code */
  463. return LDAP_OPERATIONS_ERROR;
  464. c_result = PyString_AsString(result); /*xxx Error checking?? */
  465. /* according to the sasl docs, we should malloc() the returned
  466. string only for calls where interact->id == SASL_CB_PASS, so we
  467. probably leak a few bytes per ldap bind. However, if I restrict
  468. the strdup() to this case, I get segfaults. Should probably be
  469. fixed sometimes.
  470. */
  471. interact->result = strdup( c_result );
  472. if (interact->result == NULL)
  473. return LDAP_OPERATIONS_ERROR;
  474. interact->len = strlen(c_result);
  475. /* We _should_ overwrite the python string buffer for security
  476. reasons, however we may not (api/stringObjects.html). Any ideas?
  477. */
  478. Py_DECREF(result); /*not needed any longer */
  479. result = NULL;
  480. return LDAP_SUCCESS;
  481. }
  482. /*
  483. This function will be called by ldap_sasl_interactive_bind(). The
  484. "*in" is an array of sasl_interact_t's (see sasl.h for a
  485. reference). The last interact in the array has an interact->id of
  486. SASL_CB_LIST_END.
  487. */
  488. int py_ldap_sasl_interaction( LDAP *ld,
  489. unsigned flags,
  490. void *defaults,
  491. void *in )
  492. {
  493. /* These are just typecasts */
  494. sasl_interact_t *interact = (sasl_interact_t *) in;
  495. PyObject *SASLObject = (PyObject *) defaults;
  496. /* Loop over the array of sasl_interact_t structs */
  497. while( interact->id != SASL_CB_LIST_END ) {
  498. int rc = 0;
  499. rc = interaction( flags, interact, SASLObject );
  500. if( rc ) return rc;
  501. interact++;
  502. }
  503. return LDAP_SUCCESS;
  504. }
  505. static PyObject*
  506. l_ldap_sasl_interactive_bind_s( LDAPObject* self, PyObject* args )
  507. {
  508. char *c_mechanism;
  509. char *who;
  510. PyObject *serverctrls = Py_None;
  511. PyObject *clientctrls = Py_None;
  512. LDAPControl** server_ldcs = NULL;
  513. LDAPControl** client_ldcs = NULL;
  514. PyObject *SASLObject = NULL;
  515. PyObject *mechanism = NULL;
  516. int msgid;
  517. static unsigned sasl_flags = LDAP_SASL_QUIET;
  518. /*
  519. * In Python 2.3+, a "I" format argument indicates that we're either converting
  520. * the Python object into a long or an unsigned int. In versions prior to that,
  521. * it will always convert to a long. Since the sasl_flags variable is an
  522. * unsigned int, we need to use the "I" flag if we're running Python 2.3+ and a
  523. * "i" otherwise.
  524. */
  525. #if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 3)
  526. if (!PyArg_ParseTuple(args, "sOOOi", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags ))
  527. #else
  528. if (!PyArg_ParseTuple(args, "sOOOI", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags ))
  529. #endif
  530. return NULL;
  531. if (not_valid(self)) return NULL;
  532. if (!PyNone_Check(serverctrls)) {
  533. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  534. return NULL;
  535. }
  536. if (!PyNone_Check(clientctrls)) {
  537. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  538. return NULL;
  539. }
  540. /* now we extract the sasl mechanism from the SASL Object */
  541. mechanism = PyObject_GetAttrString(SASLObject, "mech");
  542. if (mechanism == NULL) return NULL;
  543. c_mechanism = PyString_AsString(mechanism);
  544. Py_DECREF(mechanism);
  545. mechanism = NULL;
  546. /* Don't know if it is the "intended use" of the defaults
  547. parameter of ldap_sasl_interactive_bind_s when we pass the
  548. Python object SASLObject, but passing it through some
  549. static variable would destroy thread safety, IMHO.
  550. */
  551. msgid = ldap_sasl_interactive_bind_s(self->ldap,
  552. who,
  553. c_mechanism,
  554. (LDAPControl**) server_ldcs,
  555. (LDAPControl**) client_ldcs,
  556. sasl_flags,
  557. py_ldap_sasl_interaction,
  558. SASLObject);
  559. LDAPControl_List_DEL( server_ldcs );
  560. LDAPControl_List_DEL( client_ldcs );
  561. if (msgid != LDAP_SUCCESS)
  562. return LDAPerror( self->ldap, "ldap_sasl_interactive_bind_s" );
  563. return PyInt_FromLong( msgid );
  564. }
  565. #endif
  566. #ifdef LDAP_API_FEATURE_CANCEL
  567. /* ldap_cancel */
  568. static PyObject*
  569. l_ldap_cancel( LDAPObject* self, PyObject* args )
  570. {
  571. int msgid;
  572. int cancelid;
  573. PyObject *serverctrls = Py_None;
  574. PyObject *clientctrls = Py_None;
  575. LDAPControl** server_ldcs = NULL;
  576. LDAPControl** client_ldcs = NULL;
  577. int ldaperror;
  578. if (!PyArg_ParseTuple( args, "i|OO", &cancelid, &serverctrls, &clientctrls)) return NULL;
  579. if (not_valid(self)) return NULL;
  580. if (!PyNone_Check(serverctrls)) {
  581. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  582. return NULL;
  583. }
  584. if (!PyNone_Check(clientctrls)) {
  585. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  586. return NULL;
  587. }
  588. LDAP_BEGIN_ALLOW_THREADS( self );
  589. ldaperror = ldap_cancel( self->ldap, cancelid, server_ldcs, client_ldcs, &msgid );
  590. LDAP_END_ALLOW_THREADS( self );
  591. LDAPControl_List_DEL( server_ldcs );
  592. LDAPControl_List_DEL( client_ldcs );
  593. if ( ldaperror!=LDAP_SUCCESS )
  594. return LDAPerror( self->ldap, "ldap_cancel" );
  595. return PyInt_FromLong( msgid );
  596. }
  597. #endif
  598. /* ldap_compare_ext */
  599. static PyObject *
  600. l_ldap_compare_ext( LDAPObject* self, PyObject *args )
  601. {
  602. char *dn, *attr;
  603. PyObject *serverctrls = Py_None;
  604. PyObject *clientctrls = Py_None;
  605. LDAPControl** server_ldcs = NULL;
  606. LDAPControl** client_ldcs = NULL;
  607. int msgid;
  608. int ldaperror;
  609. Py_ssize_t value_len;
  610. struct berval value;
  611. if (!PyArg_ParseTuple( args, "sss#|OO", &dn, &attr, &value.bv_val, &value_len, &serverctrls, &clientctrls )) return NULL;
  612. value.bv_len = (ber_len_t) value_len;
  613. if (not_valid(self)) return NULL;
  614. if (!PyNone_Check(serverctrls)) {
  615. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  616. return NULL;
  617. }
  618. if (!PyNone_Check(clientctrls)) {
  619. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  620. return NULL;
  621. }
  622. LDAP_BEGIN_ALLOW_THREADS( self );
  623. ldaperror = ldap_compare_ext( self->ldap, dn, attr, &value, server_ldcs, client_ldcs, &msgid );
  624. LDAP_END_ALLOW_THREADS( self );
  625. LDAPControl_List_DEL( server_ldcs );
  626. LDAPControl_List_DEL( client_ldcs );
  627. if ( ldaperror!=LDAP_SUCCESS )
  628. return LDAPerror( self->ldap, "ldap_compare_ext" );
  629. return PyInt_FromLong( msgid );
  630. }
  631. /* ldap_delete_ext */
  632. static PyObject *
  633. l_ldap_delete_ext( LDAPObject* self, PyObject *args )
  634. {
  635. char *dn;
  636. PyObject *serverctrls = Py_None;
  637. PyObject *clientctrls = Py_None;
  638. LDAPControl** server_ldcs = NULL;
  639. LDAPControl** client_ldcs = NULL;
  640. int msgid;
  641. int ldaperror;
  642. if (!PyArg_ParseTuple( args, "s|OO", &dn, &serverctrls, &clientctrls )) return NULL;
  643. if (not_valid(self)) return NULL;
  644. if (!PyNone_Check(serverctrls)) {
  645. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  646. return NULL;
  647. }
  648. if (!PyNone_Check(clientctrls)) {
  649. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  650. return NULL;
  651. }
  652. LDAP_BEGIN_ALLOW_THREADS( self );
  653. ldaperror = ldap_delete_ext( self->ldap, dn, server_ldcs, client_ldcs, &msgid );
  654. LDAP_END_ALLOW_THREADS( self );
  655. LDAPControl_List_DEL( server_ldcs );
  656. LDAPControl_List_DEL( client_ldcs );
  657. if ( ldaperror!=LDAP_SUCCESS )
  658. return LDAPerror( self->ldap, "ldap_delete_ext" );
  659. return PyInt_FromLong(msgid);
  660. }
  661. /* ldap_modify_ext */
  662. static PyObject *
  663. l_ldap_modify_ext( LDAPObject* self, PyObject *args )
  664. {
  665. char *dn;
  666. PyObject *modlist;
  667. PyObject *serverctrls = Py_None;
  668. PyObject *clientctrls = Py_None;
  669. LDAPControl** server_ldcs = NULL;
  670. LDAPControl** client_ldcs = NULL;
  671. int msgid;
  672. int ldaperror;
  673. LDAPMod **mods;
  674. if (!PyArg_ParseTuple( args, "sO|OO", &dn, &modlist, &serverctrls, &clientctrls )) return NULL;
  675. if (not_valid(self)) return NULL;
  676. mods = List_to_LDAPMods( modlist, 0 );
  677. if (mods == NULL)
  678. return NULL;
  679. if (!PyNone_Check(serverctrls)) {
  680. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  681. return NULL;
  682. }
  683. if (!PyNone_Check(clientctrls)) {
  684. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  685. return NULL;
  686. }
  687. LDAP_BEGIN_ALLOW_THREADS( self );
  688. ldaperror = ldap_modify_ext( self->ldap, dn, mods, server_ldcs, client_ldcs, &msgid );
  689. LDAP_END_ALLOW_THREADS( self );
  690. LDAPMods_DEL( mods );
  691. LDAPControl_List_DEL( server_ldcs );
  692. LDAPControl_List_DEL( client_ldcs );
  693. if ( ldaperror!=LDAP_SUCCESS )
  694. return LDAPerror( self->ldap, "ldap_modify_ext" );
  695. return PyInt_FromLong( msgid );
  696. }
  697. /* ldap_rename */
  698. static PyObject *
  699. l_ldap_rename( LDAPObject* self, PyObject *args )
  700. {
  701. char *dn, *newrdn;
  702. char *newSuperior = NULL;
  703. int delold = 1;
  704. PyObject *serverctrls = Py_None;
  705. PyObject *clientctrls = Py_None;
  706. LDAPControl** server_ldcs = NULL;
  707. LDAPControl** client_ldcs = NULL;
  708. int msgid;
  709. int ldaperror;
  710. if (!PyArg_ParseTuple( args, "ss|ziOO", &dn, &newrdn, &newSuperior, &delold, &serverctrls, &clientctrls ))
  711. return NULL;
  712. if (not_valid(self)) return NULL;
  713. if (!PyNone_Check(serverctrls)) {
  714. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  715. return NULL;
  716. }
  717. if (!PyNone_Check(clientctrls)) {
  718. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  719. return NULL;
  720. }
  721. LDAP_BEGIN_ALLOW_THREADS( self );
  722. ldaperror = ldap_rename( self->ldap, dn, newrdn, newSuperior, delold, server_ldcs, client_ldcs, &msgid );
  723. LDAP_END_ALLOW_THREADS( self );
  724. LDAPControl_List_DEL( server_ldcs );
  725. LDAPControl_List_DEL( client_ldcs );
  726. if ( ldaperror!=LDAP_SUCCESS )
  727. return LDAPerror( self->ldap, "ldap_rename" );
  728. return PyInt_FromLong( msgid );
  729. }
  730. /* ldap_result3 */
  731. static PyObject *
  732. l_ldap_result3( LDAPObject* self, PyObject *args )
  733. {
  734. int msgid = LDAP_RES_ANY;
  735. int all = 1;
  736. double timeout = -1.0;
  737. struct timeval tv;
  738. struct timeval* tvp;
  739. int res_type;
  740. LDAPMessage *msg = NULL;
  741. PyObject *result_str, *retval, *pmsg, *pyctrls = 0;
  742. int res_msgid = 0;
  743. if (!PyArg_ParseTuple( args, "|iid", &msgid, &all, &timeout ))
  744. return NULL;
  745. if (not_valid(self)) return NULL;
  746. if (timeout >= 0) {
  747. tvp = &tv;
  748. set_timeval_from_double( tvp, timeout );
  749. } else {
  750. tvp = NULL;
  751. }
  752. LDAP_BEGIN_ALLOW_THREADS( self );
  753. res_type = ldap_result( self->ldap, msgid, all, tvp, &msg );
  754. LDAP_END_ALLOW_THREADS( self );
  755. if (res_type < 0) /* LDAP or system error */
  756. return LDAPerror( self->ldap, "ldap_result3" );
  757. if (res_type == 0) {
  758. /* Polls return (None, None, None, None); timeouts raise an exception */
  759. if (timeout == 0)
  760. return Py_BuildValue("(OOOO)", Py_None, Py_None, Py_None, Py_None);
  761. else
  762. return LDAPerr(LDAP_TIMEOUT);
  763. }
  764. if (msg)
  765. res_msgid = ldap_msgid(msg);
  766. int result;
  767. char **refs = NULL;
  768. LDAPControl **serverctrls = 0;
  769. LDAP_BEGIN_ALLOW_THREADS( self );
  770. ldap_parse_result( self->ldap, msg, &result, NULL, NULL, &refs,
  771. &serverctrls, 0 );
  772. LDAP_END_ALLOW_THREADS( self );
  773. if (result != LDAP_SUCCESS) { /* result error */
  774. char *e, err[1024];
  775. if (result == LDAP_REFERRAL && refs && refs[0]) {
  776. snprintf(err, sizeof(err), "Referral:\n%s", refs[0]);
  777. e = err;
  778. } else
  779. e = "ldap_parse_result";
  780. ldap_msgfree(msg);
  781. return LDAPerror( self->ldap, e );
  782. }
  783. if (!(pyctrls = LDAPControls_to_List(serverctrls))) {
  784. int err = LDAP_NO_MEMORY;
  785. ldap_set_option(self->ldap, LDAP_OPT_ERROR_NUMBER, &err);
  786. ldap_msgfree(msg);
  787. return LDAPerror(self->ldap, "LDAPControls_to_List");
  788. }
  789. ldap_controls_free(serverctrls);
  790. pmsg = LDAPmessage_to_python( self->ldap, msg );
  791. result_str = LDAPconstant( res_type );
  792. if (pmsg == NULL) {
  793. retval = NULL;
  794. } else {
  795. if (pyctrls != NULL) {
  796. retval = Py_BuildValue("(OOiO)", result_str, pmsg, res_msgid,
  797. pyctrls);
  798. } else {
  799. PyObject *pNewList = PyList_New(0);
  800. retval = Py_BuildValue("(OOiO)", result_str, pmsg, res_msgid,
  801. pNewList);
  802. Py_DECREF(pNewList);
  803. }
  804. if (pmsg != Py_None) {
  805. Py_DECREF(pmsg);
  806. }
  807. }
  808. Py_XDECREF(pyctrls);
  809. Py_DECREF(result_str);
  810. return retval;
  811. }
  812. /* ldap_search_ext */
  813. static PyObject*
  814. l_ldap_search_ext( LDAPObject* self, PyObject* args )
  815. {
  816. char *base;
  817. int scope;
  818. char *filter;
  819. PyObject *attrlist = Py_None;
  820. char **attrs;
  821. int attrsonly = 0;
  822. PyObject *serverctrls = Py_None;
  823. PyObject *clientctrls = Py_None;
  824. LDAPControl** server_ldcs = NULL;
  825. LDAPControl** client_ldcs = NULL;
  826. double timeout = -1.0;
  827. struct timeval tv;
  828. struct timeval* tvp;
  829. int sizelimit = 0;
  830. int msgid;
  831. int ldaperror;
  832. if (!PyArg_ParseTuple( args, "sis|OiOOdi",
  833. &base, &scope, &filter, &attrlist, &attrsonly,
  834. &serverctrls, &clientctrls, &timeout, &sizelimit )) return NULL;
  835. if (not_valid(self)) return NULL;
  836. if (!attrs_from_List( attrlist, &attrs ))
  837. return NULL;
  838. if (timeout >= 0) {
  839. tvp = &tv;
  840. set_timeval_from_double( tvp, timeout );
  841. } else {
  842. tvp = NULL;
  843. }
  844. if (!PyNone_Check(serverctrls)) {
  845. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  846. return NULL;
  847. }
  848. if (!PyNone_Check(clientctrls)) {
  849. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  850. return NULL;
  851. }
  852. LDAP_BEGIN_ALLOW_THREADS( self );
  853. ldaperror = ldap_search_ext( self->ldap, base, scope, filter, attrs, attrsonly,
  854. server_ldcs, client_ldcs, tvp, sizelimit, &msgid );
  855. LDAP_END_ALLOW_THREADS( self );
  856. free_attrs( &attrs );
  857. LDAPControl_List_DEL( server_ldcs );
  858. LDAPControl_List_DEL( client_ldcs );
  859. if ( ldaperror!=LDAP_SUCCESS )
  860. return LDAPerror( self->ldap, "ldap_search_ext" );
  861. return PyInt_FromLong( msgid );
  862. }
  863. /* ldap_whoami_s (available since OpenLDAP 2.1.13) */
  864. static PyObject*
  865. l_ldap_whoami_s( LDAPObject* self, PyObject* args )
  866. {
  867. PyObject *serverctrls = Py_None;
  868. PyObject *clientctrls = Py_None;
  869. LDAPControl** server_ldcs = NULL;
  870. LDAPControl** client_ldcs = NULL;
  871. struct berval *bvalue = NULL;
  872. PyObject *result;
  873. int ldaperror;
  874. if (!PyArg_ParseTuple( args, "|OO", &serverctrls, &clientctrls)) return NULL;
  875. if (!PyNone_Check(serverctrls)) {
  876. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  877. return NULL;
  878. }
  879. if (!PyNone_Check(clientctrls)) {
  880. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  881. return NULL;
  882. }
  883. LDAP_BEGIN_ALLOW_THREADS( self );
  884. ldaperror = ldap_whoami_s( self->ldap, &bvalue, server_ldcs, client_ldcs );
  885. LDAP_END_ALLOW_THREADS( self );
  886. LDAPControl_List_DEL( server_ldcs );
  887. LDAPControl_List_DEL( client_ldcs );
  888. if ( ldaperror!=LDAP_SUCCESS )
  889. return LDAPerror( self->ldap, "ldap_whoami_s" );
  890. result = LDAPberval_to_object(bvalue);
  891. return result;
  892. }
  893. #ifdef HAVE_TLS
  894. /* ldap_start_tls_s */
  895. static PyObject*
  896. l_ldap_start_tls_s( LDAPObject* self, PyObject* args )
  897. {
  898. int result;
  899. if (!PyArg_ParseTuple( args, "" )) return NULL;
  900. if (not_valid(self)) return NULL;
  901. result = ldap_start_tls_s( self->ldap, NULL, NULL );
  902. if ( result != LDAP_SUCCESS ){
  903. ldap_set_option(self->ldap, LDAP_OPT_ERROR_NUMBER, &result);
  904. return LDAPerror( self->ldap, "ldap_start_tls_s" );
  905. }
  906. Py_INCREF(Py_None);
  907. return Py_None;
  908. }
  909. #endif
  910. /* ldap_set_option */
  911. static PyObject*
  912. l_ldap_set_option(PyObject* self, PyObject *args)
  913. {
  914. PyObject *value;
  915. int option;
  916. if (!PyArg_ParseTuple(args, "iO:set_option", &option, &value))
  917. return NULL;
  918. if (LDAP_set_option((LDAPObject *)self, option, value) == -1)
  919. return NULL;
  920. Py_INCREF(Py_None);
  921. return Py_None;
  922. }
  923. /* ldap_get_option */
  924. static PyObject*
  925. l_ldap_get_option(PyObject* self, PyObject *args)
  926. {
  927. int option;
  928. if (!PyArg_ParseTuple(args, "i:get_option", &option))
  929. return NULL;
  930. return LDAP_get_option((LDAPObject *)self, option);
  931. }
  932. /* ldap_passwd */
  933. static PyObject *
  934. l_ldap_passwd( LDAPObject* self, PyObject *args )
  935. {
  936. struct berval user;
  937. Py_ssize_t user_len;
  938. struct berval oldpw;
  939. Py_ssize_t oldpw_len;
  940. struct berval newpw;
  941. Py_ssize_t newpw_len;
  942. PyObject *serverctrls = Py_None;
  943. PyObject *clientctrls = Py_None;
  944. LDAPControl** server_ldcs = NULL;
  945. LDAPControl** client_ldcs = NULL;
  946. int msgid;
  947. int ldaperror;
  948. if (!PyArg_ParseTuple( args, "z#z#z#|OO", &user.bv_val, &user_len, &oldpw.bv_val, &oldpw_len, &newpw.bv_val, &newpw_len, &serverctrls, &clientctrls ))
  949. return NULL;
  950. user.bv_len = (ber_len_t) user_len;
  951. oldpw.bv_len = (ber_len_t) oldpw_len;
  952. newpw.bv_len = (ber_len_t) newpw_len;
  953. if (not_valid(self)) return NULL;
  954. if (!PyNone_Check(serverctrls)) {
  955. if (!LDAPControls_from_object(serverctrls, &server_ldcs))
  956. return NULL;
  957. }
  958. if (!PyNone_Check(clientctrls)) {
  959. if (!LDAPControls_from_object(clientctrls, &client_ldcs))
  960. return NULL;
  961. }
  962. LDAP_BEGIN_ALLOW_THREADS( self );
  963. ldaperror = ldap_passwd( self->ldap,
  964. user.bv_val != NULL ? &user : NULL,
  965. oldpw.bv_val != NULL ? &oldpw : NULL,
  966. newpw.bv_val != NULL ? &newpw : NULL,
  967. server_ldcs,
  968. client_ldcs,
  969. &msgid );
  970. LDAP_END_ALLOW_THREADS( self );
  971. LDAPControl_List_DEL( server_ldcs );
  972. LDAPControl_List_DEL( client_ldcs );
  973. if ( ldaperror!=LDAP_SUCCESS )
  974. return LDAPerror( self->ldap, "ldap_passwd" );
  975. return PyInt_FromLong( msgid );
  976. }
  977. /* methods */
  978. static PyMethodDef methods[] = {
  979. {"unbind_ext", (PyCFunction)l_ldap_unbind_ext, METH_VARARGS },
  980. {"abandon_ext", (PyCFunction)l_ldap_abandon_ext, METH_VARARGS },
  981. {"add_ext", (PyCFunction)l_ldap_add_ext, METH_VARARGS },
  982. {"simple_bind", (PyCFunction)l_ldap_simple_bind, METH_VARARGS },
  983. #ifdef HAVE_SASL
  984. {"sasl_interactive_bind_s", (PyCFunction)l_ldap_sasl_interactive_bind_s, METH_VARARGS },
  985. #endif
  986. {"compare_ext", (PyCFunction)l_ldap_compare_ext, METH_VARARGS },
  987. {"delete_ext", (PyCFunction)l_ldap_delete_ext, METH_VARARGS },
  988. {"modify_ext", (PyCFunction)l_ldap_modify_ext, METH_VARARGS },
  989. {"rename", (PyCFunction)l_ldap_rename, METH_VARARGS },
  990. {"result3", (PyCFunction)l_ldap_result3, METH_VARARGS },
  991. {"search_ext", (PyCFunction)l_ldap_search_ext, METH_VARARGS },
  992. #ifdef HAVE_TLS
  993. {"start_tls_s", (PyCFunction)l_ldap_start_tls_s, METH_VARARGS },
  994. #endif
  995. {"whoami_s", (PyCFunction)l_ldap_whoami_s, METH_VARARGS },
  996. {"passwd", (PyCFunction)l_ldap_passwd, METH_VARARGS },
  997. {"set_option", (PyCFunction)l_ldap_set_option, METH_VARARGS },
  998. {"get_option", (PyCFunction)l_ldap_get_option, METH_VARARGS },
  999. #ifdef LDAP_API_FEATURE_CANCEL
  1000. {"cancel", (PyCFunction)l_ldap_cancel, METH_VARARGS },
  1001. #endif
  1002. { NULL, NULL }
  1003. };
  1004. /* get attribute */
  1005. static PyObject*
  1006. getattr(LDAPObject* self, char* name)
  1007. {
  1008. return Py_FindMethod(methods, (PyObject*)self, name);
  1009. }
  1010. /* set attribute */
  1011. static int
  1012. setattr(LDAPObject* self, char* name, PyObject* value)
  1013. {
  1014. PyErr_SetString(PyExc_AttributeError, name);
  1015. return -1;
  1016. }
  1017. /* type entry */
  1018. PyTypeObject LDAP_Type = {
  1019. #if defined(MS_WINDOWS) || defined(__CYGWIN__)
  1020. /* see http://www.python.org/doc/FAQ.html#3.24 */
  1021. PyObject_HEAD_INIT(NULL)
  1022. #else /* ! MS_WINDOWS */
  1023. PyObject_HEAD_INIT(&PyType_Type)
  1024. #endif /* MS_WINDOWS */
  1025. 0, /*ob_size*/
  1026. "LDAP", /*tp_name*/
  1027. sizeof(LDAPObject), /*tp_basicsize*/
  1028. 0, /*tp_itemsize*/
  1029. /* methods */
  1030. (destructor)dealloc, /*tp_dealloc*/
  1031. 0, /*tp_print*/
  1032. (getattrfunc)getattr, /*tp_getattr*/
  1033. (setattrfunc)setattr, /*tp_setattr*/
  1034. 0, /*tp_compare*/
  1035. 0, /*tp_repr*/
  1036. 0, /*tp_as_number*/
  1037. 0, /*tp_as_sequence*/
  1038. 0, /*tp_as_mapping*/
  1039. 0, /*tp_hash*/
  1040. };