s4-python: Move set_global_schema to pydsdb.
[idra/samba.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_dsdb_set_schema_from_ldif(PyObject *self, PyObject *args)
121 {
122         WERROR result;
123         char *pf, *df;
124         PyObject *py_ldb;
125         struct ldb_context *ldb;
126
127         if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &pf, &df))
128                 return NULL;
129
130         PyErr_LDB_OR_RAISE(py_ldb, ldb);
131
132         result = dsdb_set_schema_from_ldif(ldb, pf, df);
133         PyErr_WERROR_IS_ERR_RAISE(result);
134
135         Py_RETURN_NONE;
136 }
137
138 static PyObject *py_dsdb_write_prefixes_from_schema_to_ldb(PyObject *self, PyObject *args)
139 {
140         PyObject *py_ldb;
141         struct ldb_context *ldb;
142         WERROR result;
143         struct dsdb_schema *schema;
144
145         if (!PyArg_ParseTuple(args, "O", &py_ldb))
146                 return NULL;
147
148         PyErr_LDB_OR_RAISE(py_ldb, ldb);
149
150         schema = dsdb_get_schema(ldb, NULL);
151         if (!schema) {
152                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on ldb!\n");
153                 return NULL;
154         }
155
156         result = dsdb_write_prefixes_from_schema_to_ldb(NULL, ldb, schema);
157         PyErr_WERROR_IS_ERR_RAISE(result);
158
159         Py_RETURN_NONE;
160 }
161
162 static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args)
163 {
164         PyObject *py_ldb;
165         struct ldb_context *ldb;
166         PyObject *py_from_ldb;
167         struct ldb_context *from_ldb;
168         struct dsdb_schema *schema;
169         int ret;
170         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_from_ldb))
171                 return NULL;
172
173         PyErr_LDB_OR_RAISE(py_ldb, ldb);
174
175         PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb);
176
177         schema = dsdb_get_schema(from_ldb, NULL);
178         if (!schema) {
179                 PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n");
180                 return NULL;
181         }
182
183         ret = dsdb_reference_schema(ldb, schema, true);
184         PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
185
186         Py_RETURN_NONE;
187 }
188
189 static PyObject *py_dsdb_load_partition_usn(PyObject *self, PyObject *args)
190 {
191         PyObject *py_dn, *py_ldb, *result;
192         struct ldb_dn *dn;
193         uint64_t highest_uSN, urgent_uSN;
194         struct ldb_context *ldb;
195         TALLOC_CTX *mem_ctx;
196         int ret;
197
198         mem_ctx = talloc_new(NULL);
199         if (mem_ctx == NULL) {
200            PyErr_NoMemory();
201            return NULL;
202         }
203
204         if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_dn)) {
205            talloc_free(mem_ctx);
206            return NULL;
207         }
208
209         PyErr_LDB_OR_RAISE(py_ldb, ldb);
210
211         if (!PyObject_AsDn(mem_ctx, py_dn, ldb, &dn)) {
212            talloc_free(mem_ctx);
213            return NULL;
214         }
215
216         ret = dsdb_load_partition_usn(ldb, dn, &highest_uSN, &urgent_uSN);
217         if (ret != LDB_SUCCESS) {
218            char *errstr = talloc_asprintf(mem_ctx, "Failed to load partition uSN - %s", ldb_errstring(ldb));
219            PyErr_SetString(PyExc_RuntimeError, errstr);
220            talloc_free(mem_ctx);
221            return NULL;
222         }
223
224         talloc_free(mem_ctx);
225
226         result = PyDict_New();
227
228         PyDict_SetItemString(result, "uSNHighest", PyInt_FromLong((uint64_t)highest_uSN));
229         PyDict_SetItemString(result, "uSNUrgent", PyInt_FromLong((uint64_t)urgent_uSN));
230
231
232         return result;
233 }
234
235 /*
236   return the list of interface IPs we have configured
237   takes an loadparm context, returns a list of IPs in string form
238
239   Does not return addresses on 127.0.0.0/8
240  */
241 static PyObject *py_interface_ips(PyObject *self, PyObject *args)
242 {
243         PyObject *pylist;
244         int count;
245         TALLOC_CTX *tmp_ctx;
246         PyObject *py_lp_ctx;
247         struct loadparm_context *lp_ctx;
248         struct interface *ifaces;
249         int i, ifcount;
250         int all_interfaces;
251
252         if (!PyArg_ParseTuple(args, "Oi", &py_lp_ctx, &all_interfaces))
253                 return NULL;
254
255         lp_ctx = lp_from_py_object(py_lp_ctx);
256         if (lp_ctx == NULL) {
257                 PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
258                 return NULL;
259         }
260
261         tmp_ctx = talloc_new(NULL);
262
263         load_interfaces(tmp_ctx, lp_interfaces(lp_ctx), &ifaces);
264
265         count = iface_count(ifaces);
266
267         /* first count how many are not loopback addresses */
268         for (ifcount = i = 0; i<count; i++) {
269                 const char *ip = iface_n_ip(ifaces, i);
270                 if (!(!all_interfaces && iface_same_net(ip, "127.0.0.1", "255.0.0.0"))) {
271                         ifcount++;
272                 }
273         }
274
275         pylist = PyList_New(ifcount);
276         for (ifcount = i = 0; i<count; i++) {
277                 const char *ip = iface_n_ip(ifaces, i);
278                 if (!(!all_interfaces && iface_same_net(ip, "127.0.0.1", "255.0.0.0"))) {
279                         PyList_SetItem(pylist, ifcount, PyString_FromString(ip));
280                         ifcount++;
281                 }
282         }
283         talloc_free(tmp_ctx);
284         return pylist;
285 }
286
287
288 static PyMethodDef py_misc_methods[] = {
289         { "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
290                 "generate_random_str(len) -> string\n"
291                 "Generate random string with specified length." },
292         { "generate_random_password", (PyCFunction)py_generate_random_password, METH_VARARGS,
293                 "generate_random_password(min, max) -> string\n"
294                 "Generate random password with a length >= min and <= max." },
295         { "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
296                 "unix2nttime(timestamp) -> nttime" },
297         { "dsdb_set_schema_from_ldif", (PyCFunction)py_dsdb_set_schema_from_ldif, METH_VARARGS,
298                 NULL },
299         { "dsdb_write_prefixes_from_schema_to_ldb", (PyCFunction)py_dsdb_write_prefixes_from_schema_to_ldb, METH_VARARGS,
300                 NULL },
301         { "dsdb_set_schema_from_ldb", (PyCFunction)py_dsdb_set_schema_from_ldb, METH_VARARGS,
302                 NULL },
303         { "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
304                 "set debug level" },
305         { "dsdb_load_partition_usn", (PyCFunction)py_dsdb_load_partition_usn, METH_VARARGS,
306                 "get uSNHighest and uSNUrgent from the partition @REPLCHANGED"},
307         { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS,
308                 "get interface IP address list"},
309         { NULL }
310 };
311
312 void initglue(void)
313 {
314         PyObject *m;
315
316         debug_setup_talloc_log();
317
318         m = Py_InitModule3("glue", py_misc_methods, 
319                            "Python bindings for miscellaneous Samba functions.");
320         if (m == NULL)
321                 return;
322
323         PyModule_AddObject(m, "version", PyString_FromString(SAMBA_VERSION_STRING));
324
325         /* one of the most annoying things about python scripts is
326            that they don't die when you hit control-C. This fixes that
327            sillyness. As we do all database operations using
328            transactions, this is also safe. In fact, not dying
329            immediately is unsafe as we could end up treating the
330            control-C exception as a different error and try to modify
331            as database incorrectly 
332         */
333         signal(SIGINT, SIG_DFL);
334 }
335