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