r23779: Change from v2 or later to v3 or later.
[gd/samba/.git] / source3 / python / py_smb.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 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "python/py_smb.h"
22
23 /* Create a new cli_state python object */
24
25 PyObject *new_cli_state_object(struct cli_state *cli)
26 {
27         cli_state_object *o;
28
29         o = PyObject_New(cli_state_object, &cli_state_type);
30
31         o->cli = cli;
32
33         return (PyObject*)o;
34 }
35
36 static PyObject *py_smb_connect(PyObject *self, PyObject *args, PyObject *kw)
37 {
38         static char *kwlist[] = { "server", NULL };
39         struct cli_state *cli;
40         char *server;
41         struct in_addr ip;
42
43         if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &server))
44                 return NULL;
45
46         if (!(cli = cli_initialise()))
47                 return NULL;
48
49         ZERO_STRUCT(ip);
50
51         if (!cli_connect(cli, server, &ip))
52                 return NULL;
53
54         return new_cli_state_object(cli);
55 }
56
57 static PyObject *py_smb_session_request(PyObject *self, PyObject *args,
58                                         PyObject *kw)
59 {
60         cli_state_object *cli = (cli_state_object *)self;
61         static char *kwlist[] = { "called", "calling", NULL };
62         char *calling_name = NULL, *called_name;
63         struct nmb_name calling, called;
64         BOOL result;
65
66         if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s", kwlist, &called_name, 
67                                          &calling_name))
68                 return NULL;
69
70         if (!calling_name)
71                 calling_name = global_myname();
72
73         make_nmb_name(&calling, calling_name, 0x00);
74         make_nmb_name(&called, called_name, 0x20);
75
76         result = cli_session_request(cli->cli, &calling, &called);
77
78         return Py_BuildValue("i", result);
79 }
80                                       
81 static PyObject *py_smb_negprot(PyObject *self, PyObject *args, PyObject *kw)
82 {
83         cli_state_object *cli = (cli_state_object *)self;
84         static char *kwlist[] = { NULL };
85         BOOL result;
86
87         if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
88                 return NULL;
89
90         result = cli_negprot(cli->cli);
91
92         return Py_BuildValue("i", result);
93 }
94
95 static PyObject *py_smb_session_setup(PyObject *self, PyObject *args, 
96                                       PyObject *kw)
97 {
98         cli_state_object *cli = (cli_state_object *)self;
99         static char *kwlist[] = { "creds", NULL };
100         PyObject *creds;
101         char *username, *domain, *password, *errstr;
102         NTSTATUS result;
103
104         if (!PyArg_ParseTupleAndKeywords(args, kw, "|O", kwlist, &creds))
105                 return NULL;
106
107         if (!py_parse_creds(creds, &username, &domain, &password, &errstr)) {
108                 free(errstr);
109                 return NULL;
110         }
111
112         result = cli_session_setup(
113                 cli->cli, username, password, strlen(password) + 1,
114                 password, strlen(password) + 1, domain);
115
116         if (cli_is_error(cli->cli)) {
117                 PyErr_SetString(PyExc_RuntimeError, "session setup failed");
118                 return NULL;
119         }
120
121         return Py_BuildValue("i", NT_STATUS_IS_OK(result));
122 }
123
124 static PyObject *py_smb_tconx(PyObject *self, PyObject *args, PyObject *kw)
125 {
126         cli_state_object *cli = (cli_state_object *)self;
127         static char *kwlist[] = { "service", NULL };
128         char *service;
129         BOOL result;
130
131         if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &service))
132                 return NULL;
133
134         result = cli_send_tconX(
135                 cli->cli, service, strequal(service, "IPC$") ? "IPC" : 
136                 "?????", "", 1);
137
138         if (cli_is_error(cli->cli)) {
139                 PyErr_SetString(PyExc_RuntimeError, "tconx failed");
140                 return NULL;
141         }
142
143         return Py_BuildValue("i", result);
144 }
145
146 static PyObject *py_smb_nt_create_andx(PyObject *self, PyObject *args,
147                                        PyObject *kw)
148 {
149         cli_state_object *cli = (cli_state_object *)self;
150         static char *kwlist[] = { "filename", "desired_access", 
151                                   "file_attributes", "share_access",
152                                   "create_disposition", "create_options",
153                                   NULL };
154         char *filename;
155         uint32 desired_access, file_attributes = 0, 
156                 share_access = FILE_SHARE_READ | FILE_SHARE_WRITE,
157                 create_disposition = OPENX_FILE_EXISTS_OPEN, create_options = 0;
158         int result;
159
160         /* Parse parameters */
161
162         if (!PyArg_ParseTupleAndKeywords(
163                     args, kw, "si|iiii", kwlist, &filename, &desired_access,
164                     &file_attributes, &share_access, &create_disposition,
165                     &create_options))
166                 return NULL;
167
168         result = cli_nt_create_full(
169                 cli->cli, filename, 0, desired_access, file_attributes,
170                 share_access, create_disposition, create_options, 0);
171
172         if (cli_is_error(cli->cli)) {
173                 PyErr_SetString(PyExc_RuntimeError, "nt_create_andx failed");
174                 return NULL;
175         }
176
177         /* Return FID */
178
179         return PyInt_FromLong(result);
180 }
181
182 static PyObject *py_smb_open(PyObject *self, PyObject *args, PyObject *kw)
183 {
184         cli_state_object *cli = (cli_state_object *)self;
185         static char *kwlist[] = { "filename", "flags", 
186                                   "share_mode", NULL };
187         char *filename;
188         uint32 flags, share_mode = DENY_NONE;
189         int result;
190
191         /* Parse parameters */
192
193         if (!PyArg_ParseTupleAndKeywords(
194                     args, kw, "si|i", kwlist, &filename, &flags, &share_mode))
195                 return NULL;
196
197         result = cli_open(cli->cli, filename, flags, share_mode);
198
199         if (cli_is_error(cli->cli)) {
200                 PyErr_SetString(PyExc_RuntimeError, "open failed");
201                 return NULL;
202         }
203
204         /* Return FID */
205
206         return PyInt_FromLong(result);
207 }
208
209 static PyObject *py_smb_read(PyObject *self, PyObject *args, PyObject *kw)
210 {
211         cli_state_object *cli = (cli_state_object *)self;
212         static char *kwlist[] = { "fnum", "offset", "size", NULL };
213         int fnum, offset=0, size=0;
214         ssize_t result;
215         SMB_OFF_T fsize;
216         char *data;
217         PyObject *ret;
218
219         /* Parse parameters */
220
221         if (!PyArg_ParseTupleAndKeywords(
222                     args, kw, "i|ii", kwlist, &fnum, &offset, &size))
223                 return NULL;
224
225         if (!cli_qfileinfo(cli->cli, fnum, NULL, &fsize, NULL, NULL,
226                     NULL, NULL, NULL) &&
227             !cli_getattrE(cli->cli, fnum, NULL, &fsize, NULL, NULL, NULL)) {
228                 PyErr_SetString(PyExc_RuntimeError, "getattrib failed");
229                 return NULL;
230         }
231
232         if (offset < 0)
233                 offset = 0;
234
235         if (size < 1 || size > fsize - offset)
236                 size = fsize - offset;
237
238         if (!(data = SMB_XMALLOC_ARRAY(char, size))) {
239                 PyErr_SetString(PyExc_RuntimeError, "malloc failed");
240                 return NULL;
241         }
242
243         result = cli_read(cli->cli, fnum, data, (off_t) offset, (size_t) size);
244
245         if (result==-1 || cli_is_error(cli->cli)) {
246                 SAFE_FREE(data);
247                 PyErr_SetString(PyExc_RuntimeError, "read failed");
248                 return NULL;
249         }
250
251         /* Return a python string */
252
253         ret = Py_BuildValue("s#", data, result);
254         SAFE_FREE(data);
255
256         return ret;
257 }
258
259 static PyObject *py_smb_close(PyObject *self, PyObject *args,
260                               PyObject *kw)
261 {
262         cli_state_object *cli = (cli_state_object *)self;
263         static char *kwlist[] = { "fnum", NULL };
264         BOOL result;
265         int fnum;
266
267         /* Parse parameters */
268
269         if (!PyArg_ParseTupleAndKeywords(
270                     args, kw, "i", kwlist, &fnum))
271                 return NULL;
272
273         result = cli_close(cli->cli, fnum);
274
275         return PyInt_FromLong(result);
276 }
277
278 static PyObject *py_smb_unlink(PyObject *self, PyObject *args,
279                                PyObject *kw)
280 {
281         cli_state_object *cli = (cli_state_object *)self;
282         static char *kwlist[] = { "filename", NULL };
283         char *filename;
284         BOOL result;
285
286         /* Parse parameters */
287
288         if (!PyArg_ParseTupleAndKeywords(
289                     args, kw, "s", kwlist, &filename))
290                 return NULL;
291
292         result = cli_unlink(cli->cli, filename);
293
294         return PyInt_FromLong(result);
295 }
296
297 static PyObject *py_smb_query_secdesc(PyObject *self, PyObject *args,
298                                       PyObject *kw)
299 {
300         cli_state_object *cli = (cli_state_object *)self;
301         static char *kwlist[] = { "fnum", NULL };
302         PyObject *result = NULL;
303         SEC_DESC *secdesc = NULL;
304         int fnum;
305         TALLOC_CTX *mem_ctx = NULL;
306
307         /* Parse parameters */
308
309         if (!PyArg_ParseTupleAndKeywords(
310                     args, kw, "i", kwlist, &fnum))
311                 return NULL;
312
313         mem_ctx = talloc_init("py_smb_query_secdesc");
314
315         secdesc = cli_query_secdesc(cli->cli, fnum, mem_ctx);
316
317         if (cli_is_error(cli->cli)) {
318                 PyErr_SetString(PyExc_RuntimeError, "query_secdesc failed");
319                 goto done;
320         }
321
322         if (!secdesc) {
323                 Py_INCREF(Py_None);
324                 result = Py_None;
325                 goto done;
326         }
327
328         if (!py_from_SECDESC(&result, secdesc)) {
329                 PyErr_SetString(
330                         PyExc_TypeError,
331                         "Invalid security descriptor returned");
332                 goto done;
333         }
334
335  done:
336         talloc_destroy(mem_ctx);
337
338         return result;
339         
340 }
341
342 static PyObject *py_smb_set_secdesc(PyObject *self, PyObject *args,
343                                     PyObject *kw)
344 {
345         cli_state_object *cli = (cli_state_object *)self;
346         static char *kwlist[] = { "fnum", "security_descriptor", NULL };
347         PyObject *result = NULL;
348         PyObject *py_secdesc;
349         SEC_DESC *secdesc;
350         TALLOC_CTX *mem_ctx = NULL;
351         int fnum;
352         BOOL err;
353
354         /* Parse parameters */
355
356         if (!PyArg_ParseTupleAndKeywords(
357                     args, kw, "iO", kwlist, &fnum, &py_secdesc))
358                 return NULL;
359
360         mem_ctx = talloc_init("py_smb_set_secdesc");
361
362         if (!py_to_SECDESC(&secdesc, py_secdesc, mem_ctx)) {
363                 PyErr_SetString(PyExc_TypeError, 
364                                 "Invalid security descriptor");
365                 goto done;
366         }
367
368         err = cli_set_secdesc(cli->cli, fnum, secdesc);
369
370         if (cli_is_error(cli->cli)) {
371                 PyErr_SetString(PyExc_RuntimeError, "set_secdesc failed");
372                 goto done;
373         }
374
375         result =  PyInt_FromLong(err);
376  done:
377         talloc_destroy(mem_ctx);
378
379         return result;
380 }
381
382 static PyMethodDef smb_hnd_methods[] = {
383
384         /* Session and connection handling */
385
386         { "session_request", (PyCFunction)py_smb_session_request, 
387           METH_VARARGS | METH_KEYWORDS, "Request a session" },
388
389         { "negprot", (PyCFunction)py_smb_negprot, 
390           METH_VARARGS | METH_KEYWORDS, "Protocol negotiation" },
391
392         { "session_setup", (PyCFunction)py_smb_session_setup,
393           METH_VARARGS | METH_KEYWORDS, "Session setup" },
394
395         { "tconx", (PyCFunction)py_smb_tconx,
396           METH_VARARGS | METH_KEYWORDS, "Tree connect" },
397
398         /* File operations */
399
400         { "nt_create_andx", (PyCFunction)py_smb_nt_create_andx,
401           METH_VARARGS | METH_KEYWORDS, "NT Create&X" },
402
403         { "open", (PyCFunction)py_smb_open,
404           METH_VARARGS | METH_KEYWORDS,
405           "Open a file\n"
406 "\n"
407 "This function returns a fnum handle to an open file.  The file is\n"
408 "opened with flags and optional share mode.  If unspecified, the\n"
409 "default share mode is DENY_NONE\n"
410 "\n"
411 "Example:\n"
412 "\n"
413 ">>> fnum=conn.open(filename, os.O_RDONLY)" },
414
415         { "read", (PyCFunction)py_smb_read,
416           METH_VARARGS | METH_KEYWORDS,
417           "Read from an open file\n"
418 "\n"
419 "This function returns a string read from an open file starting at\n"
420 "offset for size bytes (until EOF is reached).  If unspecified, the\n"
421 "default offset is 0, and default size is the remainder of the file.\n"
422 "\n"
423 "Example:\n"
424 "\n"
425 ">>> conn.read(fnum)           # read entire file\n"
426 ">>> conn.read(fnum,5)         # read entire file from offset 5\n"
427 ">>> conn.read(fnum,size=64)   # read 64 bytes from start of file\n"
428 ">>> conn.read(fnum,4096,1024) # read 1024 bytes from offset 4096\n" },
429
430         { "close", (PyCFunction)py_smb_close,
431           METH_VARARGS | METH_KEYWORDS, "Close" },
432
433         { "unlink", (PyCFunction)py_smb_unlink,
434           METH_VARARGS | METH_KEYWORDS, "Unlink" },
435
436         /* Security descriptors */
437
438         { "query_secdesc", (PyCFunction)py_smb_query_secdesc,
439           METH_VARARGS | METH_KEYWORDS, "Query security descriptor" },
440
441         { "set_secdesc", (PyCFunction)py_smb_set_secdesc,
442           METH_VARARGS | METH_KEYWORDS, "Set security descriptor" },
443
444         { NULL }
445 };
446
447 /*
448  * Method dispatch tables
449  */
450
451 static PyMethodDef smb_methods[] = {
452
453         { "connect", (PyCFunction)py_smb_connect, METH_VARARGS | METH_KEYWORDS,
454           "Connect to a host" },
455
456         /* Other stuff - this should really go into a samba config module
457            but for the moment let's leave it here. */
458
459         { "setup_logging", (PyCFunction)py_setup_logging, 
460           METH_VARARGS | METH_KEYWORDS, 
461           "Set up debug logging.\n"
462 "\n"
463 "Initialises Samba's debug logging system.  One argument is expected which\n"
464 "is a boolean specifying whether debugging is interactive and sent to stdout\n"
465 "or logged to a file.\n"
466 "\n"
467 "Example:\n"
468 "\n"
469 ">>> smb.setup_logging(interactive = 1)" },
470
471         { "get_debuglevel", (PyCFunction)get_debuglevel, 
472           METH_VARARGS, 
473           "Set the current debug level.\n"
474 "\n"
475 "Example:\n"
476 "\n"
477 ">>> smb.get_debuglevel()\n"
478 "0" },
479
480         { "set_debuglevel", (PyCFunction)set_debuglevel, 
481           METH_VARARGS, 
482           "Get the current debug level.\n"
483 "\n"
484 "Example:\n"
485 "\n"
486 ">>> smb.set_debuglevel(10)" },
487
488         { NULL }
489 };
490
491 static void py_cli_state_dealloc(PyObject* self)
492 {
493         cli_state_object *cli = (cli_state_object *)self;
494
495         if (cli->cli)
496                 cli_shutdown(cli->cli);
497
498         PyObject_Del(self);
499 }
500
501 static PyObject *py_cli_state_getattr(PyObject *self, char *attrname)
502 {
503         return Py_FindMethod(smb_hnd_methods, self, attrname);
504 }
505
506 PyTypeObject cli_state_type = {
507         PyObject_HEAD_INIT(NULL)
508         0,
509         "SMB client connection",
510         sizeof(cli_state_object),
511         0,
512         py_cli_state_dealloc, /*tp_dealloc*/
513         0,          /*tp_print*/
514         py_cli_state_getattr,          /*tp_getattr*/
515         0,          /*tp_setattr*/
516         0,          /*tp_compare*/
517         0,          /*tp_repr*/
518         0,          /*tp_as_number*/
519         0,          /*tp_as_sequence*/
520         0,          /*tp_as_mapping*/
521         0,          /*tp_hash */
522 };
523
524 /*
525  * Module initialisation 
526  */
527
528 void initsmb(void)
529 {
530         PyObject *module, *dict;
531
532         /* Initialise module */
533
534         module = Py_InitModule("smb", smb_methods);
535         dict = PyModule_GetDict(module);
536
537         /* Initialise policy handle object */
538
539         cli_state_type.ob_type = &PyType_Type;
540
541         /* Do samba initialisation */
542
543         py_samba_init();
544
545         setup_logging("smb", True);
546         DEBUGLEVEL = 3;
547 }