s4-drs: Function for accessing dsdb_load_partition_usn from Python
[samba.git] / source4 / scripting / python / pyglue.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
4    Copyright (C) Matthias Dieter Wallnöfer          2009
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <Python.h>
21 #include "includes.h"
22 #include "ldb.h"
23 #include "ldb_errors.h"
24 #include "ldb_wrap.h"
25 #include "param/param.h"
26 #include "auth/credentials/credentials.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "lib/ldb-samba/ldif_handlers.h"
29 #include "librpc/ndr/libndr.h"
30 #include "version.h"
31 #include "lib/ldb/pyldb.h"
32 #include "libcli/util/pyerrors.h"
33 #include "libcli/security/security.h"
34 #include "auth/pyauth.h"
35 #include "param/pyparam.h"
36 #include "auth/credentials/pycredentials.h"
37
38 /* FIXME: These should be in a header file somewhere, once we finish moving
39  * away from SWIG .. */
40 #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
41 /*      if (!PyLdb_Check(py_ldb)) { \
42                 PyErr_SetString(py_ldb_get_exception(), "Ldb connection object required"); \
43                 return NULL; \
44         } */\
45         ldb = PyLdb_AsLdbContext(py_ldb);
46
47 static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_ctx)
48 {
49         if (ret == LDB_ERR_PYTHON_EXCEPTION)
50                 return; /* Python exception should already be set, just keep that */
51
52         PyErr_SetObject(error, 
53                         Py_BuildValue(discard_const_p(char, "(i,s)"), ret,
54                         ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx)));
55 }
56
57 static PyObject *py_ldb_get_exception(void)
58 {
59         PyObject *mod = PyImport_ImportModule("ldb");
60         if (mod == NULL)
61                 return NULL;
62
63         return PyObject_GetAttrString(mod, "LdbError");
64 }
65
66 static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
67 {
68         int len;
69         PyObject *ret;
70         char *retstr;
71         if (!PyArg_ParseTuple(args, "i", &len))
72                 return NULL;
73
74         retstr = generate_random_str(NULL, len);
75         ret = PyString_FromString(retstr);
76         talloc_free(retstr);
77         return ret;
78 }
79
80 static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
81 {
82         time_t t;
83         NTTIME nt;
84         if (!PyArg_ParseTuple(args, "I", &t))
85                 return NULL;
86
87         unix_to_nt_time(&nt, t);
88
89         return PyInt_FromLong((uint64_t)nt);
90 }
91
92 static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
93 {
94         unsigned level;
95         if (!PyArg_ParseTuple(args, "I", &level))
96                 return NULL;
97         (DEBUGLEVEL) = level;
98         Py_RETURN_NONE;
99 }
100
101 static PyObject *py_ldb_set_session_info(PyObject *self, PyObject *args)
102 {
103         PyObject *py_session_info, *py_ldb;
104         struct auth_session_info *info;
105         struct ldb_context *ldb;
106         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_session_info))
107                 return NULL;
108
109         PyErr_LDB_OR_RAISE(py_ldb, ldb);
110         /*if (!PyAuthSession_Check(py_session_info)) {
111                 PyErr_SetString(PyExc_TypeError, "Expected session info object");
112                 return NULL;
113         }*/
114
115         info = PyAuthSession_AsSession(py_session_info);
116
117         ldb_set_opaque(ldb, "sessionInfo", info);
118
119         Py_RETURN_NONE;
120 }
121
122 static PyObject *py_ldb_set_credentials(PyObject *self, PyObject *args)
123 {
124         PyObject *py_creds, *py_ldb;
125         struct cli_credentials *creds;
126         struct ldb_context *ldb;
127         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_creds))
128                 return NULL;
129
130         PyErr_LDB_OR_RAISE(py_ldb, ldb);
131         
132         creds = cli_credentials_from_py_object(py_creds);
133         if (creds == NULL) {
134                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
135                 return NULL;
136         }
137
138         ldb_set_opaque(ldb, "credentials", creds);
139
140         Py_RETURN_NONE;
141 }
142
143 static PyObject *py_ldb_set_loadparm(PyObject *self, PyObject *args)
144 {
145         PyObject *py_lp_ctx, *py_ldb;
146         struct loadparm_context *lp_ctx;
147         struct ldb_context *ldb;
148         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_lp_ctx))
149                 return NULL;
150
151         PyErr_LDB_OR_RAISE(py_ldb, ldb);
152
153         lp_ctx = lp_from_py_object(py_lp_ctx);
154         if (lp_ctx == NULL) {
155                 PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
156                 return NULL;
157         }
158
159         ldb_set_opaque(ldb, "loadparm", lp_ctx);
160
161         Py_RETURN_NONE;
162 }
163
164 static PyObject *py_ldb_set_utf8_casefold(PyObject *self, PyObject *args)
165 {
166         PyObject *py_ldb;
167         struct ldb_context *ldb;
168
169         if (!PyArg_ParseTuple(args, "O", &py_ldb))
170                 return NULL;
171
172         PyErr_LDB_OR_RAISE(py_ldb, ldb);
173
174         ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
175
176         Py_RETURN_NONE;
177 }
178
179 static PyObject *py_samdb_set_domain_sid(PyLdbObject *self, PyObject *args)
180
181         PyObject *py_ldb, *py_sid;
182         struct ldb_context *ldb;
183         struct dom_sid *sid;
184         bool ret;
185
186         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_sid))
187                 return NULL;
188         
189         PyErr_LDB_OR_RAISE(py_ldb, ldb);
190
191         sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
192
193         ret = samdb_set_domain_sid(ldb, sid);
194         if (!ret) {
195                 PyErr_SetString(PyExc_RuntimeError, "set_domain_sid failed");
196                 return NULL;
197         } 
198         Py_RETURN_NONE;
199 }
200
201 static PyObject *py_samdb_get_domain_sid(PyLdbObject *self, PyObject *args)
202
203         PyObject *py_ldb;
204         struct ldb_context *ldb;
205         const struct dom_sid *sid;
206         PyObject *ret;
207         char *retstr;
208
209         if (!PyArg_ParseTuple(args, "O", &py_ldb))
210                 return NULL;
211         
212         PyErr_LDB_OR_RAISE(py_ldb, ldb);
213
214         sid = samdb_domain_sid(ldb);
215         if (!sid) {
216                 PyErr_SetString(PyExc_RuntimeError, "samdb_domain_sid failed");
217                 return NULL;
218         } 
219         retstr = dom_sid_string(NULL, sid);
220         ret = PyString_FromString(retstr);
221         talloc_free(retstr);
222         return ret;
223 }
224
225 static PyObject *py_ldb_register_samba_handlers(PyObject *self, PyObject *args)
226 {
227         PyObject *py_ldb;
228         struct ldb_context *ldb;
229         int ret;
230
231         if (!PyArg_ParseTuple(args, "O", &py_ldb))
232                 return NULL;
233
234         PyErr_LDB_OR_RAISE(py_ldb, ldb);
235         ret = ldb_register_samba_handlers(ldb);
236
237         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
238         Py_RETURN_NONE;
239 }
240
241 static PyObject *py_dsdb_set_ntds_invocation_id(PyObject *self, PyObject *args)
242 {
243         PyObject *py_ldb, *py_guid;
244         bool ret;
245         struct GUID guid;
246         struct ldb_context *ldb;
247         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_guid))
248                 return NULL;
249
250         PyErr_LDB_OR_RAISE(py_ldb, ldb);
251         GUID_from_string(PyString_AsString(py_guid), &guid);
252
253         ret = samdb_set_ntds_invocation_id(ldb, &guid);
254         if (!ret) {
255                 PyErr_SetString(PyExc_RuntimeError, "set_ntds_invocation_id failed");
256                 return NULL;
257         }
258         Py_RETURN_NONE;
259 }
260
261 static PyObject *py_dsdb_set_opaque_integer(PyObject *self, PyObject *args)
262 {
263         PyObject *py_ldb;
264         int value;
265         int *old_val, *new_val;
266         char *py_opaque_name, *opaque_name_talloc;
267         struct ldb_context *ldb;
268         TALLOC_CTX *tmp_ctx;
269
270         if (!PyArg_ParseTuple(args, "Osi", &py_ldb, &py_opaque_name, &value))
271                 return NULL;
272
273         PyErr_LDB_OR_RAISE(py_ldb, ldb);
274
275         /* see if we have a cached copy */
276         old_val = (int *)ldb_get_opaque(ldb, 
277                                         py_opaque_name);
278
279         if (old_val) {
280                 *old_val = value;
281                 Py_RETURN_NONE;
282         } 
283
284         tmp_ctx = talloc_new(ldb);
285         if (tmp_ctx == NULL) {
286                 goto failed;
287         }
288         
289         new_val = talloc(tmp_ctx, int);
290         if (!new_val) {
291                 goto failed;
292         }
293         
294         opaque_name_talloc = talloc_strdup(tmp_ctx, py_opaque_name);
295         if (!opaque_name_talloc) {
296                 goto failed;
297         }
298         
299         *new_val = value;
300
301         /* cache the domain_sid in the ldb */
302         if (ldb_set_opaque(ldb, opaque_name_talloc, new_val) != LDB_SUCCESS) {
303                 goto failed;
304         }
305
306         talloc_steal(ldb, new_val);
307         talloc_steal(ldb, opaque_name_talloc);
308         talloc_free(tmp_ctx);
309
310         Py_RETURN_NONE;
311
312 failed:
313         talloc_free(tmp_ctx);
314         PyErr_SetString(PyExc_RuntimeError, "Failed to set opaque integer into the ldb!\n");
315         return NULL;
316 }
317
318 static PyObject *py_dsdb_set_global_schema(PyObject *self, PyObject *args)
319 {
320         PyObject *py_ldb;
321         struct ldb_context *ldb;
322         int ret;
323         if (!PyArg_ParseTuple(args, "O", &py_ldb))
324                 return NULL;
325
326         PyErr_LDB_OR_RAISE(py_ldb, ldb);
327
328         ret = dsdb_set_global_schema(ldb);
329         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
330
331         Py_RETURN_NONE;
332 }
333
334 static PyObject *py_dsdb_set_schema_from_ldif(PyObject *self, PyObject *args)
335 {
336         WERROR result;
337         char *pf, *df;
338         PyObject *py_ldb;
339         struct ldb_context *ldb;
340
341         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &pf, &df))
342                 return NULL;
343
344         PyErr_LDB_OR_RAISE(py_ldb, ldb);
345
346         result = dsdb_set_schema_from_ldif(ldb, pf, df);
347         PyErr_WERROR_IS_ERR_RAISE(result);
348
349         Py_RETURN_NONE;
350 }
351
352 static PyObject *py_dsdb_convert_schema_to_openldap(PyObject *self, PyObject *args)
353 {
354         char *target_str, *mapping;
355         PyObject *py_ldb;
356         struct ldb_context *ldb;
357         PyObject *ret;
358         char *retstr;
359
360         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &target_str, &mapping))
361                 return NULL;
362
363         PyErr_LDB_OR_RAISE(py_ldb, ldb);
364
365         retstr = dsdb_convert_schema_to_openldap(ldb, target_str, mapping);
366         if (!retstr) {
367                 PyErr_SetString(PyExc_RuntimeError, "dsdb_convert_schema_to_openldap failed");
368                 return NULL;
369         } 
370         ret = PyString_FromString(retstr);
371         talloc_free(retstr);
372         return ret;
373 }
374
375 static PyObject *py_dsdb_write_prefixes_from_schema_to_ldb(PyObject *self, PyObject *args)
376 {
377         PyObject *py_ldb;
378         struct ldb_context *ldb;
379         WERROR result;
380         struct dsdb_schema *schema;
381
382         if (!PyArg_ParseTuple(args, "O", &py_ldb))
383                 return NULL;
384
385         PyErr_LDB_OR_RAISE(py_ldb, ldb);
386
387         schema = dsdb_get_schema(ldb);
388         if (!schema) {
389                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on ldb!\n");
390                 return NULL;
391         }
392
393         result = dsdb_write_prefixes_from_schema_to_ldb(NULL, ldb, schema);
394         PyErr_WERROR_IS_ERR_RAISE(result);
395
396         Py_RETURN_NONE;
397 }
398
399 static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args)
400 {
401         PyObject *py_ldb;
402         struct ldb_context *ldb;
403         PyObject *py_from_ldb;
404         struct ldb_context *from_ldb;
405         struct dsdb_schema *schema;
406         int ret;
407         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_from_ldb))
408                 return NULL;
409
410         PyErr_LDB_OR_RAISE(py_ldb, ldb);
411
412         PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb);
413
414         schema = dsdb_get_schema(from_ldb);
415         if (!schema) {
416                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n");
417                 return NULL;
418         }
419
420         ret = dsdb_reference_schema(ldb, schema, true);
421         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
422
423         Py_RETURN_NONE;
424 }
425
426 static PyObject *py_dsdb_make_schema_global(PyObject *self, PyObject *args)
427 {
428         PyObject *py_ldb;
429         struct ldb_context *ldb;
430
431         if (!PyArg_ParseTuple(args, "O", &py_ldb))
432                 return NULL;
433
434         PyErr_LDB_OR_RAISE(py_ldb, ldb);
435
436         dsdb_make_schema_global(ldb);
437
438         Py_RETURN_NONE;
439 }
440
441 static PyObject *py_dsdb_load_partition_usn(PyObject *self, PyObject *args)
442 {
443         PyObject *py_dn, *py_ldb, *result;
444         struct ldb_dn *dn;
445         uint64_t highest_uSN, urgent_uSN;
446         struct ldb_context *ldb;
447         TALLOC_CTX *mem_ctx;
448         int ret;
449
450         mem_ctx = talloc_new(NULL);
451         if (mem_ctx == NULL) {
452            PyErr_NoMemory();
453            return NULL;
454         }
455
456         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dn)) {
457            talloc_free(mem_ctx);
458            return NULL;
459         }
460
461         PyErr_LDB_OR_RAISE(py_ldb, ldb);
462
463         if (!PyObject_AsDn(mem_ctx, py_dn, ldb, &dn)) {
464            talloc_free(mem_ctx);
465            return NULL;
466         }
467
468         ret = dsdb_load_partition_usn(ldb, dn, &highest_uSN, &urgent_uSN);
469         if (ret != LDB_SUCCESS) {
470            char *errstr = talloc_asprintf(mem_ctx, "Failed to load partition uSN - %s", ldb_errstring(ldb));
471            PyErr_SetString(PyExc_RuntimeError, errstr);
472            talloc_free(mem_ctx);
473            return NULL;
474         }
475
476         talloc_free(mem_ctx);
477
478         result = PyDict_New();
479
480         PyDict_SetItemString(result, "uSNHighest", PyInt_FromLong((uint64_t)highest_uSN));
481         PyDict_SetItemString(result, "uSNUrgent", PyInt_FromLong((uint64_t)urgent_uSN));
482
483
484         return result;
485
486 }
487
488
489 static PyMethodDef py_misc_methods[] = {
490         { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
491                 "random_password(len) -> string\n"
492                 "Generate random password with specified length." },
493         { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
494                 "unix2nttime(timestamp) -> nttime" },
495         { "ldb_set_session_info", (PyCFunction)py_ldb_set_session_info, METH_VARARGS,
496                 "ldb_set_session_info(ldb, session_info)\n"
497                 "Set session info to use when connecting." },
498         { "ldb_set_credentials", (PyCFunction)py_ldb_set_credentials, METH_VARARGS,
499                 "ldb_set_credentials(ldb, credentials)\n"
500                 "Set credentials to use when connecting." },
501         { "ldb_set_loadparm", (PyCFunction)py_ldb_set_loadparm, METH_VARARGS,
502                 "ldb_set_loadparm(ldb, session_info)\n"
503                 "Set loadparm context to use when connecting." },
504         { "samdb_set_domain_sid", (PyCFunction)py_samdb_set_domain_sid, METH_VARARGS,
505                 "samdb_set_domain_sid(samdb, sid)\n"
506                 "Set SID of domain to use." },
507         { "samdb_get_domain_sid", (PyCFunction)py_samdb_get_domain_sid, METH_VARARGS,
508                 "samdb_get_domain_sid(samdb)\n"
509                 "Get SID of domain in use." },
510         { "ldb_register_samba_handlers", (PyCFunction)py_ldb_register_samba_handlers, METH_VARARGS,
511                 "ldb_register_samba_handlers(ldb)\n"
512                 "Register Samba-specific LDB modules and schemas." },
513         { "ldb_set_utf8_casefold", (PyCFunction)py_ldb_set_utf8_casefold, METH_VARARGS,
514                 "ldb_set_utf8_casefold(ldb)\n"
515                 "Set the right Samba casefolding function for UTF8 charset." },
516         { "dsdb_set_ntds_invocation_id", (PyCFunction)py_dsdb_set_ntds_invocation_id, METH_VARARGS,
517                 NULL },
518         { "dsdb_set_opaque_integer", (PyCFunction)py_dsdb_set_opaque_integer, METH_VARARGS,
519                 NULL },
520         { "dsdb_set_global_schema", (PyCFunction)py_dsdb_set_global_schema, METH_VARARGS,
521                 NULL },
522         { "dsdb_set_schema_from_ldif", (PyCFunction)py_dsdb_set_schema_from_ldif, METH_VARARGS,
523                 NULL },
524         { "dsdb_write_prefixes_from_schema_to_ldb", (PyCFunction)py_dsdb_write_prefixes_from_schema_to_ldb, METH_VARARGS,
525                 NULL },
526         { "dsdb_set_schema_from_ldb", (PyCFunction)py_dsdb_set_schema_from_ldb, METH_VARARGS,
527                 NULL },
528         { "dsdb_convert_schema_to_openldap", (PyCFunction)py_dsdb_convert_schema_to_openldap, METH_VARARGS,
529                 NULL },
530         { "dsdb_make_schema_global", (PyCFunction)py_dsdb_make_schema_global, METH_VARARGS,
531                 NULL },
532         { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
533                 "set debug level" },
534         { "dsdb_load_partition_usn", (PyCFunction)py_dsdb_load_partition_usn, METH_VARARGS,
535                 "get uSNHighest and uSNUrgent from the partition @REPLCHANGED"},
536         { NULL }
537 };
538
539 void initglue(void)
540 {
541         PyObject *m;
542
543         m = Py_InitModule3("glue", py_misc_methods, 
544                            "Python bindings for miscellaneous Samba functions.");
545         if (m == NULL)
546                 return;
547
548         PyModule_AddObject(m, "version", PyString_FromString(SAMBA_VERSION_STRING));
549
550         /* "userAccountControl" flags */
551         PyModule_AddObject(m, "UF_NORMAL_ACCOUNT", PyInt_FromLong(UF_NORMAL_ACCOUNT));
552         PyModule_AddObject(m, "UF_TEMP_DUPLICATE_ACCOUNT", PyInt_FromLong(UF_TEMP_DUPLICATE_ACCOUNT));
553         PyModule_AddObject(m, "UF_SERVER_TRUST_ACCOUNT", PyInt_FromLong(UF_SERVER_TRUST_ACCOUNT));
554         PyModule_AddObject(m, "UF_WORKSTATION_TRUST_ACCOUNT", PyInt_FromLong(UF_WORKSTATION_TRUST_ACCOUNT));
555         PyModule_AddObject(m, "UF_INTERDOMAIN_TRUST_ACCOUNT", PyInt_FromLong(UF_INTERDOMAIN_TRUST_ACCOUNT));
556         PyModule_AddObject(m, "UF_PASSWD_NOTREQD", PyInt_FromLong(UF_PASSWD_NOTREQD));
557         PyModule_AddObject(m, "UF_ACCOUNTDISABLE", PyInt_FromLong(UF_ACCOUNTDISABLE));
558
559         /* "groupType" flags */
560         PyModule_AddObject(m, "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP));
561         PyModule_AddObject(m, "GTYPE_SECURITY_GLOBAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_GLOBAL_GROUP));
562         PyModule_AddObject(m, "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
563         PyModule_AddObject(m, "GTYPE_SECURITY_UNIVERSAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_UNIVERSAL_GROUP));
564         PyModule_AddObject(m, "GTYPE_DISTRIBUTION_GLOBAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_GLOBAL_GROUP));
565         PyModule_AddObject(m, "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP));
566         PyModule_AddObject(m, "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP));
567
568         /* "sAMAccountType" flags */
569         PyModule_AddObject(m, "ATYPE_NORMAL_ACCOUNT", PyInt_FromLong(ATYPE_NORMAL_ACCOUNT));
570         PyModule_AddObject(m, "ATYPE_WORKSTATION_TRUST", PyInt_FromLong(ATYPE_WORKSTATION_TRUST));
571         PyModule_AddObject(m, "ATYPE_INTERDOMAIN_TRUST", PyInt_FromLong(ATYPE_INTERDOMAIN_TRUST));
572         PyModule_AddObject(m, "ATYPE_SECURITY_GLOBAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_GLOBAL_GROUP));
573         PyModule_AddObject(m, "ATYPE_SECURITY_LOCAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_LOCAL_GROUP));
574         PyModule_AddObject(m, "ATYPE_SECURITY_UNIVERSAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_UNIVERSAL_GROUP));
575         PyModule_AddObject(m, "ATYPE_DISTRIBUTION_GLOBAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_GLOBAL_GROUP));
576         PyModule_AddObject(m, "ATYPE_DISTRIBUTION_LOCAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_LOCAL_GROUP));
577         PyModule_AddObject(m, "ATYPE_DISTRIBUTION_UNIVERSAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_UNIVERSAL_GROUP));
578
579         /* "domainFunctionality", "forestFunctionality" flags in the rootDSE */
580         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2000", PyInt_FromLong(DS_DOMAIN_FUNCTION_2000));
581         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2003_MIXED", PyInt_FromLong(DS_DOMAIN_FUNCTION_2003_MIXED));
582         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2003", PyInt_FromLong(DS_DOMAIN_FUNCTION_2003));
583         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2008", PyInt_FromLong(DS_DOMAIN_FUNCTION_2008));
584         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2008_R2", PyInt_FromLong(DS_DOMAIN_FUNCTION_2008_R2));
585
586         /* "domainControllerFunctionality" flags in the rootDSE */
587         PyModule_AddObject(m, "DS_DC_FUNCTION_2000", PyInt_FromLong(DS_DC_FUNCTION_2000));
588         PyModule_AddObject(m, "DS_DC_FUNCTION_2003", PyInt_FromLong(DS_DC_FUNCTION_2003));
589         PyModule_AddObject(m, "DS_DC_FUNCTION_2008", PyInt_FromLong(DS_DC_FUNCTION_2008));
590         PyModule_AddObject(m, "DS_DC_FUNCTION_2008_R2", PyInt_FromLong(DS_DC_FUNCTION_2008_R2));
591
592         /* "LDAP_SERVER_SD_FLAGS_OID" */
593         PyModule_AddObject(m, "SECINFO_OWNER", PyInt_FromLong(SECINFO_OWNER));
594         PyModule_AddObject(m, "SECINFO_GROUP", PyInt_FromLong(SECINFO_GROUP));
595         PyModule_AddObject(m, "SECINFO_DACL", PyInt_FromLong(SECINFO_DACL));
596         PyModule_AddObject(m, "SECINFO_SACL", PyInt_FromLong(SECINFO_SACL));
597
598         /* one of the most annoying things about python scripts is
599            that they don't die when you hit control-C. This fixes that
600            sillyness. As we do all database operations using
601            transactions, this is also safe. In fact, not dying
602            immediately is unsafe as we could end up treating the
603            control-C exception as a different error and try to modify
604            as database incorrectly 
605         */
606         signal(SIGINT, SIG_DFL);
607 }
608