tests: Fix a comment
[samba4-gss.git] / python / pyglue.c
blob5598c0929f3e0ed505e0ab8775d06d6a1202d233
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 static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
34 Py_ssize_t len;
35 PyObject *ret;
36 char *retstr;
38 if (!PyArg_ParseTuple(args, "n", &len)) {
39 return NULL;
41 if (len < 0) {
42 PyErr_Format(PyExc_ValueError,
43 "random string length should be positive, not %zd",
44 len);
45 return NULL;
47 retstr = generate_random_str(NULL, len);
48 if (retstr == NULL) {
49 return PyErr_NoMemory();
51 ret = PyUnicode_FromStringAndSize(retstr, len);
52 talloc_free(retstr);
53 return ret;
56 static PyObject *py_generate_random_password(PyObject *self, PyObject *args)
58 Py_ssize_t min, max;
59 PyObject *ret;
60 char *retstr;
62 if (!PyArg_ParseTuple(args, "nn", &min, &max)) {
63 return NULL;
65 if (max < 0 || min < 0) {
67 * The real range checks happens in generate_random_password().
68 * Here just filter out any negative numbers.
70 PyErr_Format(PyExc_ValueError,
71 "invalid range: %zd - %zd",
72 min, max);
73 return NULL;
76 retstr = generate_random_password(NULL, min, max);
77 if (retstr == NULL) {
78 if (errno == EINVAL) {
79 return PyErr_Format(PyExc_ValueError,
80 "invalid range: %zd - %zd",
81 min, max);
83 return PyErr_NoMemory();
85 ret = PyUnicode_FromString(retstr);
86 talloc_free(retstr);
87 return ret;
90 static PyObject *py_generate_random_machine_password(PyObject *self, PyObject *args)
92 Py_ssize_t min, max;
93 PyObject *ret;
94 char *retstr;
96 if (!PyArg_ParseTuple(args, "nn", &min, &max)) {
97 return NULL;
99 if (max < 0 || min < 0) {
101 * The real range checks happens in
102 * generate_random_machine_password().
103 * Here we just filter out any negative numbers.
105 PyErr_Format(PyExc_ValueError,
106 "invalid range: %zd - %zd",
107 min, max);
108 return NULL;
111 retstr = generate_random_machine_password(NULL, min, max);
112 if (retstr == NULL) {
113 if (errno == EINVAL) {
114 return PyErr_Format(PyExc_ValueError,
115 "invalid range: %zd - %zd",
116 min, max);
118 return PyErr_NoMemory();
120 ret = PyUnicode_FromString(retstr);
121 talloc_free(retstr);
122 return ret;
125 static PyObject *py_check_password_quality(PyObject *self, PyObject *args)
127 char *pass;
129 if (!PyArg_ParseTuple(args, "s", &pass)) {
130 return NULL;
133 return PyBool_FromLong(check_password_quality(pass));
136 static PyObject *py_generate_random_bytes(PyObject *self, PyObject *args)
138 Py_ssize_t len;
139 PyObject *ret;
140 uint8_t *bytes = NULL;
142 if (!PyArg_ParseTuple(args, "n", &len)) {
143 return NULL;
145 if (len < 0) {
146 PyErr_Format(PyExc_ValueError,
147 "random bytes length should be positive, not %zd",
148 len);
149 return NULL;
151 bytes = talloc_zero_size(NULL, len);
152 if (bytes == NULL) {
153 PyErr_NoMemory();
154 return NULL;
156 generate_random_buffer(bytes, len);
157 ret = PyBytes_FromStringAndSize((const char *)bytes, len);
158 talloc_free(bytes);
159 return ret;
162 static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
164 time_t t;
165 unsigned int _t;
166 NTTIME nt;
168 if (!PyArg_ParseTuple(args, "I", &_t)) {
169 return NULL;
171 t = _t;
173 unix_to_nt_time(&nt, t);
175 return PyLong_FromLongLong((uint64_t)nt);
178 static PyObject *py_nttime2unix(PyObject *self, PyObject *args)
180 time_t t;
181 NTTIME nt;
182 if (!PyArg_ParseTuple(args, "K", &nt))
183 return NULL;
185 t = nt_time_to_unix(nt);
187 return PyLong_FromLong((uint64_t)t);
190 static PyObject *py_float2nttime(PyObject *self, PyObject *args)
192 double ft = 0;
193 double ft_sec = 0;
194 double ft_nsec = 0;
195 struct timespec ts;
196 NTTIME nt = 0;
198 if (!PyArg_ParseTuple(args, "d", &ft)) {
199 return NULL;
202 ft_sec = (double)(int)ft;
203 ft_nsec = (ft - ft_sec) * 1.0e+9;
205 ts.tv_sec = (int)ft_sec;
206 ts.tv_nsec = (int)ft_nsec;
208 nt = full_timespec_to_nt_time(&ts);
210 return PyLong_FromLongLong((uint64_t)nt);
213 static PyObject *py_nttime2float(PyObject *self, PyObject *args)
215 double ft = 0;
216 struct timespec ts;
217 const struct timespec ts_zero = { .tv_sec = 0, };
218 NTTIME nt = 0;
220 if (!PyArg_ParseTuple(args, "K", &nt)) {
221 return NULL;
224 ts = nt_time_to_full_timespec(nt);
225 if (is_omit_timespec(&ts)) {
226 return PyFloat_FromDouble(1.0);
228 ft = timespec_elapsed2(&ts_zero, &ts);
230 return PyFloat_FromDouble(ft);
233 static PyObject *py_nttime2string(PyObject *self, PyObject *args)
235 PyObject *ret;
236 NTTIME nt;
237 TALLOC_CTX *tmp_ctx;
238 const char *string;
239 if (!PyArg_ParseTuple(args, "K", &nt))
240 return NULL;
242 tmp_ctx = talloc_new(NULL);
243 if (tmp_ctx == NULL) {
244 PyErr_NoMemory();
245 return NULL;
248 string = nt_time_string(tmp_ctx, nt);
249 ret = PyUnicode_FromString(string);
251 talloc_free(tmp_ctx);
253 return ret;
256 static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
258 unsigned level;
259 if (!PyArg_ParseTuple(args, "I", &level))
260 return NULL;
261 debuglevel_set(level);
262 Py_RETURN_NONE;
265 static PyObject *py_get_debug_level(PyObject *self,
266 PyObject *Py_UNUSED(ignored))
268 return PyLong_FromLong(debuglevel_get());
271 static PyObject *py_fault_setup(PyObject *self,
272 PyObject *Py_UNUSED(ignored))
274 static bool done;
275 if (!done) {
276 fault_setup();
277 done = true;
279 Py_RETURN_NONE;
282 static PyObject *py_is_ntvfs_fileserver_built(PyObject *self,
283 PyObject *Py_UNUSED(ignored))
285 #ifdef WITH_NTVFS_FILESERVER
286 Py_RETURN_TRUE;
287 #else
288 Py_RETURN_FALSE;
289 #endif
292 static PyObject *py_is_heimdal_built(PyObject *self,
293 PyObject *Py_UNUSED(ignored))
295 #ifdef SAMBA4_USES_HEIMDAL
296 Py_RETURN_TRUE;
297 #else
298 Py_RETURN_FALSE;
299 #endif
302 static PyObject *py_is_ad_dc_built(PyObject *self,
303 PyObject *Py_UNUSED(ignored))
305 #ifdef AD_DC_BUILD_IS_ENABLED
306 Py_RETURN_TRUE;
307 #else
308 Py_RETURN_FALSE;
309 #endif
312 static PyObject *py_is_rust_built(PyObject *self,
313 PyObject *Py_UNUSED(ignored))
315 #ifdef HAVE_RUST
316 Py_RETURN_TRUE;
317 #else
318 Py_RETURN_FALSE;
319 #endif
322 static PyObject *py_is_selftest_enabled(PyObject *self,
323 PyObject *Py_UNUSED(ignored))
325 #ifdef ENABLE_SELFTEST
326 Py_RETURN_TRUE;
327 #else
328 Py_RETURN_FALSE;
329 #endif
332 static PyObject *py_ndr_token_max_list_size(PyObject *self,
333 PyObject *Py_UNUSED(ignored))
335 return PyLong_FromLong(ndr_token_max_list_size());
339 return the list of interface IPs we have configured
340 takes an loadparm context, returns a list of IPs in string form
342 Does not return addresses on 127.0.0.0/8
344 static PyObject *py_interface_ips(PyObject *self, PyObject *args)
346 PyObject *pylist;
347 int count;
348 TALLOC_CTX *tmp_ctx;
349 PyObject *py_lp_ctx;
350 struct loadparm_context *lp_ctx;
351 struct interface *ifaces;
352 int i, ifcount;
353 int all_interfaces = 1;
355 if (!PyArg_ParseTuple(args, "O|i", &py_lp_ctx, &all_interfaces))
356 return NULL;
358 tmp_ctx = talloc_new(NULL);
359 if (tmp_ctx == NULL) {
360 PyErr_NoMemory();
361 return NULL;
364 lp_ctx = lpcfg_from_py_object(tmp_ctx, py_lp_ctx);
365 if (lp_ctx == NULL) {
366 talloc_free(tmp_ctx);
367 return PyErr_NoMemory();
370 load_interface_list(tmp_ctx, lp_ctx, &ifaces);
372 count = iface_list_count(ifaces);
374 /* first count how many are not loopback addresses */
375 for (ifcount = i = 0; i<count; i++) {
376 const char *ip = iface_list_n_ip(ifaces, i);
378 if (all_interfaces) {
379 ifcount++;
380 continue;
383 if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
384 continue;
387 if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
388 continue;
391 if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
392 continue;
395 if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
396 continue;
399 ifcount++;
402 pylist = PyList_New(ifcount);
403 for (ifcount = i = 0; i<count; i++) {
404 const char *ip = iface_list_n_ip(ifaces, i);
406 if (all_interfaces) {
407 PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
408 ifcount++;
409 continue;
412 if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
413 continue;
416 if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
417 continue;
420 if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
421 continue;
424 if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
425 continue;
428 PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
429 ifcount++;
431 talloc_free(tmp_ctx);
432 return pylist;
435 static PyObject *py_strcasecmp_m(PyObject *self, PyObject *args)
437 char *s1 = NULL;
438 char *s2 = NULL;
439 long cmp_result = 0;
440 if (!PyArg_ParseTuple(args, PYARG_STR_UNI
441 PYARG_STR_UNI,
442 "utf8", &s1, "utf8", &s2)) {
443 return NULL;
446 cmp_result = strcasecmp_m(s1, s2);
447 PyMem_Free(s1);
448 PyMem_Free(s2);
449 return PyLong_FromLong(cmp_result);
452 static PyObject *py_strstr_m(PyObject *self, PyObject *args)
454 char *s1 = NULL;
455 char *s2 = NULL;
456 char *strstr_ret = NULL;
457 PyObject *result = NULL;
458 if (!PyArg_ParseTuple(args, PYARG_STR_UNI
459 PYARG_STR_UNI,
460 "utf8", &s1, "utf8", &s2))
461 return NULL;
463 strstr_ret = strstr_m(s1, s2);
464 if (!strstr_ret) {
465 PyMem_Free(s1);
466 PyMem_Free(s2);
467 Py_RETURN_NONE;
469 result = PyUnicode_FromString(strstr_ret);
470 PyMem_Free(s1);
471 PyMem_Free(s2);
472 return result;
475 static PyObject *py_get_burnt_commandline(PyObject *self, PyObject *args)
477 PyObject *cmdline_as_list, *ret;
478 char *burnt_cmdline = NULL;
479 Py_ssize_t i, argc;
480 char **argv = NULL;
481 TALLOC_CTX *frame = talloc_stackframe();
482 bool burnt;
484 if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &cmdline_as_list))
486 TALLOC_FREE(frame);
487 return NULL;
490 argc = PyList_GET_SIZE(cmdline_as_list);
492 if (argc == 0) {
493 TALLOC_FREE(frame);
494 Py_RETURN_NONE;
497 argv = PyList_AsStringList(frame, cmdline_as_list, "sys.argv");
498 if (argv == NULL) {
499 TALLOC_FREE(frame);
500 return NULL;
503 burnt = samba_cmdline_burn(argc, argv);
504 if (!burnt) {
505 TALLOC_FREE(frame);
506 Py_RETURN_NONE;
509 for (i = 0; i < argc; i++) {
510 if (i == 0) {
511 burnt_cmdline = talloc_strdup(frame,
512 argv[i]);
513 } else {
514 burnt_cmdline
515 = talloc_asprintf_append(burnt_cmdline,
516 " %s",
517 argv[i]);
519 if (burnt_cmdline == NULL) {
520 PyErr_NoMemory();
521 TALLOC_FREE(frame);
522 return NULL;
526 ret = PyUnicode_FromString(burnt_cmdline);
527 TALLOC_FREE(frame);
529 return ret;
532 static PyMethodDef py_misc_methods[] = {
533 { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
534 "generate_random_str(len) -> string\n"
535 "Generate random string with specified length." },
536 { "generate_random_password", (PyCFunction)py_generate_random_password,
537 METH_VARARGS, "generate_random_password(min, max) -> string\n"
538 "Generate random password (based on printable ascii characters) "
539 "with a length >= min and <= max." },
540 { "generate_random_machine_password", (PyCFunction)py_generate_random_machine_password,
541 METH_VARARGS, "generate_random_machine_password(min, max) -> string\n"
542 "Generate random password "
543 "(based on random utf16 characters converted to utf8 or "
544 "random ascii characters if 'unix charset' is not 'utf8') "
545 "with a length >= min (at least 14) and <= max (at most 255)." },
546 { "check_password_quality", (PyCFunction)py_check_password_quality,
547 METH_VARARGS, "check_password_quality(pass) -> bool\n"
548 "Check password quality against Samba's check_password_quality, "
549 "the implementation of Microsoft's rules: "
550 "http://msdn.microsoft.com/en-us/subscriptions/cc786468%28v=ws.10%29.aspx"
552 { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
553 "unix2nttime(timestamp) -> nttime" },
554 { "nttime2unix", (PyCFunction)py_nttime2unix, METH_VARARGS,
555 "nttime2unix(nttime) -> timestamp" },
556 { "float2nttime", (PyCFunction)py_float2nttime, METH_VARARGS,
557 "pytime2nttime(floattimestamp) -> nttime" },
558 { "nttime2float", (PyCFunction)py_nttime2float, METH_VARARGS,
559 "nttime2pytime(nttime) -> floattimestamp" },
560 { "nttime2string", (PyCFunction)py_nttime2string, METH_VARARGS,
561 "nttime2string(nttime) -> string" },
562 { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
563 "set debug level" },
564 { "get_debug_level", (PyCFunction)py_get_debug_level, METH_NOARGS,
565 "get debug level" },
566 { "fault_setup", (PyCFunction)py_fault_setup, METH_NOARGS,
567 "setup the default samba panic handler" },
568 { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS,
569 "interface_ips(lp_ctx[, all_interfaces) -> list_of_ifaces\n"
570 "\n"
571 "get interface IP address list"},
572 { "strcasecmp_m", (PyCFunction)py_strcasecmp_m, METH_VARARGS,
573 "(for testing) compare two strings using Samba's strcasecmp_m()"},
574 { "strstr_m", (PyCFunction)py_strstr_m, METH_VARARGS,
575 "(for testing) find one string in another with Samba's strstr_m()"},
576 { "is_ntvfs_fileserver_built", (PyCFunction)py_is_ntvfs_fileserver_built, METH_NOARGS,
577 "is the NTVFS file server built in this installation?" },
578 { "is_heimdal_built", (PyCFunction)py_is_heimdal_built, METH_NOARGS,
579 "is Samba built with Heimdal Kerberos?" },
580 { "generate_random_bytes",
581 (PyCFunction)py_generate_random_bytes,
582 METH_VARARGS,
583 "generate_random_bytes(len) -> bytes\n"
584 "Generate random bytes with specified length." },
585 { "is_ad_dc_built", (PyCFunction)py_is_ad_dc_built, METH_NOARGS,
586 "is Samba built with AD DC?" },
587 { "is_selftest_enabled", (PyCFunction)py_is_selftest_enabled,
588 METH_NOARGS, "is Samba built with selftest enabled?" },
589 { "ndr_token_max_list_size", (PyCFunction)py_ndr_token_max_list_size,
590 METH_NOARGS, "How many NDR internal tokens is too many for this build?" },
591 { "get_burnt_commandline", (PyCFunction)py_get_burnt_commandline,
592 METH_VARARGS, "Return a redacted commandline to feed to setproctitle (None if no redaction required)" },
593 { "is_rust_built", (PyCFunction)py_is_rust_built, METH_NOARGS,
594 "is Samba built with Rust?" },
598 static struct PyModuleDef moduledef = {
599 PyModuleDef_HEAD_INIT,
600 .m_name = "_glue",
601 .m_doc = "Python bindings for miscellaneous Samba functions.",
602 .m_size = -1,
603 .m_methods = py_misc_methods,
606 MODULE_INIT_FUNC(_glue)
608 PyObject *m;
609 PyObject *py_obj = NULL;
610 int ret;
612 debug_setup_talloc_log();
614 m = PyModule_Create(&moduledef);
615 if (m == NULL)
616 return NULL;
618 PyModule_AddObject(m, "version",
619 PyUnicode_FromString(SAMBA_VERSION_STRING));
620 py_obj = PyErr_NewException("samba.NTSTATUSError", PyExc_RuntimeError, NULL);
621 if (py_obj != NULL) {
622 PyModule_AddObject(m, "NTSTATUSError", py_obj);
625 py_obj = PyErr_NewException("samba.WERRORError", PyExc_RuntimeError, NULL);
626 if (py_obj != NULL) {
627 PyModule_AddObject(m, "WERRORError", py_obj);
630 py_obj = PyErr_NewException("samba.HRESULTError", PyExc_RuntimeError, NULL);
631 if (py_obj != NULL) {
632 PyModule_AddObject(m, "HRESULTError", py_obj);
635 py_obj = PyErr_NewException("samba.DsExtendedError", PyExc_RuntimeError, NULL);
636 if (py_obj != NULL) {
637 PyModule_AddObject(m, "DsExtendedError", py_obj);
640 ret = PyModule_AddIntConstant(m, "GKDI_L1_KEY_ITERATION", gkdi_l1_key_iteration);
641 if (ret) {
642 Py_DECREF(m);
643 return NULL;
645 ret = PyModule_AddIntConstant(m, "GKDI_L2_KEY_ITERATION", gkdi_l2_key_iteration);
646 if (ret) {
647 Py_DECREF(m);
648 return NULL;
650 py_obj = PyLong_FromLongLong(gkdi_key_cycle_duration);
651 if (py_obj == NULL) {
652 Py_DECREF(m);
653 return NULL;
655 ret = PyModule_AddObject(m, "GKDI_KEY_CYCLE_DURATION", py_obj);
656 if (ret) {
657 Py_DECREF(py_obj);
658 Py_DECREF(m);
659 return NULL;
661 py_obj = PyLong_FromLongLong(gkdi_max_clock_skew);
662 if (py_obj == NULL) {
663 Py_DECREF(m);
664 return NULL;
666 ret = PyModule_AddObject(m, "GKDI_MAX_CLOCK_SKEW", py_obj);
667 if (ret) {
668 Py_DECREF(py_obj);
669 Py_DECREF(m);
670 return NULL;
673 return m;