1/*
2   Unix SMB/CIFS implementation.
3   Samba utility functions
4   Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2009
5   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22#include "auth/auth.h"
23#include "lib/ldb_wrap.h"
24#include "ldb/include/ldb.h"
25#include "ldb_errors.h"
26#include "libcli/raw/libcliraw.h"
27#include "librpc/ndr/libndr.h"
28
29#include "param/param.h"
30#include "param/provision.h"
31#include "param/secrets.h"
32#include <Python.h>
33#include "lib/talloc/pytalloc.h"
34#include "librpc/rpc/pyrpc.h"
35#include "scripting/python/modules.h"
36#include "lib/ldb/pyldb.h"
37#include "param/pyparam.h"
38
39static PyObject *provision_module(void)
40{
41	PyObject *name = PyString_FromString("samba.provision");
42	if (name == NULL)
43		return NULL;
44	return PyImport_Import(name);
45}
46
47NTSTATUS provision_bare(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
48			struct provision_settings *settings,
49			struct provision_result *result)
50{
51	const char *configfile;
52	PyObject *provision_mod, *provision_dict, *provision_fn, *py_result, *parameters;
53
54	DEBUG(0,("Provision for Become-DC test using python\n"));
55
56	py_load_samba_modules();
57	Py_Initialize();
58	py_update_path("bin"); /* FIXME: Can't assume this is always the case */
59
60	provision_mod = provision_module();
61
62	if (provision_mod == NULL) {
63		PyErr_Print();
64		DEBUG(0, ("Unable to import provision Python module.\n"));
65	      	return NT_STATUS_UNSUCCESSFUL;
66	}
67
68	provision_dict = PyModule_GetDict(provision_mod);
69
70	if (provision_dict == NULL) {
71		DEBUG(0, ("Unable to get dictionary for provision module\n"));
72		return NT_STATUS_UNSUCCESSFUL;
73	}
74
75	provision_fn = PyDict_GetItemString(provision_dict, "provision_become_dc");
76	if (provision_fn == NULL) {
77		PyErr_Print();
78		DEBUG(0, ("Unable to get provision_become_dc function\n"));
79		return NT_STATUS_UNSUCCESSFUL;
80	}
81
82	DEBUG(0,("New Server in Site[%s]\n",
83		 settings->site_name));
84
85	DEBUG(0,("DSA Instance [%s]\n"
86		"\tinvocationId[%s]\n",
87		settings->ntds_dn_str,
88		settings->invocation_id == NULL?"None":GUID_string(mem_ctx, settings->invocation_id)));
89
90	DEBUG(0,("Pathes under targetdir[%s]\n",
91		 settings->targetdir));
92	parameters = PyDict_New();
93
94	configfile = lp_configfile(lp_ctx);
95	if (configfile != NULL) {
96		PyDict_SetItemString(parameters, "smbconf",
97				     PyString_FromString(configfile));
98	}
99
100	PyDict_SetItemString(parameters, "rootdn",
101						 PyString_FromString(settings->root_dn_str));
102	if (settings->targetdir != NULL)
103		PyDict_SetItemString(parameters, "targetdir",
104							 PyString_FromString(settings->targetdir));
105	PyDict_SetItemString(parameters, "setup_dir",
106			     PyString_FromString("setup"));
107	PyDict_SetItemString(parameters, "hostname",
108						 PyString_FromString(settings->netbios_name));
109	PyDict_SetItemString(parameters, "domain",
110						 PyString_FromString(settings->domain));
111	PyDict_SetItemString(parameters, "realm",
112						 PyString_FromString(settings->realm));
113	if (settings->root_dn_str)
114		PyDict_SetItemString(parameters, "rootdn",
115				     PyString_FromString(settings->root_dn_str));
116
117	if (settings->domain_dn_str)
118		PyDict_SetItemString(parameters, "domaindn",
119				     PyString_FromString(settings->domain_dn_str));
120
121	if (settings->schema_dn_str)
122		PyDict_SetItemString(parameters, "schemadn",
123				     PyString_FromString(settings->schema_dn_str));
124
125	if (settings->config_dn_str)
126		PyDict_SetItemString(parameters, "configdn",
127				     PyString_FromString(settings->config_dn_str));
128
129	if (settings->server_dn_str)
130		PyDict_SetItemString(parameters, "serverdn",
131				     PyString_FromString(settings->server_dn_str));
132
133	if (settings->site_name)
134		PyDict_SetItemString(parameters, "sitename",
135				     PyString_FromString(settings->site_name));
136
137	PyDict_SetItemString(parameters, "machinepass",
138			     PyString_FromString(settings->machine_password));
139
140
141	PyDict_SetItemString(parameters, "debuglevel", PyInt_FromLong(DEBUGLEVEL));
142
143	py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters);
144
145	Py_DECREF(parameters);
146
147	if (py_result == NULL) {
148		PyErr_Print();
149		PyErr_Clear();
150		return NT_STATUS_UNSUCCESSFUL;
151	}
152
153	result->domaindn = talloc_strdup(mem_ctx, PyString_AsString(PyObject_GetAttrString(py_result, "domaindn")));
154
155	/* FIXME paths */
156	result->lp_ctx = lp_from_py_object(PyObject_GetAttrString(py_result, "lp"));
157	result->samdb = PyLdb_AsLdbContext(PyObject_GetAttrString(py_result, "samdb"));
158
159	return NT_STATUS_OK;
160}
161
162extern void initldb(void);
163
164static PyObject *py_dom_sid_FromSid(struct dom_sid *sid)
165{
166	PyObject *mod_security, *dom_sid_Type;
167
168	mod_security = PyImport_ImportModule("samba.dcerpc.security");
169	if (mod_security == NULL)
170		return NULL;
171
172	dom_sid_Type = PyObject_GetAttrString(mod_security, "dom_sid");
173	if (dom_sid_Type == NULL)
174		return NULL;
175
176	return py_talloc_reference((PyTypeObject *)dom_sid_Type, sid);
177}
178
179NTSTATUS provision_store_self_join(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
180				   struct tevent_context *event_ctx,
181				   struct provision_store_self_join_settings *settings,
182				   const char **error_string)
183{
184	int ret;
185	PyObject *provision_mod, *provision_dict, *provision_fn, *py_result, *parameters, *py_sid;
186	struct ldb_context *ldb;
187	TALLOC_CTX *tmp_mem = talloc_new(mem_ctx);
188	if (!tmp_mem) {
189		return NT_STATUS_NO_MEMORY;
190	}
191
192	/* Open the secrets database */
193	ldb = secrets_db_connect(tmp_mem, event_ctx, lp_ctx);
194	if (!ldb) {
195		*error_string
196			= talloc_asprintf(mem_ctx,
197					  "Could not open secrets database");
198		talloc_free(tmp_mem);
199		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
200	}
201
202	ret = ldb_transaction_start(ldb);
203
204	if (ret != LDB_SUCCESS) {
205		*error_string
206			= talloc_asprintf(mem_ctx,
207					  "Could not start transaction on secrets database: %s", ldb_errstring(ldb));
208		talloc_free(tmp_mem);
209		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
210	}
211
212	py_load_samba_modules();
213	Py_Initialize();
214	py_update_path("bin"); /* FIXME: Can't assume this is always the case */
215	initldb();
216	provision_mod = provision_module();
217
218	if (provision_mod == NULL) {
219		PyErr_Print();
220		*error_string
221			= talloc_asprintf(mem_ctx, "Unable to import provision Python module.");
222		talloc_free(tmp_mem);
223	      	return NT_STATUS_UNSUCCESSFUL;
224	}
225
226	provision_dict = PyModule_GetDict(provision_mod);
227
228	if (provision_dict == NULL) {
229		*error_string
230			= talloc_asprintf(mem_ctx, "Unable to get dictionary for provision module");
231		talloc_free(tmp_mem);
232		return NT_STATUS_UNSUCCESSFUL;
233	}
234
235	provision_fn = PyDict_GetItemString(provision_dict, "secretsdb_self_join");
236	if (provision_fn == NULL) {
237		PyErr_Print();
238		*error_string
239			= talloc_asprintf(mem_ctx, "Unable to get provision_become_dc function");
240		talloc_free(tmp_mem);
241		return NT_STATUS_UNSUCCESSFUL;
242	}
243
244	parameters = PyDict_New();
245
246	PyDict_SetItemString(parameters, "secretsdb",
247			     PyLdb_FromLdbContext(ldb));
248	PyDict_SetItemString(parameters, "domain",
249			     PyString_FromString(settings->domain_name));
250	PyDict_SetItemString(parameters, "domain",
251			     PyString_FromString(settings->domain_name));
252	PyDict_SetItemString(parameters, "realm",
253			     PyString_FromString(settings->realm));
254	PyDict_SetItemString(parameters, "machinepass",
255			     PyString_FromString(settings->machine_password));
256	PyDict_SetItemString(parameters, "netbiosname",
257			     PyString_FromString(settings->netbios_name));
258
259	py_sid = py_dom_sid_FromSid(settings->domain_sid);
260	if (py_sid == NULL) {
261		Py_DECREF(parameters);
262		goto failure;
263	}
264
265	PyDict_SetItemString(parameters, "domainsid",
266			     py_sid);
267
268	PyDict_SetItemString(parameters, "secure_channel_type",
269		       PyInt_FromLong(settings->secure_channel_type));
270
271	PyDict_SetItemString(parameters, "key_version_number",
272		       PyInt_FromLong(settings->key_version_number));
273
274	py_result = PyEval_CallObjectWithKeywords(provision_fn, NULL, parameters);
275
276	Py_DECREF(parameters);
277
278	if (py_result == NULL) {
279		goto failure;
280	}
281
282	ret = ldb_transaction_commit(ldb);
283	if (ret != LDB_SUCCESS) {
284		*error_string
285			= talloc_asprintf(mem_ctx,
286					  "Could not commit transaction on secrets database: %s", ldb_errstring(ldb));
287		talloc_free(tmp_mem);
288		return NT_STATUS_INTERNAL_DB_ERROR;
289	}
290
291	talloc_free(tmp_mem);
292
293	return NT_STATUS_OK;
294
295failure:
296	ldb_transaction_cancel(ldb);
297	talloc_free(tmp_mem);
298
299	PyErr_Print();
300	PyErr_Clear();
301	return NT_STATUS_UNSUCCESSFUL;
302}
303