libsmb: Simplify an if-condition
[Samba.git] / python / pyglue.c
blobc24d1b033a486c3cea8a09407e2505dfaa5723aa
1 /*
2 Unix SMB/CIFS implementation.
3 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
4 Copyright (C) Matthias Dieter Wallnöfer 2009
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.
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.
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/>.
20 #include "lib/replace/system/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 #include "lib/crypto/gkdi.h"
32 void init_glue(void);
33 static PyObject *PyExc_NTSTATUSError;
34 static PyObject *PyExc_WERRORError;
35 static PyObject *PyExc_HRESULTError;
36 static PyObject *PyExc_DsExtendedError;
38 static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
40 Py_ssize_t len;
41 PyObject *ret;
42 char *retstr;
44 if (!PyArg_ParseTuple(args, "n", &len)) {
45 return NULL;
47 if (len < 0) {
48 PyErr_Format(PyExc_ValueError,
49 "random string length should be positive, not %zd",
50 len);
51 return NULL;
53 retstr = generate_random_str(NULL, len);
54 if (retstr == NULL) {
55 return PyErr_NoMemory();
57 ret = PyUnicode_FromStringAndSize(retstr, len);
58 talloc_free(retstr);
59 return ret;
62 static PyObject *py_generate_random_password(PyObject *self, PyObject *args)
64 Py_ssize_t min, max;
65 PyObject *ret;
66 char *retstr;
68 if (!PyArg_ParseTuple(args, "nn", &min, &max)) {
69 return NULL;
71 if (max < 0 || min < 0) {
73 * The real range checks happens in generate_random_password().
74 * Here just filter out any negative numbers.
76 PyErr_Format(PyExc_ValueError,
77 "invalid range: %zd - %zd",
78 min, max);
79 return NULL;
82 retstr = generate_random_password(NULL, min, max);
83 if (retstr == NULL) {
84 if (errno == EINVAL) {
85 return PyErr_Format(PyExc_ValueError,
86 "invalid range: %zd - %zd",
87 min, max);
89 return PyErr_NoMemory();
91 ret = PyUnicode_FromString(retstr);
92 talloc_free(retstr);
93 return ret;
96 static PyObject *py_generate_random_machine_password(PyObject *self, PyObject *args)
98 Py_ssize_t min, max;
99 PyObject *ret;
100 char *retstr;
102 if (!PyArg_ParseTuple(args, "nn", &min, &max)) {
103 return NULL;
105 if (max < 0 || min < 0) {
107 * The real range checks happens in
108 * generate_random_machine_password().
109 * Here we just filter out any negative numbers.
111 PyErr_Format(PyExc_ValueError,
112 "invalid range: %zd - %zd",
113 min, max);
114 return NULL;
117 retstr = generate_random_machine_password(NULL, min, max);
118 if (retstr == NULL) {
119 if (errno == EINVAL) {
120 return PyErr_Format(PyExc_ValueError,
121 "invalid range: %zd - %zd",
122 min, max);
124 return PyErr_NoMemory();
126 ret = PyUnicode_FromString(retstr);
127 talloc_free(retstr);
128 return ret;
131 static PyObject *py_check_password_quality(PyObject *self, PyObject *args)
133 char *pass;
135 if (!PyArg_ParseTuple(args, "s", &pass)) {
136 return NULL;
139 return PyBool_FromLong(check_password_quality(pass));
142 static PyObject *py_generate_random_bytes(PyObject *self, PyObject *args)
144 Py_ssize_t len;
145 PyObject *ret;
146 uint8_t *bytes = NULL;
148 if (!PyArg_ParseTuple(args, "n", &len)) {
149 return NULL;
151 if (len < 0) {
152 PyErr_Format(PyExc_ValueError,
153 "random bytes length should be positive, not %zd",
154 len);
155 return NULL;
157 bytes = talloc_zero_size(NULL, len);
158 if (bytes == NULL) {
159 PyErr_NoMemory();
160 return NULL;
162 generate_random_buffer(bytes, len);
163 ret = PyBytes_FromStringAndSize((const char *)bytes, len);
164 talloc_free(bytes);
165 return ret;
168 static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
170 time_t t;
171 unsigned int _t;
172 NTTIME nt;
174 if (!PyArg_ParseTuple(args, "I", &_t)) {
175 return NULL;
177 t = _t;
179 unix_to_nt_time(&nt, t);
181 return PyLong_FromLongLong((uint64_t)nt);
184 static PyObject *py_nttime2unix(PyObject *self, PyObject *args)
186 time_t t;
187 NTTIME nt;
188 if (!PyArg_ParseTuple(args, "K", &nt))
189 return NULL;
191 t = nt_time_to_unix(nt);
193 return PyLong_FromLong((uint64_t)t);
196 static PyObject *py_float2nttime(PyObject *self, PyObject *args)
198 double ft = 0;
199 double ft_sec = 0;
200 double ft_nsec = 0;
201 struct timespec ts;
202 NTTIME nt = 0;
204 if (!PyArg_ParseTuple(args, "d", &ft)) {
205 return NULL;
208 ft_sec = (double)(int)ft;
209 ft_nsec = (ft - ft_sec) * 1.0e+9;
211 ts.tv_sec = (int)ft_sec;
212 ts.tv_nsec = (int)ft_nsec;
214 nt = full_timespec_to_nt_time(&ts);
216 return PyLong_FromLongLong((uint64_t)nt);
219 static PyObject *py_nttime2float(PyObject *self, PyObject *args)
221 double ft = 0;
222 struct timespec ts;
223 const struct timespec ts_zero = { .tv_sec = 0, };
224 NTTIME nt = 0;
226 if (!PyArg_ParseTuple(args, "K", &nt)) {
227 return NULL;
230 ts = nt_time_to_full_timespec(nt);
231 if (is_omit_timespec(&ts)) {
232 return PyFloat_FromDouble(1.0);
234 ft = timespec_elapsed2(&ts_zero, &ts);
236 return PyFloat_FromDouble(ft);
239 static PyObject *py_nttime2string(PyObject *self, PyObject *args)
241 PyObject *ret;
242 NTTIME nt;
243 TALLOC_CTX *tmp_ctx;
244 const char *string;
245 if (!PyArg_ParseTuple(args, "K", &nt))
246 return NULL;
248 tmp_ctx = talloc_new(NULL);
249 if (tmp_ctx == NULL) {
250 PyErr_NoMemory();
251 return NULL;
254 string = nt_time_string(tmp_ctx, nt);
255 ret = PyUnicode_FromString(string);
257 talloc_free(tmp_ctx);
259 return ret;
262 static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
264 unsigned level;
265 if (!PyArg_ParseTuple(args, "I", &level))
266 return NULL;
267 debuglevel_set(level);
268 Py_RETURN_NONE;
271 static PyObject *py_get_debug_level(PyObject *self,
272 PyObject *Py_UNUSED(ignored))
274 return PyLong_FromLong(debuglevel_get());
277 static PyObject *py_fault_setup(PyObject *self,
278 PyObject *Py_UNUSED(ignored))
280 static bool done;
281 if (!done) {
282 fault_setup();
283 done = true;
285 Py_RETURN_NONE;
288 static PyObject *py_is_ntvfs_fileserver_built(PyObject *self,
289 PyObject *Py_UNUSED(ignored))
291 #ifdef WITH_NTVFS_FILESERVER
292 Py_RETURN_TRUE;
293 #else
294 Py_RETURN_FALSE;
295 #endif
298 static PyObject *py_is_heimdal_built(PyObject *self,
299 PyObject *Py_UNUSED(ignored))
301 #ifdef SAMBA4_USES_HEIMDAL
302 Py_RETURN_TRUE;
303 #else
304 Py_RETURN_FALSE;
305 #endif
308 static PyObject *py_is_ad_dc_built(PyObject *self,
309 PyObject *Py_UNUSED(ignored))
311 #ifdef AD_DC_BUILD_IS_ENABLED
312 Py_RETURN_TRUE;
313 #else
314 Py_RETURN_FALSE;
315 #endif
318 static PyObject *py_is_selftest_enabled(PyObject *self,
319 PyObject *Py_UNUSED(ignored))
321 #ifdef ENABLE_SELFTEST
322 Py_RETURN_TRUE;
323 #else
324 Py_RETURN_FALSE;
325 #endif
328 static PyObject *py_ndr_token_max_list_size(PyObject *self,
329 PyObject *Py_UNUSED(ignored))
331 return PyLong_FromLong(ndr_token_max_list_size());
335 return the list of interface IPs we have configured
336 takes an loadparm context, returns a list of IPs in string form
338 Does not return addresses on 127.0.0.0/8
340 static PyObject *py_interface_ips(PyObject *self, PyObject *args)
342 PyObject *pylist;
343 int count;
344 TALLOC_CTX *tmp_ctx;
345 PyObject *py_lp_ctx;
346 struct loadparm_context *lp_ctx;
347 struct interface *ifaces;
348 int i, ifcount;
349 int all_interfaces = 1;
351 if (!PyArg_ParseTuple(args, "O|i", &py_lp_ctx, &all_interfaces))
352 return NULL;
354 tmp_ctx = talloc_new(NULL);
355 if (tmp_ctx == NULL) {
356 PyErr_NoMemory();
357 return NULL;
360 lp_ctx = lpcfg_from_py_object(tmp_ctx, py_lp_ctx);
361 if (lp_ctx == NULL) {
362 talloc_free(tmp_ctx);
363 return PyErr_NoMemory();
366 load_interface_list(tmp_ctx, lp_ctx, &ifaces);
368 count = iface_list_count(ifaces);
370 /* first count how many are not loopback addresses */
371 for (ifcount = i = 0; i<count; i++) {
372 const char *ip = iface_list_n_ip(ifaces, i);
374 if (all_interfaces) {
375 ifcount++;
376 continue;
379 if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
380 continue;
383 if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
384 continue;
387 if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
388 continue;
391 if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
392 continue;
395 ifcount++;
398 pylist = PyList_New(ifcount);
399 for (ifcount = i = 0; i<count; i++) {
400 const char *ip = iface_list_n_ip(ifaces, i);
402 if (all_interfaces) {
403 PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
404 ifcount++;
405 continue;
408 if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
409 continue;
412 if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
413 continue;
416 if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
417 continue;
420 if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
421 continue;
424 PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
425 ifcount++;
427 talloc_free(tmp_ctx);
428 return pylist;
431 static PyObject *py_strcasecmp_m(PyObject *self, PyObject *args)
433 char *s1 = NULL;
434 char *s2 = NULL;
435 long cmp_result = 0;
436 if (!PyArg_ParseTuple(args, PYARG_STR_UNI
437 PYARG_STR_UNI,
438 "utf8", &s1, "utf8", &s2)) {
439 return NULL;
442 cmp_result = strcasecmp_m(s1, s2);
443 PyMem_Free(s1);
444 PyMem_Free(s2);
445 return PyLong_FromLong(cmp_result);
448 static PyObject *py_strstr_m(PyObject *self, PyObject *args)
450 char *s1 = NULL;
451 char *s2 = NULL;
452 char *strstr_ret = NULL;
453 PyObject *result = NULL;
454 if (!PyArg_ParseTuple(args, PYARG_STR_UNI
455 PYARG_STR_UNI,
456 "utf8", &s1, "utf8", &s2))
457 return NULL;
459 strstr_ret = strstr_m(s1, s2);
460 if (!strstr_ret) {
461 PyMem_Free(s1);
462 PyMem_Free(s2);
463 Py_RETURN_NONE;
465 result = PyUnicode_FromString(strstr_ret);
466 PyMem_Free(s1);
467 PyMem_Free(s2);
468 return result;
471 static PyObject *py_get_burnt_commandline(PyObject *self, PyObject *args)
473 PyObject *cmdline_as_list, *ret;
474 char *burnt_cmdline = NULL;
475 Py_ssize_t i, argc;
476 char **argv = NULL;
477 TALLOC_CTX *frame = talloc_stackframe();
478 bool burnt;
480 if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &cmdline_as_list))
482 TALLOC_FREE(frame);
483 return NULL;
486 argc = PyList_GET_SIZE(cmdline_as_list);
488 if (argc == 0) {
489 TALLOC_FREE(frame);
490 Py_RETURN_NONE;
493 argv = PyList_AsStringList(frame, cmdline_as_list, "sys.argv");
494 if (argv == NULL) {
495 TALLOC_FREE(frame);
496 return NULL;
499 burnt = samba_cmdline_burn(argc, argv);
500 if (!burnt) {
501 TALLOC_FREE(frame);
502 Py_RETURN_NONE;
505 for (i = 0; i < argc; i++) {
506 if (i == 0) {
507 burnt_cmdline = talloc_strdup(frame,
508 argv[i]);
509 } else {
510 burnt_cmdline
511 = talloc_asprintf_append(burnt_cmdline,
512 " %s",
513 argv[i]);
515 if (burnt_cmdline == NULL) {
516 PyErr_NoMemory();
517 TALLOC_FREE(frame);
518 return NULL;
522 ret = PyUnicode_FromString(burnt_cmdline);
523 TALLOC_FREE(frame);
525 return ret;
528 static PyMethodDef py_misc_methods[] = {
529 { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
530 "generate_random_str(len) -> string\n"
531 "Generate random string with specified length." },
532 { "generate_random_password", (PyCFunction)py_generate_random_password,
533 METH_VARARGS, "generate_random_password(min, max) -> string\n"
534 "Generate random password (based on printable ascii characters) "
535 "with a length >= min and <= max." },
536 { "generate_random_machine_password", (PyCFunction)py_generate_random_machine_password,
537 METH_VARARGS, "generate_random_machine_password(min, max) -> string\n"
538 "Generate random password "
539 "(based on random utf16 characters converted to utf8 or "
540 "random ascii characters if 'unix charset' is not 'utf8') "
541 "with a length >= min (at least 14) and <= max (at most 255)." },
542 { "check_password_quality", (PyCFunction)py_check_password_quality,
543 METH_VARARGS, "check_password_quality(pass) -> bool\n"
544 "Check password quality against Samba's check_password_quality, "
545 "the implementation of Microsoft's rules: "
546 "http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx"
548 { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
549 "unix2nttime(timestamp) -> nttime" },
550 { "nttime2unix", (PyCFunction)py_nttime2unix, METH_VARARGS,
551 "nttime2unix(nttime) -> timestamp" },
552 { "float2nttime", (PyCFunction)py_float2nttime, METH_VARARGS,
553 "pytime2nttime(floattimestamp) -> nttime" },
554 { "nttime2float", (PyCFunction)py_nttime2float, METH_VARARGS,
555 "nttime2pytime(nttime) -> floattimestamp" },
556 { "nttime2string", (PyCFunction)py_nttime2string, METH_VARARGS,
557 "nttime2string(nttime) -> string" },
558 { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
559 "set debug level" },
560 { "get_debug_level", (PyCFunction)py_get_debug_level, METH_NOARGS,
561 "get debug level" },
562 { "fault_setup", (PyCFunction)py_fault_setup, METH_NOARGS,
563 "setup the default samba panic handler" },
564 { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS,
565 "interface_ips(lp_ctx[, all_interfaces) -> list_of_ifaces\n"
566 "\n"
567 "get interface IP address list"},
568 { "strcasecmp_m", (PyCFunction)py_strcasecmp_m, METH_VARARGS,
569 "(for testing) compare two strings using Samba's strcasecmp_m()"},
570 { "strstr_m", (PyCFunction)py_strstr_m, METH_VARARGS,
571 "(for testing) find one string in another with Samba's strstr_m()"},
572 { "is_ntvfs_fileserver_built", (PyCFunction)py_is_ntvfs_fileserver_built, METH_NOARGS,
573 "is the NTVFS file server built in this installation?" },
574 { "is_heimdal_built", (PyCFunction)py_is_heimdal_built, METH_NOARGS,
575 "is Samba built with Heimdal Kerberos?" },
576 { "generate_random_bytes",
577 (PyCFunction)py_generate_random_bytes,
578 METH_VARARGS,
579 "generate_random_bytes(len) -> bytes\n"
580 "Generate random bytes with specified length." },
581 { "is_ad_dc_built", (PyCFunction)py_is_ad_dc_built, METH_NOARGS,
582 "is Samba built with AD DC?" },
583 { "is_selftest_enabled", (PyCFunction)py_is_selftest_enabled,
584 METH_NOARGS, "is Samba built with selftest enabled?" },
585 { "ndr_token_max_list_size", (PyCFunction)py_ndr_token_max_list_size,
586 METH_NOARGS, "How many NDR internal tokens is too many for this build?" },
587 { "get_burnt_commandline", (PyCFunction)py_get_burnt_commandline,
588 METH_VARARGS, "Return a redacted commandline to feed to setproctitle (None if no redaction required)" },
592 static struct PyModuleDef moduledef = {
593 PyModuleDef_HEAD_INIT,
594 .m_name = "_glue",
595 .m_doc = "Python bindings for miscellaneous Samba functions.",
596 .m_size = -1,
597 .m_methods = py_misc_methods,
600 MODULE_INIT_FUNC(_glue)
602 PyObject *m;
603 PyObject *py_obj = NULL;
604 int ret;
606 debug_setup_talloc_log();
608 m = PyModule_Create(&moduledef);
609 if (m == NULL)
610 return NULL;
612 PyModule_AddObject(m, "version",
613 PyUnicode_FromString(SAMBA_VERSION_STRING));
614 PyExc_NTSTATUSError = PyErr_NewException("samba.NTSTATUSError", PyExc_RuntimeError, NULL);
615 if (PyExc_NTSTATUSError != NULL) {
616 Py_INCREF(PyExc_NTSTATUSError);
617 PyModule_AddObject(m, "NTSTATUSError", PyExc_NTSTATUSError);
620 PyExc_WERRORError = PyErr_NewException("samba.WERRORError", PyExc_RuntimeError, NULL);
621 if (PyExc_WERRORError != NULL) {
622 Py_INCREF(PyExc_WERRORError);
623 PyModule_AddObject(m, "WERRORError", PyExc_WERRORError);
626 PyExc_HRESULTError = PyErr_NewException("samba.HRESULTError", PyExc_RuntimeError, NULL);
627 if (PyExc_HRESULTError != NULL) {
628 Py_INCREF(PyExc_HRESULTError);
629 PyModule_AddObject(m, "HRESULTError", PyExc_HRESULTError);
632 PyExc_DsExtendedError = PyErr_NewException("samba.DsExtendedError", PyExc_RuntimeError, NULL);
633 if (PyExc_DsExtendedError != NULL) {
634 Py_INCREF(PyExc_DsExtendedError);
635 PyModule_AddObject(m, "DsExtendedError", PyExc_DsExtendedError);
638 ret = PyModule_AddIntConstant(m, "GKDI_L1_KEY_ITERATION", gkdi_l1_key_iteration);
639 if (ret) {
640 Py_DECREF(m);
641 return NULL;
643 ret = PyModule_AddIntConstant(m, "GKDI_L2_KEY_ITERATION", gkdi_l2_key_iteration);
644 if (ret) {
645 Py_DECREF(m);
646 return NULL;
648 py_obj = PyLong_FromLongLong(gkdi_key_cycle_duration);
649 if (py_obj == NULL) {
650 Py_DECREF(m);
651 return NULL;
653 ret = PyModule_AddObject(m, "GKDI_KEY_CYCLE_DURATION", py_obj);
654 if (ret) {
655 Py_DECREF(py_obj);
656 Py_DECREF(m);
657 return NULL;
659 py_obj = PyLong_FromLongLong(gkdi_max_clock_skew);
660 if (py_obj == NULL) {
661 Py_DECREF(m);
662 return NULL;
664 ret = PyModule_AddObject(m, "GKDI_MAX_CLOCK_SKEW", py_obj);
665 if (ret) {
666 Py_DECREF(py_obj);
667 Py_DECREF(m);
668 return NULL;
671 return m;