1/*
2   Python wrappers for DCERPC/SMB client routines.
3
4   Copyright (C) Tim Potter, 2002
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 2 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, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "python/py_common.h"
22
23/* Return a tuple of (error code, error string) from a WERROR */
24
25PyObject *py_werror_tuple(WERROR werror)
26{
27	return Py_BuildValue("[is]", W_ERROR_V(werror),
28			     dos_errstr(werror));
29}
30
31/* Return a tuple of (error code, error string) from a WERROR */
32
33PyObject *py_ntstatus_tuple(NTSTATUS ntstatus)
34{
35	return Py_BuildValue("[is]", NT_STATUS_V(ntstatus),
36			     nt_errstr(ntstatus));
37}
38
39/* Initialise samba client routines */
40
41static BOOL initialised;
42
43void py_samba_init(void)
44{
45	if (initialised)
46		return;
47
48	/* Load configuration file */
49
50	if (!lp_load(dyn_CONFIGFILE, True, False, False))
51		fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
52
53	/* Misc other stuff */
54
55	load_interfaces();
56	init_names();
57
58	initialised = True;
59}
60
61/* Debuglevel routines */
62
63PyObject *get_debuglevel(PyObject *self, PyObject *args)
64{
65	PyObject *debuglevel;
66
67	if (!PyArg_ParseTuple(args, ""))
68		return NULL;
69
70	debuglevel = PyInt_FromLong(DEBUGLEVEL);
71
72	return debuglevel;
73}
74
75PyObject *set_debuglevel(PyObject *self, PyObject *args)
76{
77	int debuglevel;
78
79	if (!PyArg_ParseTuple(args, "i", &debuglevel))
80		return NULL;
81
82	DEBUGLEVEL = debuglevel;
83
84	Py_INCREF(Py_None);
85	return Py_None;
86}
87
88/* Initialise logging */
89
90PyObject *py_setup_logging(PyObject *self, PyObject *args, PyObject *kw)
91{
92	BOOL interactive = False;
93	char *logfilename = NULL;
94	static char *kwlist[] = {"interactive", "logfilename", NULL};
95
96	if (!PyArg_ParseTupleAndKeywords(
97		    args, kw, "|is", kwlist, &interactive, &logfilename))
98		return NULL;
99
100	if (interactive && logfilename) {
101		PyErr_SetString(PyExc_RuntimeError,
102				"can't be interactive and set log file name");
103		return NULL;
104	}
105
106	if (interactive)
107		setup_logging("spoolss", True);
108
109	if (logfilename) {
110		lp_set_logfile(logfilename);
111		setup_logging(logfilename, False);
112		reopen_logs();
113	}
114
115	Py_INCREF(Py_None);
116	return Py_None;
117}
118
119/* Parse credentials from a python dictionary.  The dictionary can
120   only have the keys "username", "domain" and "password".  Return
121   True for valid credentials in which case the username, domain and
122   password are set to pointers to their values from the dicationary.
123   If returns False, the errstr is set to point at some mallocated
124   memory describing the error. */
125
126BOOL py_parse_creds(PyObject *creds, char **username, char **domain,
127		    char **password, char **errstr)
128{
129	/* Initialise anonymous credentials */
130
131	*username = "";
132	*domain = "";
133	*password = "";
134
135	if (creds && PyDict_Size(creds) > 0) {
136		PyObject *username_obj, *password_obj, *domain_obj;
137		PyObject *key, *value;
138		int i;
139
140		/* Check for presence of required fields */
141
142		username_obj = PyDict_GetItemString(creds, "username");
143		domain_obj = PyDict_GetItemString(creds, "domain");
144		password_obj = PyDict_GetItemString(creds, "password");
145
146		if (!username_obj) {
147			*errstr = SMB_STRDUP("no username field in credential");
148			return False;
149		}
150
151		if (!domain_obj) {
152			*errstr = SMB_STRDUP("no domain field in credential");
153			return False;
154		}
155
156		if (!password_obj) {
157			*errstr = SMB_STRDUP("no password field in credential");
158			return False;
159		}
160
161		/* Check type of required fields */
162
163		if (!PyString_Check(username_obj)) {
164			*errstr = SMB_STRDUP("username field is not string type");
165			return False;
166		}
167
168		if (!PyString_Check(domain_obj)) {
169			*errstr = SMB_STRDUP("domain field is not string type");
170			return False;
171		}
172
173		if (!PyString_Check(password_obj)) {
174			*errstr = SMB_STRDUP("password field is not string type");
175			return False;
176		}
177
178		/* Look for any extra fields */
179
180		i = 0;
181
182		while (PyDict_Next(creds, &i, &key, &value)) {
183			if (strcmp(PyString_AsString(key), "domain") != 0 &&
184			    strcmp(PyString_AsString(key), "username") != 0 &&
185			    strcmp(PyString_AsString(key), "password") != 0) {
186				asprintf(errstr,
187					 "creds contain extra field '%s'",
188					 PyString_AsString(key));
189				return False;
190			}
191		}
192
193		/* Assign values */
194
195		*username = PyString_AsString(username_obj);
196		*domain = PyString_AsString(domain_obj);
197		*password = PyString_AsString(password_obj);
198	}
199
200	*errstr = NULL;
201
202	return True;
203}
204
205/* Return a cli_state to a RPC pipe on the given server.  Use the
206   credentials passed if not NULL.  If an error occurs errstr is set to a
207   string describing the error and NULL is returned.  If set, errstr must
208   be freed by calling free(). */
209
210struct cli_state *open_pipe_creds(char *server, PyObject *creds,
211				  int pipe_idx, char **errstr)
212{
213	char *username, *password, *domain;
214	struct cli_state *cli;
215	NTSTATUS result;
216
217	/* Extract credentials from the python dictionary */
218
219	if (!py_parse_creds(creds, &username, &domain, &password, errstr))
220		return NULL;
221
222	/* Now try to connect */
223
224	result = cli_full_connection(
225		&cli, NULL, server, NULL, 0, "IPC$", "IPC",
226		username, domain, password, 0, Undefined, NULL);
227
228	if (!NT_STATUS_IS_OK(result)) {
229		*errstr = SMB_STRDUP("error connecting to IPC$ pipe");
230		return NULL;
231	}
232
233	if (!cli_nt_session_open(cli, pipe_idx)) {
234		cli_shutdown(cli);
235		asprintf(errstr, "error opening pipe index %d", pipe_idx);
236		return NULL;
237	}
238
239	*errstr = NULL;
240
241	return cli;
242}
243
244/* Return true if a dictionary contains a "level" key with an integer
245   value.  Set the value if so. */
246
247BOOL get_level_value(PyObject *dict, uint32 *level)
248{
249	PyObject *obj;
250
251	if (!(obj = PyDict_GetItemString(dict, "level")) ||
252	    !PyInt_Check(obj))
253		return False;
254
255	if (level)
256		*level = PyInt_AsLong(obj);
257
258	return True;
259}
260