libsmb: Avoid an "else", we return in the "true" branch
[samba4-gss.git] / python / pyglue.c
blob042bf9e14f32937d7641e2ef046f1dd311b7681e
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_selftest_enabled(PyObject *self,
313 PyObject *Py_UNUSED(ignored))
315 #ifdef ENABLE_SELFTEST
316 Py_RETURN_TRUE;
317 #else
318 Py_RETURN_FALSE;
319 #endif
322 static PyObject *py_ndr_token_max_list_size(PyObject *self,
323 PyObject *Py_UNUSED(ignored))
325 return PyLong_FromLong(ndr_token_max_list_size());
329 return the list of interface IPs we have configured
330 takes an loadparm context, returns a list of IPs in string form
332 Does not return addresses on 127.0.0.0/8
334 static PyObject *py_interface_ips(PyObject *self, PyObject *args)
336 PyObject *pylist;
337 int count;
338 TALLOC_CTX *tmp_ctx;
339 PyObject *py_lp_ctx;
340 struct loadparm_context *lp_ctx;
341 struct interface *ifaces;
342 int i, ifcount;
343 int all_interfaces = 1;
345 if (!PyArg_ParseTuple(args, "O|i", &py_lp_ctx, &all_interfaces))
346 return NULL;
348 tmp_ctx = talloc_new(NULL);
349 if (tmp_ctx == NULL) {
350 PyErr_NoMemory();
351 return NULL;
354 lp_ctx = lpcfg_from_py_object(tmp_ctx, py_lp_ctx);
355 if (lp_ctx == NULL) {
356 talloc_free(tmp_ctx);
357 return PyErr_NoMemory();
360 load_interface_list(tmp_ctx, lp_ctx, &ifaces);
362 count = iface_list_count(ifaces);
364 /* first count how many are not loopback addresses */
365 for (ifcount = i = 0; i<count; i++) {
366 const char *ip = iface_list_n_ip(ifaces, i);
368 if (all_interfaces) {
369 ifcount++;
370 continue;
373 if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
374 continue;
377 if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
378 continue;
381 if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
382 continue;
385 if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
386 continue;
389 ifcount++;
392 pylist = PyList_New(ifcount);
393 for (ifcount = i = 0; i<count; i++) {
394 const char *ip = iface_list_n_ip(ifaces, i);
396 if (all_interfaces) {
397 PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
398 ifcount++;
399 continue;
402 if (iface_list_same_net(ip, "127.0.0.1", "255.0.0.0")) {
403 continue;
406 if (iface_list_same_net(ip, "169.254.0.0", "255.255.0.0")) {
407 continue;
410 if (iface_list_same_net(ip, "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")) {
411 continue;
414 if (iface_list_same_net(ip, "fe80::", "ffff:ffff:ffff:ffff::")) {
415 continue;
418 PyList_SetItem(pylist, ifcount, PyUnicode_FromString(ip));
419 ifcount++;
421 talloc_free(tmp_ctx);
422 return pylist;
425 static PyObject *py_strcasecmp_m(PyObject *self, PyObject *args)
427 char *s1 = NULL;
428 char *s2 = NULL;
429 long cmp_result = 0;
430 if (!PyArg_ParseTuple(args, PYARG_STR_UNI
431 PYARG_STR_UNI,
432 "utf8", &s1, "utf8", &s2)) {
433 return NULL;
436 cmp_result = strcasecmp_m(s1, s2);
437 PyMem_Free(s1);
438 PyMem_Free(s2);
439 return PyLong_FromLong(cmp_result);
442 static PyObject *py_strstr_m(PyObject *self, PyObject *args)
444 char *s1 = NULL;
445 char *s2 = NULL;
446 char *strstr_ret = NULL;
447 PyObject *result = NULL;
448 if (!PyArg_ParseTuple(args, PYARG_STR_UNI
449 PYARG_STR_UNI,
450 "utf8", &s1, "utf8", &s2))
451 return NULL;
453 strstr_ret = strstr_m(s1, s2);
454 if (!strstr_ret) {
455 PyMem_Free(s1);
456 PyMem_Free(s2);
457 Py_RETURN_NONE;
459 result = PyUnicode_FromString(strstr_ret);
460 PyMem_Free(s1);
461 PyMem_Free(s2);
462 return result;
465 static PyObject *py_get_burnt_commandline(PyObject *self, PyObject *args)
467 PyObject *cmdline_as_list, *ret;
468 char *burnt_cmdline = NULL;
469 Py_ssize_t i, argc;
470 char **argv = NULL;
471 TALLOC_CTX *frame = talloc_stackframe();
472 bool burnt;
474 if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &cmdline_as_list))
476 TALLOC_FREE(frame);
477 return NULL;
480 argc = PyList_GET_SIZE(cmdline_as_list);
482 if (argc == 0) {
483 TALLOC_FREE(frame);
484 Py_RETURN_NONE;
487 argv = PyList_AsStringList(frame, cmdline_as_list, "sys.argv");
488 if (argv == NULL) {
489 TALLOC_FREE(frame);
490 return NULL;
493 burnt = samba_cmdline_burn(argc, argv);
494 if (!burnt) {
495 TALLOC_FREE(frame);
496 Py_RETURN_NONE;
499 for (i = 0; i < argc; i++) {
500 if (i == 0) {
501 burnt_cmdline = talloc_strdup(frame,
502 argv[i]);
503 } else {
504 burnt_cmdline
505 = talloc_asprintf_append(burnt_cmdline,
506 " %s",
507 argv[i]);
509 if (burnt_cmdline == NULL) {
510 PyErr_NoMemory();
511 TALLOC_FREE(frame);
512 return NULL;
516 ret = PyUnicode_FromString(burnt_cmdline);
517 TALLOC_FREE(frame);
519 return ret;
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"
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 Kerberos?" },
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)" },
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,
594 MODULE_INIT_FUNC(_glue)
596 PyObject *m;
597 PyObject *py_obj = NULL;
598 int ret;
600 debug_setup_talloc_log();
602 m = PyModule_Create(&moduledef);
603 if (m == NULL)
604 return NULL;
606 PyModule_AddObject(m, "version",
607 PyUnicode_FromString(SAMBA_VERSION_STRING));
608 py_obj = PyErr_NewException("samba.NTSTATUSError", PyExc_RuntimeError, NULL);
609 if (py_obj != NULL) {
610 PyModule_AddObject(m, "NTSTATUSError", py_obj);
613 py_obj = PyErr_NewException("samba.WERRORError", PyExc_RuntimeError, NULL);
614 if (py_obj != NULL) {
615 PyModule_AddObject(m, "WERRORError", py_obj);
618 py_obj = PyErr_NewException("samba.HRESULTError", PyExc_RuntimeError, NULL);
619 if (py_obj != NULL) {
620 PyModule_AddObject(m, "HRESULTError", py_obj);
623 py_obj = PyErr_NewException("samba.DsExtendedError", PyExc_RuntimeError, NULL);
624 if (py_obj != NULL) {
625 PyModule_AddObject(m, "DsExtendedError", py_obj);
628 ret = PyModule_AddIntConstant(m, "GKDI_L1_KEY_ITERATION", gkdi_l1_key_iteration);
629 if (ret) {
630 Py_DECREF(m);
631 return NULL;
633 ret = PyModule_AddIntConstant(m, "GKDI_L2_KEY_ITERATION", gkdi_l2_key_iteration);
634 if (ret) {
635 Py_DECREF(m);
636 return NULL;
638 py_obj = PyLong_FromLongLong(gkdi_key_cycle_duration);
639 if (py_obj == NULL) {
640 Py_DECREF(m);
641 return NULL;
643 ret = PyModule_AddObject(m, "GKDI_KEY_CYCLE_DURATION", py_obj);
644 if (ret) {
645 Py_DECREF(py_obj);
646 Py_DECREF(m);
647 return NULL;
649 py_obj = PyLong_FromLongLong(gkdi_max_clock_skew);
650 if (py_obj == NULL) {
651 Py_DECREF(m);
652 return NULL;
654 ret = PyModule_AddObject(m, "GKDI_MAX_CLOCK_SKEW", py_obj);
655 if (ret) {
656 Py_DECREF(py_obj);
657 Py_DECREF(m);
658 return NULL;
661 return m;