s4-python: fixed annoyance where control-C doesn't kill our python scripts
[ira/wip.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 #ifndef Py_RETURN_NONE
39 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
40 #endif
41
42 /* FIXME: These should be in a header file somewhere, once we finish moving
43  * away from SWIG .. */
44 #define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
45 /*      if (!PyLdb_Check(py_ldb)) { \
46                 PyErr_SetString(py_ldb_get_exception(), "Ldb connection object required"); \
47                 return NULL; \
48         } */\
49         ldb = PyLdb_AsLdbContext(py_ldb);
50
51 static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_ctx)
52 {
53         if (ret == LDB_ERR_PYTHON_EXCEPTION)
54                 return; /* Python exception should already be set, just keep that */
55
56         PyErr_SetObject(error, 
57                                         Py_BuildValue(discard_const_p(char, "(i,s)"), ret, 
58                                   ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx)));
59 }
60
61 static PyObject *py_ldb_get_exception(void)
62 {
63         PyObject *mod = PyImport_ImportModule("ldb");
64         if (mod == NULL)
65                 return NULL;
66
67         return PyObject_GetAttrString(mod, "LdbError");
68 }
69
70 static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
71 {
72         int len;
73         PyObject *ret;
74         char *retstr;
75         if (!PyArg_ParseTuple(args, "i", &len))
76                 return NULL;
77
78         retstr = generate_random_str(NULL, len);
79         ret = PyString_FromString(retstr);
80         talloc_free(retstr);
81         return ret;
82 }
83
84 static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
85 {
86         time_t t;
87         NTTIME nt;
88         if (!PyArg_ParseTuple(args, "I", &t))
89                 return NULL;
90
91         unix_to_nt_time(&nt, t);
92
93         return PyInt_FromLong((uint64_t)nt);
94 }
95
96 static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
97 {
98         unsigned level;
99         if (!PyArg_ParseTuple(args, "I", &level))
100                 return NULL;
101         (DEBUGLEVEL) = level;
102         Py_RETURN_NONE;
103 }
104
105 static PyObject *py_ldb_set_credentials(PyObject *self, PyObject *args)
106 {
107         PyObject *py_creds, *py_ldb;
108         struct cli_credentials *creds;
109         struct ldb_context *ldb;
110         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_creds))
111                 return NULL;
112
113         PyErr_LDB_OR_RAISE(py_ldb, ldb);
114         
115         creds = cli_credentials_from_py_object(py_creds);
116         if (creds == NULL) {
117                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
118                 return NULL;
119         }
120
121         ldb_set_opaque(ldb, "credentials", creds);
122
123         Py_RETURN_NONE;
124 }
125
126 static PyObject *py_ldb_set_loadparm(PyObject *self, PyObject *args)
127 {
128         PyObject *py_lp_ctx, *py_ldb;
129         struct loadparm_context *lp_ctx;
130         struct ldb_context *ldb;
131         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_lp_ctx))
132                 return NULL;
133
134         PyErr_LDB_OR_RAISE(py_ldb, ldb);
135
136         lp_ctx = lp_from_py_object(py_lp_ctx);
137         if (lp_ctx == NULL) {
138                 PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
139                 return NULL;
140         }
141
142         ldb_set_opaque(ldb, "loadparm", lp_ctx);
143
144         Py_RETURN_NONE;
145 }
146
147
148 static PyObject *py_ldb_set_session_info(PyObject *self, PyObject *args)
149 {
150         PyObject *py_session_info, *py_ldb;
151         struct auth_session_info *info;
152         struct ldb_context *ldb;
153         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_session_info))
154                 return NULL;
155
156         PyErr_LDB_OR_RAISE(py_ldb, ldb);
157         /*if (!PyAuthSession_Check(py_session_info)) {
158                 PyErr_SetString(PyExc_TypeError, "Expected session info object");
159                 return NULL;
160         }*/
161
162         info = PyAuthSession_AsSession(py_session_info);
163
164         ldb_set_opaque(ldb, "sessionInfo", info);
165
166         Py_RETURN_NONE;
167 }
168
169 static PyObject *py_ldb_set_utf8_casefold(PyObject *self, PyObject *args)
170 {
171         PyObject *py_ldb;
172         struct ldb_context *ldb;
173
174         if (!PyArg_ParseTuple(args, "O", &py_ldb))
175                 return NULL;
176
177         PyErr_LDB_OR_RAISE(py_ldb, ldb);
178
179         ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
180
181         Py_RETURN_NONE;
182 }
183
184 static PyObject *py_samdb_set_domain_sid(PyLdbObject *self, PyObject *args)
185
186         PyObject *py_ldb, *py_sid;
187         struct ldb_context *ldb;
188         struct dom_sid *sid;
189         bool ret;
190
191         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_sid))
192                 return NULL;
193         
194         PyErr_LDB_OR_RAISE(py_ldb, ldb);
195
196         sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
197
198         ret = samdb_set_domain_sid(ldb, sid);
199         if (!ret) {
200                 PyErr_SetString(PyExc_RuntimeError, "set_domain_sid failed");
201                 return NULL;
202         } 
203         Py_RETURN_NONE;
204 }
205
206 static PyObject *py_samdb_get_domain_sid(PyLdbObject *self, PyObject *args)
207
208         PyObject *py_ldb;
209         struct ldb_context *ldb;
210         const struct dom_sid *sid;
211         PyObject *ret;
212         char *retstr;
213
214         if (!PyArg_ParseTuple(args, "O", &py_ldb))
215                 return NULL;
216         
217         PyErr_LDB_OR_RAISE(py_ldb, ldb);
218
219         sid = samdb_domain_sid(ldb);
220         if (!sid) {
221                 PyErr_SetString(PyExc_RuntimeError, "samdb_domain_sid failed");
222                 return NULL;
223         } 
224         retstr = dom_sid_string(NULL, sid);
225         ret = PyString_FromString(retstr);
226         talloc_free(retstr);
227         return ret;
228 }
229
230 static PyObject *py_ldb_register_samba_handlers(PyObject *self, PyObject *args)
231 {
232         PyObject *py_ldb;
233         struct ldb_context *ldb;
234         int ret;
235
236         if (!PyArg_ParseTuple(args, "O", &py_ldb))
237                 return NULL;
238
239         PyErr_LDB_OR_RAISE(py_ldb, ldb);
240         ret = ldb_register_samba_handlers(ldb);
241
242         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
243         Py_RETURN_NONE;
244 }
245
246 static PyObject *py_dsdb_set_ntds_invocation_id(PyObject *self, PyObject *args)
247 {
248         PyObject *py_ldb, *py_guid;
249         bool ret;
250         struct GUID guid;
251         struct ldb_context *ldb;
252         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_guid))
253                 return NULL;
254
255         PyErr_LDB_OR_RAISE(py_ldb, ldb);
256         GUID_from_string(PyString_AsString(py_guid), &guid);
257
258         ret = samdb_set_ntds_invocation_id(ldb, &guid);
259         if (!ret) {
260                 PyErr_SetString(PyExc_RuntimeError, "set_ntds_invocation_id failed");
261                 return NULL;
262         }
263         Py_RETURN_NONE;
264 }
265
266 static PyObject *py_dsdb_set_opaque_integer(PyObject *self, PyObject *args)
267 {
268         PyObject *py_ldb;
269         int value;
270         int *old_val, *new_val;
271         char *py_opaque_name, *opaque_name_talloc;
272         struct ldb_context *ldb;
273         TALLOC_CTX *tmp_ctx;
274
275         if (!PyArg_ParseTuple(args, "Osi", &py_ldb, &py_opaque_name, &value))
276                 return NULL;
277
278         PyErr_LDB_OR_RAISE(py_ldb, ldb);
279
280         /* see if we have a cached copy */
281         old_val = (int *)ldb_get_opaque(ldb, 
282                                         py_opaque_name);
283
284         if (old_val) {
285                 *old_val = value;
286                 Py_RETURN_NONE;
287         } 
288
289         tmp_ctx = talloc_new(ldb);
290         if (tmp_ctx == NULL) {
291                 goto failed;
292         }
293         
294         new_val = talloc(tmp_ctx, int);
295         if (!new_val) {
296                 goto failed;
297         }
298         
299         opaque_name_talloc = talloc_strdup(tmp_ctx, py_opaque_name);
300         if (!opaque_name_talloc) {
301                 goto failed;
302         }
303         
304         *new_val = value;
305
306         /* cache the domain_sid in the ldb */
307         if (ldb_set_opaque(ldb, opaque_name_talloc, new_val) != LDB_SUCCESS) {
308                 goto failed;
309         }
310
311         talloc_steal(ldb, new_val);
312         talloc_steal(ldb, opaque_name_talloc);
313         talloc_free(tmp_ctx);
314
315         Py_RETURN_NONE;
316
317 failed:
318         talloc_free(tmp_ctx);
319         PyErr_SetString(PyExc_RuntimeError, "Failed to set opaque integer into the ldb!\n");
320         return NULL;
321 }
322
323 static PyObject *py_dsdb_set_global_schema(PyObject *self, PyObject *args)
324 {
325         PyObject *py_ldb;
326         struct ldb_context *ldb;
327         int ret;
328         if (!PyArg_ParseTuple(args, "O", &py_ldb))
329                 return NULL;
330
331         PyErr_LDB_OR_RAISE(py_ldb, ldb);
332
333         ret = dsdb_set_global_schema(ldb);
334         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
335
336         Py_RETURN_NONE;
337 }
338
339 static PyObject *py_dsdb_set_schema_from_ldif(PyObject *self, PyObject *args)
340 {
341         WERROR result;
342         char *pf, *df;
343         PyObject *py_ldb;
344         struct ldb_context *ldb;
345
346         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &pf, &df))
347                 return NULL;
348
349         PyErr_LDB_OR_RAISE(py_ldb, ldb);
350
351         result = dsdb_set_schema_from_ldif(ldb, pf, df);
352         PyErr_WERROR_IS_ERR_RAISE(result);
353
354         Py_RETURN_NONE;
355 }
356
357 static PyObject *py_dsdb_convert_schema_to_openldap(PyObject *self, PyObject *args)
358 {
359         char *target_str, *mapping;
360         PyObject *py_ldb;
361         struct ldb_context *ldb;
362         PyObject *ret;
363         char *retstr;
364
365         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &target_str, &mapping))
366                 return NULL;
367
368         PyErr_LDB_OR_RAISE(py_ldb, ldb);
369
370         retstr = dsdb_convert_schema_to_openldap(ldb, target_str, mapping);
371         if (!retstr) {
372                 PyErr_SetString(PyExc_RuntimeError, "dsdb_convert_schema_to_openldap failed");
373                 return NULL;
374         } 
375         ret = PyString_FromString(retstr);
376         talloc_free(retstr);
377         return ret;
378 }
379
380 static PyObject *py_dsdb_write_prefixes_from_schema_to_ldb(PyObject *self, PyObject *args)
381 {
382         PyObject *py_ldb;
383         struct ldb_context *ldb;
384         WERROR result;
385         struct dsdb_schema *schema;
386
387         if (!PyArg_ParseTuple(args, "O", &py_ldb))
388                 return NULL;
389
390         PyErr_LDB_OR_RAISE(py_ldb, ldb);
391
392         schema = dsdb_get_schema(ldb);
393         if (!schema) {
394                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on ldb!\n");
395                 return NULL;
396         }
397
398         result = dsdb_write_prefixes_from_schema_to_ldb(NULL, ldb, schema);
399         PyErr_WERROR_IS_ERR_RAISE(result);
400
401         Py_RETURN_NONE;
402 }
403
404 static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args)
405 {
406         PyObject *py_ldb;
407         struct ldb_context *ldb;
408         PyObject *py_from_ldb;
409         struct ldb_context *from_ldb;
410         struct dsdb_schema *schema;
411         int ret;
412         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_from_ldb))
413                 return NULL;
414
415         PyErr_LDB_OR_RAISE(py_ldb, ldb);
416
417         PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb);
418
419         schema = dsdb_get_schema(from_ldb);
420         if (!schema) {
421                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n");
422                 return NULL;
423         }
424
425         ret = dsdb_reference_schema(ldb, schema, true);
426         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
427
428         Py_RETURN_NONE;
429 }
430
431 static PyObject *py_dom_sid_to_rid(PyLdbObject *self, PyObject *args)
432 {
433         PyObject *py_sid;
434         struct dom_sid *sid;
435         uint32_t rid;
436         NTSTATUS status;
437         
438         if(!PyArg_ParseTuple(args, "O", &py_sid))
439                 return NULL;
440
441         sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
442
443         status = dom_sid_split_rid(NULL, sid, NULL, &rid);
444         if (!NT_STATUS_IS_OK(status)) {
445                 PyErr_SetString(PyExc_RuntimeError, "dom_sid_split_rid failed");
446                 return NULL;
447         }
448
449         return PyInt_FromLong(rid);
450 }
451
452 static PyMethodDef py_misc_methods[] = {
453         { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
454                 "random_password(len) -> string\n"
455                 "Generate random password with specified length." },
456         { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
457                 "unix2nttime(timestamp) -> nttime" },
458         { "ldb_set_credentials", (PyCFunction)py_ldb_set_credentials, METH_VARARGS, 
459                 "ldb_set_credentials(ldb, credentials) -> None\n"
460                 "Set credentials to use when connecting." },
461         { "ldb_set_session_info", (PyCFunction)py_ldb_set_session_info, METH_VARARGS,
462                 "ldb_set_session_info(ldb, session_info)\n"
463                 "Set session info to use when connecting." },
464         { "ldb_set_loadparm", (PyCFunction)py_ldb_set_loadparm, METH_VARARGS,
465                 "ldb_set_loadparm(ldb, session_info)\n"
466                 "Set loadparm context to use when connecting." },
467         { "samdb_set_domain_sid", (PyCFunction)py_samdb_set_domain_sid, METH_VARARGS,
468                 "samdb_set_domain_sid(samdb, sid)\n"
469                 "Set SID of domain to use." },
470         { "samdb_get_domain_sid", (PyCFunction)py_samdb_get_domain_sid, METH_VARARGS,
471                 "samdb_get_domain_sid(samdb)\n"
472                 "Get SID of domain in use." },
473         { "ldb_register_samba_handlers", (PyCFunction)py_ldb_register_samba_handlers, METH_VARARGS,
474                 "ldb_register_samba_handlers(ldb)\n"
475                 "Register Samba-specific LDB modules and schemas." },
476         { "ldb_set_utf8_casefold", (PyCFunction)py_ldb_set_utf8_casefold, METH_VARARGS,
477                 "ldb_set_utf8_casefold(ldb)\n"
478                 "Set the right Samba casefolding function for UTF8 charset." },
479         { "dsdb_set_ntds_invocation_id", (PyCFunction)py_dsdb_set_ntds_invocation_id, METH_VARARGS,
480                 NULL },
481         { "dsdb_set_opaque_integer", (PyCFunction)py_dsdb_set_opaque_integer, METH_VARARGS,
482                 NULL },
483         { "dsdb_set_global_schema", (PyCFunction)py_dsdb_set_global_schema, METH_VARARGS,
484                 NULL },
485         { "dsdb_set_schema_from_ldif", (PyCFunction)py_dsdb_set_schema_from_ldif, METH_VARARGS,
486                 NULL },
487         { "dsdb_write_prefixes_from_schema_to_ldb", (PyCFunction)py_dsdb_write_prefixes_from_schema_to_ldb, METH_VARARGS,
488                 NULL },
489         { "dsdb_set_schema_from_ldb", (PyCFunction)py_dsdb_set_schema_from_ldb, METH_VARARGS,
490                 NULL },
491         { "dsdb_convert_schema_to_openldap", (PyCFunction)py_dsdb_convert_schema_to_openldap, METH_VARARGS,
492                 NULL },
493         { "dom_sid_to_rid", (PyCFunction)py_dom_sid_to_rid, METH_VARARGS,
494                 NULL },
495         { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
496                 "set debug level" },
497         { NULL }
498 };
499
500 void initglue(void)
501 {
502         PyObject *m;
503
504         m = Py_InitModule3("glue", py_misc_methods, 
505                            "Python bindings for miscellaneous Samba functions.");
506         if (m == NULL)
507                 return;
508
509         PyModule_AddObject(m, "version", PyString_FromString(SAMBA_VERSION_STRING));
510
511         /* "userAccountControl" flags */
512         PyModule_AddObject(m, "UF_NORMAL_ACCOUNT", PyInt_FromLong(UF_NORMAL_ACCOUNT));
513         PyModule_AddObject(m, "UF_TEMP_DUPLICATE_ACCOUNT", PyInt_FromLong(UF_TEMP_DUPLICATE_ACCOUNT));
514         PyModule_AddObject(m, "UF_SERVER_TRUST_ACCOUNT", PyInt_FromLong(UF_SERVER_TRUST_ACCOUNT));
515         PyModule_AddObject(m, "UF_WORKSTATION_TRUST_ACCOUNT", PyInt_FromLong(UF_WORKSTATION_TRUST_ACCOUNT));
516         PyModule_AddObject(m, "UF_INTERDOMAIN_TRUST_ACCOUNT", PyInt_FromLong(UF_INTERDOMAIN_TRUST_ACCOUNT));
517         PyModule_AddObject(m, "UF_PASSWD_NOTREQD", PyInt_FromLong(UF_PASSWD_NOTREQD));
518         PyModule_AddObject(m, "UF_ACCOUNTDISABLE", PyInt_FromLong(UF_ACCOUNTDISABLE));
519
520         /* "groupType" flags */
521         PyModule_AddObject(m, "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP));
522         PyModule_AddObject(m, "GTYPE_SECURITY_GLOBAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_GLOBAL_GROUP));
523         PyModule_AddObject(m, "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
524         PyModule_AddObject(m, "GTYPE_SECURITY_UNIVERSAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_UNIVERSAL_GROUP));
525         PyModule_AddObject(m, "GTYPE_DISTRIBUTION_GLOBAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_GLOBAL_GROUP));
526         PyModule_AddObject(m, "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP));
527         PyModule_AddObject(m, "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP));
528
529         /* "sAMAccountType" flags */
530         PyModule_AddObject(m, "ATYPE_NORMAL_ACCOUNT", PyInt_FromLong(ATYPE_NORMAL_ACCOUNT));
531         PyModule_AddObject(m, "ATYPE_WORKSTATION_TRUST", PyInt_FromLong(ATYPE_WORKSTATION_TRUST));
532         PyModule_AddObject(m, "ATYPE_INTERDOMAIN_TRUST", PyInt_FromLong(ATYPE_INTERDOMAIN_TRUST));
533         PyModule_AddObject(m, "ATYPE_SECURITY_GLOBAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_GLOBAL_GROUP));
534         PyModule_AddObject(m, "ATYPE_SECURITY_LOCAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_LOCAL_GROUP));
535         PyModule_AddObject(m, "ATYPE_SECURITY_UNIVERSAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_UNIVERSAL_GROUP));
536         PyModule_AddObject(m, "ATYPE_DISTRIBUTION_GLOBAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_GLOBAL_GROUP));
537         PyModule_AddObject(m, "ATYPE_DISTRIBUTION_LOCAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_LOCAL_GROUP));
538         PyModule_AddObject(m, "ATYPE_DISTRIBUTION_UNIVERSAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_UNIVERSAL_GROUP));
539
540         /* "domainFunctionality", "forestFunctionality" flags in the rootDSE */
541         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2000", PyInt_FromLong(DS_DOMAIN_FUNCTION_2000));
542         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2003_MIXED", PyInt_FromLong(DS_DOMAIN_FUNCTION_2003_MIXED));
543         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2003", PyInt_FromLong(DS_DOMAIN_FUNCTION_2003));
544         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2008", PyInt_FromLong(DS_DOMAIN_FUNCTION_2008));
545         PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2008_R2", PyInt_FromLong(DS_DOMAIN_FUNCTION_2008_R2));
546
547         /* "domainControllerFunctionality" flags in the rootDSE */
548         PyModule_AddObject(m, "DS_DC_FUNCTION_2000", PyInt_FromLong(DS_DC_FUNCTION_2000));
549         PyModule_AddObject(m, "DS_DC_FUNCTION_2003", PyInt_FromLong(DS_DC_FUNCTION_2003));
550         PyModule_AddObject(m, "DS_DC_FUNCTION_2008", PyInt_FromLong(DS_DC_FUNCTION_2008));
551         PyModule_AddObject(m, "DS_DC_FUNCTION_2008_R2", PyInt_FromLong(DS_DC_FUNCTION_2008_R2));
552
553         /* one of the most annoying things about python scripts is
554            that they don't die when you hit control-C. This fixes that
555            sillyness. As we do all database operations using
556            transactions, this is also safe. In fact, not dying
557            immediately is unsafe as we could end up treating the
558            control-C exception as a different error and try to modify
559            as database incorrectly 
560         */
561         signal(SIGINT, SIG_DFL);
562 }
563