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