Line data Source code
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 "python/py3compat.h"
22 : #include "includes.h"
23 : #include "python/modules.h"
24 : #include "version.h"
25 : #include "param/pyparam.h"
26 : #include "lib/socket/netif.h"
27 : #include "lib/util/debug.h"
28 : #include "librpc/ndr/ndr_private.h"
29 : #include "lib/cmdline/cmdline.h"
30 :
31 : void init_glue(void);
32 : static PyObject *PyExc_NTSTATUSError;
33 : static PyObject *PyExc_WERRORError;
34 : static PyObject *PyExc_HRESULTError;
35 : static PyObject *PyExc_DsExtendedError;
36 :
37 0 : static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
38 : {
39 : int len;
40 : PyObject *ret;
41 : char *retstr;
42 0 : if (!PyArg_ParseTuple(args, "i", &len)) {
43 0 : return NULL;
44 : }
45 0 : if (len < 0) {
46 0 : PyErr_Format(PyExc_ValueError,
47 : "random string length should be positive, not %d",
48 : len);
49 0 : return NULL;
50 : }
51 0 : retstr = generate_random_str(NULL, len);
52 0 : ret = PyUnicode_FromString(retstr);
53 0 : talloc_free(retstr);
54 0 : return ret;
55 : }
56 :
57 1057 : static PyObject *py_generate_random_password(PyObject *self, PyObject *args)
58 : {
59 : int min, max;
60 : PyObject *ret;
61 : char *retstr;
62 1057 : if (!PyArg_ParseTuple(args, "ii", &min, &max)) {
63 0 : return NULL;
64 : }
65 1057 : if (max < 0 || min < 0) {
66 : /*
67 : * The real range checks happen in generate_random_password().
68 : * Here we are just checking the values won't overflow into
69 : * numbers when cast to size_t.
70 : */
71 0 : PyErr_Format(PyExc_ValueError,
72 : "invalid range: %d - %d",
73 : min, max);
74 0 : return NULL;
75 : }
76 :
77 1057 : retstr = generate_random_password(NULL, min, max);
78 1057 : if (retstr == NULL) {
79 0 : if (errno == EINVAL) {
80 0 : PyErr_Format(PyExc_ValueError,
81 : "invalid range: %d - %d",
82 : min, max);
83 : }
84 0 : return NULL;
85 : }
86 1057 : ret = PyUnicode_FromString(retstr);
87 1057 : talloc_free(retstr);
88 1057 : return ret;
89 : }
90 :
91 347 : static PyObject *py_generate_random_machine_password(PyObject *self, PyObject *args)
92 : {
93 : int min, max;
94 : PyObject *ret;
95 : char *retstr;
96 347 : if (!PyArg_ParseTuple(args, "ii", &min, &max)) {
97 0 : return NULL;
98 : }
99 347 : if (max < 0 || min < 0) {
100 : /*
101 : * The real range checks happen in
102 : * generate_random_machine_password().
103 : * Here we are just checking the values won't overflow into
104 : * numbers when cast to size_t.
105 : */
106 0 : PyErr_Format(PyExc_ValueError,
107 : "invalid range: %d - %d",
108 : min, max);
109 0 : return NULL;
110 : }
111 :
112 347 : retstr = generate_random_machine_password(NULL, min, max);
113 347 : if (retstr == NULL) {
114 0 : if (errno == EINVAL) {
115 0 : PyErr_Format(PyExc_ValueError,
116 : "invalid range: %d - %d",
117 : min, max);
118 : }
119 0 : return NULL;
120 : }
121 347 : ret = PyUnicode_FromString(retstr);
122 347 : talloc_free(retstr);
123 347 : return ret;
124 : }
125 :
126 44 : static PyObject *py_check_password_quality(PyObject *self, PyObject *args)
127 : {
128 : char *pass;
129 :
130 44 : if (!PyArg_ParseTuple(args, "s", &pass)) {
131 0 : return NULL;
132 : }
133 :
134 44 : return PyBool_FromLong(check_password_quality(pass));
135 : }
136 :
137 4807 : static PyObject *py_generate_random_bytes(PyObject *self, PyObject *args)
138 : {
139 : int len;
140 : PyObject *ret;
141 4807 : uint8_t *bytes = NULL;
142 :
143 4807 : if (!PyArg_ParseTuple(args, "i", &len)) {
144 0 : return NULL;
145 : }
146 4807 : if (len < 0) {
147 0 : PyErr_Format(PyExc_ValueError,
148 : "random bytes length should be positive, not %d",
149 : len);
150 0 : return NULL;
151 : }
152 4807 : bytes = talloc_zero_size(NULL, len);
153 4807 : if (bytes == NULL) {
154 0 : PyErr_NoMemory();
155 0 : return NULL;
156 : }
157 4807 : generate_random_buffer(bytes, len);
158 4807 : ret = PyBytes_FromStringAndSize((const char *)bytes, len);
159 4807 : talloc_free(bytes);
160 4807 : return ret;
161 : }
162 :
163 503 : static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
164 : {
165 : time_t t;
166 : unsigned int _t;
167 : NTTIME nt;
168 :
169 503 : if (!PyArg_ParseTuple(args, "I", &_t)) {
170 0 : return NULL;
171 : }
172 503 : t = _t;
173 :
174 503 : unix_to_nt_time(&nt, t);
175 :
176 503 : return PyLong_FromLongLong((uint64_t)nt);
177 : }
178 :
179 71177 : static PyObject *py_nttime2unix(PyObject *self, PyObject *args)
180 : {
181 : time_t t;
182 : NTTIME nt;
183 71177 : if (!PyArg_ParseTuple(args, "K", &nt))
184 0 : return NULL;
185 :
186 71177 : t = nt_time_to_unix(nt);
187 :
188 71177 : return PyLong_FromLong((uint64_t)t);
189 : }
190 :
191 0 : static PyObject *py_float2nttime(PyObject *self, PyObject *args)
192 : {
193 0 : double ft = 0;
194 0 : double ft_sec = 0;
195 0 : double ft_nsec = 0;
196 : struct timespec ts;
197 0 : NTTIME nt = 0;
198 :
199 0 : if (!PyArg_ParseTuple(args, "d", &ft)) {
200 0 : return NULL;
201 : }
202 :
203 0 : ft_sec = (double)(int)ft;
204 0 : ft_nsec = (ft - ft_sec) * 1.0e+9;
205 :
206 0 : ts.tv_sec = (int)ft_sec;
207 0 : ts.tv_nsec = (int)ft_nsec;
208 :
209 0 : nt = full_timespec_to_nt_time(&ts);
210 :
211 0 : return PyLong_FromLongLong((uint64_t)nt);
212 : }
213 :
214 72 : static PyObject *py_nttime2float(PyObject *self, PyObject *args)
215 : {
216 72 : double ft = 0;
217 : struct timespec ts;
218 72 : const struct timespec ts_zero = { .tv_sec = 0, };
219 72 : NTTIME nt = 0;
220 :
221 72 : if (!PyArg_ParseTuple(args, "K", &nt)) {
222 0 : return NULL;
223 : }
224 :
225 72 : ts = nt_time_to_full_timespec(nt);
226 72 : if (is_omit_timespec(&ts)) {
227 0 : return PyFloat_FromDouble(1.0);
228 : }
229 72 : ft = timespec_elapsed2(&ts_zero, &ts);
230 :
231 72 : return PyFloat_FromDouble(ft);
232 : }
233 :
234 64 : static PyObject *py_nttime2string(PyObject *self, PyObject *args)
235 : {
236 : PyObject *ret;
237 : NTTIME nt;
238 : TALLOC_CTX *tmp_ctx;
239 : const char *string;
240 64 : if (!PyArg_ParseTuple(args, "K", &nt))
241 0 : return NULL;
242 :
243 64 : tmp_ctx = talloc_new(NULL);
244 64 : if (tmp_ctx == NULL) {
245 0 : PyErr_NoMemory();
246 0 : return NULL;
247 : }
248 :
249 64 : string = nt_time_string(tmp_ctx, nt);
250 64 : ret = PyUnicode_FromString(string);
251 :
252 64 : talloc_free(tmp_ctx);
253 :
254 64 : return ret;
255 : }
256 :
257 2001 : static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
258 : {
259 : unsigned level;
260 2001 : if (!PyArg_ParseTuple(args, "I", &level))
261 0 : return NULL;
262 2001 : debuglevel_set(level);
263 2001 : Py_RETURN_NONE;
264 : }
265 :
266 2230 : static PyObject *py_get_debug_level(PyObject *self,
267 : PyObject *Py_UNUSED(ignored))
268 : {
269 2230 : return PyLong_FromLong(debuglevel_get());
270 : }
271 :
272 11298 : static PyObject *py_fault_setup(PyObject *self,
273 : PyObject *Py_UNUSED(ignored))
274 : {
275 : static bool done;
276 11298 : if (!done) {
277 5286 : fault_setup();
278 5286 : done = true;
279 : }
280 11298 : Py_RETURN_NONE;
281 : }
282 :
283 2248 : static PyObject *py_is_ntvfs_fileserver_built(PyObject *self,
284 : PyObject *Py_UNUSED(ignored))
285 : {
286 : #ifdef WITH_NTVFS_FILESERVER
287 2248 : Py_RETURN_TRUE;
288 : #else
289 : Py_RETURN_FALSE;
290 : #endif
291 : }
292 :
293 167 : static PyObject *py_is_heimdal_built(PyObject *self,
294 : PyObject *Py_UNUSED(ignored))
295 : {
296 : #ifdef SAMBA4_USES_HEIMDAL
297 131 : Py_RETURN_TRUE;
298 : #else
299 36 : Py_RETURN_FALSE;
300 : #endif
301 : }
302 :
303 596 : static PyObject *py_is_ad_dc_built(PyObject *self,
304 : PyObject *Py_UNUSED(ignored))
305 : {
306 : #ifdef AD_DC_BUILD_IS_ENABLED
307 596 : Py_RETURN_TRUE;
308 : #else
309 : Py_RETURN_FALSE;
310 : #endif
311 : }
312 :
313 562 : static PyObject *py_is_selftest_enabled(PyObject *self,
314 : PyObject *Py_UNUSED(ignored))
315 : {
316 : #ifdef ENABLE_SELFTEST
317 562 : Py_RETURN_TRUE;
318 : #else
319 : Py_RETURN_FALSE;
320 : #endif
321 : }
322 :
323 0 : static PyObject *py_ndr_token_max_list_size(PyObject *self,
324 : PyObject *Py_UNUSED(ignored))
325 : {
326 0 : return PyLong_FromLong(ndr_token_max_list_size());
327 : }
328 :
329 : /*
330 : return the list of interface IPs we have configured
331 : takes an loadparm context, returns a list of IPs in string form
332 :
333 : Does not return addresses on 127.0.0.0/8
334 : */
335 393 : static PyObject *py_interface_ips(PyObject *self, PyObject *args)
336 : {
337 : PyObject *pylist;
338 : int count;
339 : TALLOC_CTX *tmp_ctx;
340 : PyObject *py_lp_ctx;
341 : struct loadparm_context *lp_ctx;
342 : struct interface *ifaces;
343 : int i, ifcount;
344 393 : int all_interfaces = 1;
345 :
346 393 : if (!PyArg_ParseTuple(args, "O|i", &py_lp_ctx, &all_interfaces))
347 0 : return NULL;
348 :
349 393 : tmp_ctx = talloc_new(NULL);
350 393 : if (tmp_ctx == NULL) {
351 0 : PyErr_NoMemory();
352 0 : return NULL;
353 : }
354 :
355 393 : lp_ctx = lpcfg_from_py_object(tmp_ctx, py_lp_ctx);
356 393 : if (lp_ctx == NULL) {
357 0 : talloc_free(tmp_ctx);
358 0 : return NULL;
359 : }
360 :
361 393 : load_interface_list(tmp_ctx, lp_ctx, &ifaces);
362 :
363 393 : count = iface_list_count(ifaces);
364 :
365 : /* first count how many are not loopback addresses */
366 1844 : for (ifcount = i = 0; i<count; i++) {
367 1451 : const char *ip = iface_list_n_ip(ifaces, i);
368 :
369 1451 : if (all_interfaces) {
370 202 : ifcount++;
371 202 : continue;
372 : }
373 :
374 1249 : if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
375 0 : continue;
376 : }
377 :
378 1249 : if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
379 0 : continue;
380 : }
381 :
382 1249 : if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
383 0 : continue;
384 : }
385 :
386 1249 : if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
387 0 : continue;
388 : }
389 :
390 1249 : ifcount++;
391 : }
392 :
393 393 : pylist = PyList_New(ifcount);
394 1844 : for (ifcount = i = 0; i<count; i++) {
395 1451 : const char *ip = iface_list_n_ip(ifaces, i);
396 :
397 1451 : if (all_interfaces) {
398 202 : PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
399 202 : ifcount++;
400 202 : continue;
401 : }
402 :
403 1249 : if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
404 0 : continue;
405 : }
406 :
407 1249 : if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
408 0 : continue;
409 : }
410 :
411 1249 : if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
412 0 : continue;
413 : }
414 :
415 1249 : if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
416 0 : continue;
417 : }
418 :
419 1249 : PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
420 1249 : ifcount++;
421 : }
422 393 : talloc_free(tmp_ctx);
423 393 : return pylist;
424 : }
425 :
426 0 : static PyObject *py_strcasecmp_m(PyObject *self, PyObject *args)
427 : {
428 0 : const char *s1 = NULL;
429 0 : const char *s2 = NULL;
430 0 : long cmp_result = 0;
431 0 : if (!PyArg_ParseTuple(args, PYARG_STR_UNI
432 : PYARG_STR_UNI,
433 : "utf8", &s1, "utf8", &s2)) {
434 0 : return NULL;
435 : }
436 :
437 0 : cmp_result = strcasecmp_m(s1, s2);
438 0 : PyMem_Free(discard_const_p(char, s1));
439 0 : PyMem_Free(discard_const_p(char, s2));
440 0 : return PyLong_FromLong(cmp_result);
441 : }
442 :
443 0 : static PyObject *py_strstr_m(PyObject *self, PyObject *args)
444 : {
445 0 : const char *s1 = NULL;
446 0 : const char *s2 = NULL;
447 0 : char *strstr_ret = NULL;
448 0 : PyObject *result = NULL;
449 0 : if (!PyArg_ParseTuple(args, PYARG_STR_UNI
450 : PYARG_STR_UNI,
451 : "utf8", &s1, "utf8", &s2))
452 0 : return NULL;
453 :
454 0 : strstr_ret = strstr_m(s1, s2);
455 0 : if (!strstr_ret) {
456 0 : PyMem_Free(discard_const_p(char, s1));
457 0 : PyMem_Free(discard_const_p(char, s2));
458 0 : Py_RETURN_NONE;
459 : }
460 0 : result = PyUnicode_FromString(strstr_ret);
461 0 : PyMem_Free(discard_const_p(char, s1));
462 0 : PyMem_Free(discard_const_p(char, s2));
463 0 : return result;
464 : }
465 :
466 11298 : static PyObject *py_get_burnt_commandline(PyObject *self, PyObject *args)
467 : {
468 : PyObject *cmdline_as_list, *ret;
469 11298 : char *burnt_cmdline = NULL;
470 : Py_ssize_t i, argc;
471 11298 : char **argv = NULL;
472 11298 : TALLOC_CTX *frame = talloc_stackframe();
473 : bool burnt;
474 :
475 11298 : if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &cmdline_as_list))
476 : {
477 0 : TALLOC_FREE(frame);
478 0 : return NULL;
479 : }
480 :
481 11298 : argc = PyList_GET_SIZE(cmdline_as_list);
482 :
483 11298 : if (argc == 0) {
484 0 : TALLOC_FREE(frame);
485 0 : Py_RETURN_NONE;
486 : }
487 :
488 11298 : argv = PyList_AsStringList(frame, cmdline_as_list, "sys.argv");
489 11298 : if (argv == NULL) {
490 0 : return NULL;
491 : }
492 :
493 11298 : burnt = samba_cmdline_burn(argc, argv);
494 11298 : if (!burnt) {
495 8237 : TALLOC_FREE(frame);
496 8237 : Py_RETURN_NONE;
497 : }
498 :
499 17199 : for (i = 0; i < argc; i++) {
500 14138 : if (i == 0) {
501 3061 : burnt_cmdline = talloc_strdup(frame,
502 3061 : argv[i]);
503 : } else {
504 : burnt_cmdline
505 11077 : = talloc_asprintf_append(burnt_cmdline,
506 : " %s",
507 11077 : argv[i]);
508 : }
509 14138 : if (burnt_cmdline == NULL) {
510 0 : PyErr_NoMemory();
511 0 : TALLOC_FREE(frame);
512 0 : return NULL;
513 : }
514 : }
515 :
516 3061 : ret = PyUnicode_FromString(burnt_cmdline);
517 3061 : TALLOC_FREE(frame);
518 :
519 3061 : return ret;
520 : }
521 :
522 : static PyMethodDef py_misc_methods[] = {
523 : { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
524 : "generate_random_str(len) -> string\n"
525 : "Generate random string with specified length." },
526 : { "generate_random_password", (PyCFunction)py_generate_random_password,
527 : METH_VARARGS, "generate_random_password(min, max) -> string\n"
528 : "Generate random password (based on printable ascii characters) "
529 : "with a length >= min and <= max." },
530 : { "generate_random_machine_password", (PyCFunction)py_generate_random_machine_password,
531 : METH_VARARGS, "generate_random_machine_password(min, max) -> string\n"
532 : "Generate random password "
533 : "(based on random utf16 characters converted to utf8 or "
534 : "random ascii characters if 'unix charset' is not 'utf8')"
535 : "with a length >= min (at least 14) and <= max (at most 255)." },
536 : { "check_password_quality", (PyCFunction)py_check_password_quality,
537 : METH_VARARGS, "check_password_quality(pass) -> bool\n"
538 : "Check password quality against Samba's check_password_quality,"
539 : "the implementation of Microsoft's rules:"
540 : "http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx"
541 : },
542 : { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
543 : "unix2nttime(timestamp) -> nttime" },
544 : { "nttime2unix", (PyCFunction)py_nttime2unix, METH_VARARGS,
545 : "nttime2unix(nttime) -> timestamp" },
546 : { "float2nttime", (PyCFunction)py_float2nttime, METH_VARARGS,
547 : "pytime2nttime(floattimestamp) -> nttime" },
548 : { "nttime2float", (PyCFunction)py_nttime2float, METH_VARARGS,
549 : "nttime2pytime(nttime) -> floattimestamp" },
550 : { "nttime2string", (PyCFunction)py_nttime2string, METH_VARARGS,
551 : "nttime2string(nttime) -> string" },
552 : { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
553 : "set debug level" },
554 : { "get_debug_level", (PyCFunction)py_get_debug_level, METH_NOARGS,
555 : "get debug level" },
556 : { "fault_setup", (PyCFunction)py_fault_setup, METH_NOARGS,
557 : "setup the default samba panic handler" },
558 : { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS,
559 : "interface_ips(lp_ctx[, all_interfaces) -> list_of_ifaces\n"
560 : "\n"
561 : "get interface IP address list"},
562 : { "strcasecmp_m", (PyCFunction)py_strcasecmp_m, METH_VARARGS,
563 : "(for testing) compare two strings using Samba's strcasecmp_m()"},
564 : { "strstr_m", (PyCFunction)py_strstr_m, METH_VARARGS,
565 : "(for testing) find one string in another with Samba's strstr_m()"},
566 : { "is_ntvfs_fileserver_built", (PyCFunction)py_is_ntvfs_fileserver_built, METH_NOARGS,
567 : "is the NTVFS file server built in this installation?" },
568 : { "is_heimdal_built", (PyCFunction)py_is_heimdal_built, METH_NOARGS,
569 : "is Samba built with Heimdal Kerberbos?" },
570 : { "generate_random_bytes",
571 : (PyCFunction)py_generate_random_bytes,
572 : METH_VARARGS,
573 : "generate_random_bytes(len) -> bytes\n"
574 : "Generate random bytes with specified length." },
575 : { "is_ad_dc_built", (PyCFunction)py_is_ad_dc_built, METH_NOARGS,
576 : "is Samba built with AD DC?" },
577 : { "is_selftest_enabled", (PyCFunction)py_is_selftest_enabled,
578 : METH_NOARGS, "is Samba built with selftest enabled?" },
579 : { "ndr_token_max_list_size", (PyCFunction)py_ndr_token_max_list_size,
580 : METH_NOARGS, "How many NDR internal tokens is too many for this build?" },
581 : { "get_burnt_commandline", (PyCFunction)py_get_burnt_commandline,
582 : METH_VARARGS, "Return a redacted commandline to feed to setproctitle (None if no redaction required)" },
583 : {0}
584 : };
585 :
586 : static struct PyModuleDef moduledef = {
587 : PyModuleDef_HEAD_INIT,
588 : .m_name = "_glue",
589 : .m_doc = "Python bindings for miscellaneous Samba functions.",
590 : .m_size = -1,
591 : .m_methods = py_misc_methods,
592 : };
593 :
594 7558 : MODULE_INIT_FUNC(_glue)
595 : {
596 : PyObject *m;
597 :
598 7558 : debug_setup_talloc_log();
599 :
600 7558 : m = PyModule_Create(&moduledef);
601 7558 : if (m == NULL)
602 0 : return NULL;
603 :
604 7558 : PyModule_AddObject(m, "version",
605 : PyUnicode_FromString(SAMBA_VERSION_STRING));
606 7558 : PyExc_NTSTATUSError = PyErr_NewException(discard_const_p(char, "samba.NTSTATUSError"), PyExc_RuntimeError, NULL);
607 7558 : if (PyExc_NTSTATUSError != NULL) {
608 7558 : Py_INCREF(PyExc_NTSTATUSError);
609 7558 : PyModule_AddObject(m, "NTSTATUSError", PyExc_NTSTATUSError);
610 : }
611 :
612 7558 : PyExc_WERRORError = PyErr_NewException(discard_const_p(char, "samba.WERRORError"), PyExc_RuntimeError, NULL);
613 7558 : if (PyExc_WERRORError != NULL) {
614 7558 : Py_INCREF(PyExc_WERRORError);
615 7558 : PyModule_AddObject(m, "WERRORError", PyExc_WERRORError);
616 : }
617 :
618 7558 : PyExc_HRESULTError = PyErr_NewException(discard_const_p(char, "samba.HRESULTError"), PyExc_RuntimeError, NULL);
619 7558 : if (PyExc_HRESULTError != NULL) {
620 7558 : Py_INCREF(PyExc_HRESULTError);
621 7558 : PyModule_AddObject(m, "HRESULTError", PyExc_HRESULTError);
622 : }
623 :
624 7558 : PyExc_DsExtendedError = PyErr_NewException(discard_const_p(char, "samba.DsExtendedError"), PyExc_RuntimeError, NULL);
625 7558 : if (PyExc_DsExtendedError != NULL) {
626 7558 : Py_INCREF(PyExc_DsExtendedError);
627 7558 : PyModule_AddObject(m, "DsExtendedError", PyExc_DsExtendedError);
628 : }
629 :
630 7558 : return m;
631 : }
|