Initial import
[samba] / source / python / py_common.c
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
25 PyObject *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
33 PyObject *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
41 static BOOL initialised;
42
43 void 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
63 PyObject *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
75 PyObject *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
90 PyObject *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
126 BOOL 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
210 struct 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
247 BOOL 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 }