s4-python: Move set_opaque_integer -> dsdb.
[metze/samba/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_credentials(PyObject *self, PyObject *args)
142 {
143         PyObject *py_creds, *py_ldb;
144         struct cli_credentials *creds;
145         struct ldb_context *ldb;
146         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_creds))
147                 return NULL;
148
149         PyErr_LDB_OR_RAISE(py_ldb, ldb);
150         
151         creds = cli_credentials_from_py_object(py_creds);
152         if (creds == NULL) {
153                 PyErr_SetString(PyExc_TypeError, "Expected credentials object");
154                 return NULL;
155         }
156
157         ldb_set_opaque(ldb, "credentials", creds);
158
159         Py_RETURN_NONE;
160 }
161
162 static PyObject *py_ldb_set_loadparm(PyObject *self, PyObject *args)
163 {
164         PyObject *py_lp_ctx, *py_ldb;
165         struct loadparm_context *lp_ctx;
166         struct ldb_context *ldb;
167         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_lp_ctx))
168                 return NULL;
169
170         PyErr_LDB_OR_RAISE(py_ldb, ldb);
171
172         lp_ctx = lp_from_py_object(py_lp_ctx);
173         if (lp_ctx == NULL) {
174                 PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
175                 return NULL;
176         }
177
178         ldb_set_opaque(ldb, "loadparm", lp_ctx);
179
180         Py_RETURN_NONE;
181 }
182
183 static PyObject *py_ldb_set_utf8_casefold(PyObject *self, PyObject *args)
184 {
185         PyObject *py_ldb;
186         struct ldb_context *ldb;
187
188         if (!PyArg_ParseTuple(args, "O", &py_ldb))
189                 return NULL;
190
191         PyErr_LDB_OR_RAISE(py_ldb, ldb);
192
193         ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
194
195         Py_RETURN_NONE;
196 }
197
198 static PyObject *py_samdb_set_domain_sid(PyLdbObject *self, PyObject *args)
199
200         PyObject *py_ldb, *py_sid;
201         struct ldb_context *ldb;
202         struct dom_sid *sid;
203         bool ret;
204
205         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_sid))
206                 return NULL;
207         
208         PyErr_LDB_OR_RAISE(py_ldb, ldb);
209
210         sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
211
212         ret = samdb_set_domain_sid(ldb, sid);
213         if (!ret) {
214                 PyErr_SetString(PyExc_RuntimeError, "set_domain_sid failed");
215                 return NULL;
216         } 
217         Py_RETURN_NONE;
218 }
219
220 static PyObject *py_samdb_get_domain_sid(PyLdbObject *self, PyObject *args)
221
222         PyObject *py_ldb;
223         struct ldb_context *ldb;
224         const struct dom_sid *sid;
225         PyObject *ret;
226         char *retstr;
227
228         if (!PyArg_ParseTuple(args, "O", &py_ldb))
229                 return NULL;
230         
231         PyErr_LDB_OR_RAISE(py_ldb, ldb);
232
233         sid = samdb_domain_sid(ldb);
234         if (!sid) {
235                 PyErr_SetString(PyExc_RuntimeError, "samdb_domain_sid failed");
236                 return NULL;
237         } 
238         retstr = dom_sid_string(NULL, sid);
239         ret = PyString_FromString(retstr);
240         talloc_free(retstr);
241         return ret;
242 }
243
244 static PyObject *py_ldb_register_samba_handlers(PyObject *self, PyObject *args)
245 {
246         PyObject *py_ldb;
247         struct ldb_context *ldb;
248         int ret;
249
250         if (!PyArg_ParseTuple(args, "O", &py_ldb))
251                 return NULL;
252
253         PyErr_LDB_OR_RAISE(py_ldb, ldb);
254         ret = ldb_register_samba_handlers(ldb);
255
256         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
257         Py_RETURN_NONE;
258 }
259
260 static PyObject *py_dsdb_set_ntds_invocation_id(PyObject *self, PyObject *args)
261 {
262         PyObject *py_ldb, *py_guid;
263         bool ret;
264         struct GUID guid;
265         struct ldb_context *ldb;
266         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_guid))
267                 return NULL;
268
269         PyErr_LDB_OR_RAISE(py_ldb, ldb);
270         GUID_from_string(PyString_AsString(py_guid), &guid);
271
272         ret = samdb_set_ntds_invocation_id(ldb, &guid);
273         if (!ret) {
274                 PyErr_SetString(PyExc_RuntimeError, "set_ntds_invocation_id failed");
275                 return NULL;
276         }
277         Py_RETURN_NONE;
278 }
279
280 static PyObject *py_dsdb_set_global_schema(PyObject *self, PyObject *args)
281 {
282         PyObject *py_ldb;
283         struct ldb_context *ldb;
284         int ret;
285         if (!PyArg_ParseTuple(args, "O", &py_ldb))
286                 return NULL;
287
288         PyErr_LDB_OR_RAISE(py_ldb, ldb);
289
290         ret = dsdb_set_global_schema(ldb);
291         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
292
293         Py_RETURN_NONE;
294 }
295
296 static PyObject *py_dsdb_set_schema_from_ldif(PyObject *self, PyObject *args)
297 {
298         WERROR result;
299         char *pf, *df;
300         PyObject *py_ldb;
301         struct ldb_context *ldb;
302
303         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &pf, &df))
304                 return NULL;
305
306         PyErr_LDB_OR_RAISE(py_ldb, ldb);
307
308         result = dsdb_set_schema_from_ldif(ldb, pf, df);
309         PyErr_WERROR_IS_ERR_RAISE(result);
310
311         Py_RETURN_NONE;
312 }
313
314 static PyObject *py_dsdb_convert_schema_to_openldap(PyObject *self, PyObject *args)
315 {
316         char *target_str, *mapping;
317         PyObject *py_ldb;
318         struct ldb_context *ldb;
319         PyObject *ret;
320         char *retstr;
321
322         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &target_str, &mapping))
323                 return NULL;
324
325         PyErr_LDB_OR_RAISE(py_ldb, ldb);
326
327         retstr = dsdb_convert_schema_to_openldap(ldb, target_str, mapping);
328         if (!retstr) {
329                 PyErr_SetString(PyExc_RuntimeError, "dsdb_convert_schema_to_openldap failed");
330                 return NULL;
331         } 
332         ret = PyString_FromString(retstr);
333         talloc_free(retstr);
334         return ret;
335 }
336
337 static PyObject *py_dsdb_write_prefixes_from_schema_to_ldb(PyObject *self, PyObject *args)
338 {
339         PyObject *py_ldb;
340         struct ldb_context *ldb;
341         WERROR result;
342         struct dsdb_schema *schema;
343
344         if (!PyArg_ParseTuple(args, "O", &py_ldb))
345                 return NULL;
346
347         PyErr_LDB_OR_RAISE(py_ldb, ldb);
348
349         schema = dsdb_get_schema(ldb, NULL);
350         if (!schema) {
351                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on ldb!\n");
352                 return NULL;
353         }
354
355         result = dsdb_write_prefixes_from_schema_to_ldb(NULL, ldb, schema);
356         PyErr_WERROR_IS_ERR_RAISE(result);
357
358         Py_RETURN_NONE;
359 }
360
361 static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args)
362 {
363         PyObject *py_ldb;
364         struct ldb_context *ldb;
365         PyObject *py_from_ldb;
366         struct ldb_context *from_ldb;
367         struct dsdb_schema *schema;
368         int ret;
369         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_from_ldb))
370                 return NULL;
371
372         PyErr_LDB_OR_RAISE(py_ldb, ldb);
373
374         PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb);
375
376         schema = dsdb_get_schema(from_ldb, NULL);
377         if (!schema) {
378                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n");
379                 return NULL;
380         }
381
382         ret = dsdb_reference_schema(ldb, schema, true);
383         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
384
385         Py_RETURN_NONE;
386 }
387
388 static PyObject *py_dsdb_load_partition_usn(PyObject *self, PyObject *args)
389 {
390         PyObject *py_dn, *py_ldb, *result;
391         struct ldb_dn *dn;
392         uint64_t highest_uSN, urgent_uSN;
393         struct ldb_context *ldb;
394         TALLOC_CTX *mem_ctx;
395         int ret;
396
397         mem_ctx = talloc_new(NULL);
398         if (mem_ctx == NULL) {
399            PyErr_NoMemory();
400            return NULL;
401         }
402
403         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dn)) {
404            talloc_free(mem_ctx);
405            return NULL;
406         }
407
408         PyErr_LDB_OR_RAISE(py_ldb, ldb);
409
410         if (!PyObject_AsDn(mem_ctx, py_dn, ldb, &dn)) {
411            talloc_free(mem_ctx);
412            return NULL;
413         }
414
415         ret = dsdb_load_partition_usn(ldb, dn, &highest_uSN, &urgent_uSN);
416         if (ret != LDB_SUCCESS) {
417            char *errstr = talloc_asprintf(mem_ctx, "Failed to load partition uSN - %s", ldb_errstring(ldb));
418            PyErr_SetString(PyExc_RuntimeError, errstr);
419            talloc_free(mem_ctx);
420            return NULL;
421         }
422
423         talloc_free(mem_ctx);
424
425         result = PyDict_New();
426
427         PyDict_SetItemString(result, "uSNHighest", PyInt_FromLong((uint64_t)highest_uSN));
428         PyDict_SetItemString(result, "uSNUrgent", PyInt_FromLong((uint64_t)urgent_uSN));
429
430
431         return result;
432 }
433
434 static PyObject *py_samdb_ntds_invocation_id(PyObject *self, PyObject *args)
435 {
436         PyObject *py_ldb, *result;
437         struct ldb_context *ldb;
438         TALLOC_CTX *mem_ctx;
439         const struct GUID *guid;
440
441         mem_ctx = talloc_new(NULL);
442         if (mem_ctx == NULL) {
443                 PyErr_NoMemory();
444                 return NULL;
445         }
446
447         if (!PyArg_ParseTuple(args, "O", &py_ldb)) {
448                 talloc_free(mem_ctx);
449                 return NULL;
450         }
451
452         PyErr_LDB_OR_RAISE(py_ldb, ldb);
453
454         guid = samdb_ntds_invocation_id(ldb);
455         if (guid == NULL) {
456                 PyErr_SetString(PyExc_RuntimeError, "Failed to find NTDS invocation ID");
457                 talloc_free(mem_ctx);
458                 return NULL;
459         }
460
461         result = PyString_FromString(GUID_string(mem_ctx, guid));
462         talloc_free(mem_ctx);
463         return result;
464 }
465
466
467 static PyObject *py_samdb_ntds_objectGUID(PyObject *self, PyObject *args)
468 {
469         PyObject *py_ldb, *result;
470         struct ldb_context *ldb;
471         TALLOC_CTX *mem_ctx;
472         const struct GUID *guid;
473
474         mem_ctx = talloc_new(NULL);
475         if (mem_ctx == NULL) {
476                 PyErr_NoMemory();
477                 return NULL;
478         }
479
480         if (!PyArg_ParseTuple(args, "O", &py_ldb)) {
481                 talloc_free(mem_ctx);
482                 return NULL;
483         }
484
485         PyErr_LDB_OR_RAISE(py_ldb, ldb);
486
487         guid = samdb_ntds_objectGUID(ldb);
488         if (guid == NULL) {
489                 PyErr_SetString(PyExc_RuntimeError, "Failed to find NTDS GUID");
490                 talloc_free(mem_ctx);
491                 return NULL;
492         }
493
494         result = PyString_FromString(GUID_string(mem_ctx, guid));
495         talloc_free(mem_ctx);
496         return result;
497 }
498
499
500 /*
501   return the list of interface IPs we have configured
502   takes an loadparm context, returns a list of IPs in string form
503
504   Does not return addresses on 127.0.0.0/8
505  */
506 static PyObject *py_interface_ips(PyObject *self, PyObject *args)
507 {
508         PyObject *pylist;
509         int count;
510         TALLOC_CTX *tmp_ctx;
511         PyObject *py_lp_ctx;
512         struct loadparm_context *lp_ctx;
513         struct interface *ifaces;
514         int i, ifcount;
515         int all_interfaces;
516
517         if (!PyArg_ParseTuple(args, "Oi", &py_lp_ctx, &all_interfaces))
518                 return NULL;
519
520         lp_ctx = lp_from_py_object(py_lp_ctx);
521         if (lp_ctx == NULL) {
522                 PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
523                 return NULL;
524         }
525
526         tmp_ctx = talloc_new(NULL);
527
528         load_interfaces(tmp_ctx, lp_interfaces(lp_ctx), &ifaces);
529
530         count = iface_count(ifaces);
531
532         /* first count how many are not loopback addresses */
533         for (ifcount = i = 0; i<count; i++) {
534                 const char *ip = iface_n_ip(ifaces, i);
535                 if (!(!all_interfaces && iface_same_net(ip, "127.0.0.1", "255.0.0.0"))) {
536                         ifcount++;
537                 }
538         }
539
540         pylist = PyList_New(ifcount);
541         for (ifcount = i = 0; i<count; i++) {
542                 const char *ip = iface_n_ip(ifaces, i);
543                 if (!(!all_interfaces && iface_same_net(ip, "127.0.0.1", "255.0.0.0"))) {
544                         PyList_SetItem(pylist, ifcount, PyString_FromString(ip));
545                         ifcount++;
546                 }
547         }
548         talloc_free(tmp_ctx);
549         return pylist;
550 }
551
552
553 static PyMethodDef py_misc_methods[] = {
554         { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
555                 "generate_random_str(len) -> string\n"
556                 "Generate random string with specified length." },
557         { "generate_random_password", (PyCFunction)py_generate_random_password, METH_VARARGS,
558                 "generate_random_password(min, max) -> string\n"
559                 "Generate random password with a length >= min and <= max." },
560         { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
561                 "unix2nttime(timestamp) -> nttime" },
562         { "ldb_set_session_info", (PyCFunction)py_ldb_set_session_info, METH_VARARGS,
563                 "ldb_set_session_info(ldb, session_info)\n"
564                 "Set session info to use when connecting." },
565         { "ldb_set_credentials", (PyCFunction)py_ldb_set_credentials, METH_VARARGS,
566                 "ldb_set_credentials(ldb, credentials)\n"
567                 "Set credentials to use when connecting." },
568         { "ldb_set_loadparm", (PyCFunction)py_ldb_set_loadparm, METH_VARARGS,
569                 "ldb_set_loadparm(ldb, session_info)\n"
570                 "Set loadparm context to use when connecting." },
571         { "samdb_set_domain_sid", (PyCFunction)py_samdb_set_domain_sid, METH_VARARGS,
572                 "samdb_set_domain_sid(samdb, sid)\n"
573                 "Set SID of domain to use." },
574         { "samdb_get_domain_sid", (PyCFunction)py_samdb_get_domain_sid, METH_VARARGS,
575                 "samdb_get_domain_sid(samdb)\n"
576                 "Get SID of domain in use." },
577         { "ldb_register_samba_handlers", (PyCFunction)py_ldb_register_samba_handlers, METH_VARARGS,
578                 "ldb_register_samba_handlers(ldb)\n"
579                 "Register Samba-specific LDB modules and schemas." },
580         { "ldb_set_utf8_casefold", (PyCFunction)py_ldb_set_utf8_casefold, METH_VARARGS,
581                 "ldb_set_utf8_casefold(ldb)\n"
582                 "Set the right Samba casefolding function for UTF8 charset." },
583         { "dsdb_set_ntds_invocation_id", (PyCFunction)py_dsdb_set_ntds_invocation_id, METH_VARARGS,
584                 NULL },
585         { "dsdb_set_global_schema", (PyCFunction)py_dsdb_set_global_schema, METH_VARARGS,
586                 NULL },
587         { "dsdb_set_schema_from_ldif", (PyCFunction)py_dsdb_set_schema_from_ldif, METH_VARARGS,
588                 NULL },
589         { "dsdb_write_prefixes_from_schema_to_ldb", (PyCFunction)py_dsdb_write_prefixes_from_schema_to_ldb, METH_VARARGS,
590                 NULL },
591         { "dsdb_set_schema_from_ldb", (PyCFunction)py_dsdb_set_schema_from_ldb, METH_VARARGS,
592                 NULL },
593         { "dsdb_convert_schema_to_openldap", (PyCFunction)py_dsdb_convert_schema_to_openldap, METH_VARARGS,
594                 NULL },
595         { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
596                 "set debug level" },
597         { "dsdb_load_partition_usn", (PyCFunction)py_dsdb_load_partition_usn, METH_VARARGS,
598                 "get uSNHighest and uSNUrgent from the partition @REPLCHANGED"},
599         { "samdb_ntds_invocation_id", (PyCFunction)py_samdb_ntds_invocation_id, METH_VARARGS,
600                 "get the NTDS invocation ID GUID as a string"},
601         { "samdb_ntds_objectGUID", (PyCFunction)py_samdb_ntds_objectGUID, METH_VARARGS,
602                 "get the NTDS objectGUID as a string"},
603         { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS,
604                 "get interface IP address list"},
605         { NULL }
606 };
607
608 void initglue(void)
609 {
610         PyObject *m;
611
612         debug_setup_talloc_log();
613
614         m = Py_InitModule3("glue", py_misc_methods, 
615                            "Python bindings for miscellaneous Samba functions.");
616         if (m == NULL)
617                 return;
618
619         PyModule_AddObject(m, "version", PyString_FromString(SAMBA_VERSION_STRING));
620
621         /* one of the most annoying things about python scripts is
622            that they don't die when you hit control-C. This fixes that
623            sillyness. As we do all database operations using
624            transactions, this is also safe. In fact, not dying
625            immediately is unsafe as we could end up treating the
626            control-C exception as a different error and try to modify
627            as database incorrectly 
628         */
629         signal(SIGINT, SIG_DFL);
630 }
631