s4:pysmb: Add error log that the s4 bindings are deprecated
[metze/samba/wip.git] / source4 / libcli / pysmb.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Amitay Isaacs 2011
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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <Python.h>
21 #include "python/py3compat.h"
22 #include <tevent.h>
23 #include <pytalloc.h>
24 #include "includes.h"
25 #include "param/param.h"
26 #include "param/pyparam.h"
27 #include "system/dir.h"
28 #include "system/filesys.h"
29 #include "lib/events/events.h"
30 #include "auth/credentials/credentials.h"
31 #include "auth/credentials/pycredentials.h"
32 #include "auth/gensec/gensec.h"
33 #include "libcli/libcli.h"
34 #include "libcli/raw/libcliraw.h"
35 #include "libcli/raw/raw_proto.h"
36 #include "libcli/resolve/resolve.h"
37 #include "libcli/util/pyerrors.h"
38 #include "libcli/smb_composite/smb_composite.h"
39 #include "libcli/security/security_descriptor.h"
40 #include "librpc/rpc/pyrpc_util.h"
41
42 static PyTypeObject PySMB;
43
44 void initsmb(void);
45
46 struct smb_private_data {
47         struct loadparm_context *lp_ctx;
48         struct cli_credentials *creds;
49         struct tevent_context *ev_ctx;
50         struct smbcli_tree *tree;
51 };
52
53 static void dos_format(char *s)
54 {
55         string_replace(s, '/', '\\');
56 }
57
58
59 /*
60  * Connect to SMB share using smb_full_connection
61  */
62 static NTSTATUS do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spdata,
63                                const char *hostname, const char *service,
64                                struct smbcli_options *options,
65                                struct smbcli_session_options *session_options,
66                                struct smbcli_tree **tree)
67 {
68         struct smbcli_state *smb_state;
69         NTSTATUS status;
70
71         *tree = NULL;
72
73         gensec_init();
74
75         smb_state = smbcli_state_init(mem_ctx);
76
77         status = smbcli_full_connection(mem_ctx, &smb_state, hostname, 
78                                         lpcfg_smb_ports(spdata->lp_ctx),
79                                         service, 
80                                         NULL,
81                                         lpcfg_socket_options(spdata->lp_ctx),
82                                         spdata->creds,
83                                         lpcfg_resolve_context(spdata->lp_ctx),
84                                         spdata->ev_ctx,
85                                         options,
86                                         session_options,
87                                         lpcfg_gensec_settings(mem_ctx, spdata->lp_ctx));
88
89         if (NT_STATUS_IS_OK(status)) {
90                 *tree = smb_state->tree;
91         }
92
93         return status;
94 }
95
96
97 /*
98  * Read SMB file and return the contents of the file as python string
99  */
100 static PyObject * py_smb_loadfile(PyObject *self, PyObject *args)
101 {
102         struct smb_composite_loadfile io;
103         const char *filename;
104         NTSTATUS status;
105         struct smb_private_data *spdata;
106
107         if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
108                 return NULL;
109         }
110
111         ZERO_STRUCT(io);
112
113         io.in.fname = filename;
114
115         spdata = pytalloc_get_ptr(self);
116         status = smb_composite_loadfile(spdata->tree, pytalloc_get_mem_ctx(self), &io);
117         PyErr_NTSTATUS_IS_ERR_RAISE(status);
118
119         return Py_BuildValue(PYARG_BYTES_LEN, io.out.data, io.out.size);
120 }
121
122 /*
123  * Create a SMB file with given string as the contents
124  */
125 static PyObject * py_smb_savefile(PyObject *self, PyObject *args)
126 {
127         struct smb_composite_savefile io;
128         const char *filename;
129         char *data = NULL;
130         Py_ssize_t size = 0;
131         NTSTATUS status;
132         struct smb_private_data *spdata;
133
134         if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename, &data, &size )) {
135                 return NULL;
136         }
137
138         io.in.fname = filename;
139         io.in.data = (unsigned char *)data;
140         io.in.size = size;
141
142         spdata = pytalloc_get_ptr(self);
143         status = smb_composite_savefile(spdata->tree, &io);
144         PyErr_NTSTATUS_IS_ERR_RAISE(status);
145
146         Py_RETURN_NONE;
147 }
148
149 /*
150  * Callback function to accumulate directory contents in a python list
151  */
152 static void py_smb_list_callback(struct clilist_file_info *f, const char *mask, void *state)
153 {
154         PyObject *py_dirlist;
155         PyObject *dict;
156
157         if(!ISDOT(f->name) && !ISDOTDOT(f->name)) {
158                 py_dirlist = (PyObject *)state;
159
160                 dict = PyDict_New();
161                 if(dict) {
162                         PyDict_SetItemString(dict, "name", PyStr_FromString(f->name));
163                         
164                         /* Windows does not always return short_name */
165                         if (f->short_name) {
166                                 PyDict_SetItemString(dict, "short_name", PyStr_FromString(f->short_name));
167                         } else {
168                                 PyDict_SetItemString(dict, "short_name", Py_None);
169                         }
170
171                         PyDict_SetItemString(dict, "size", PyLong_FromUnsignedLongLong(f->size));
172                         PyDict_SetItemString(dict, "attrib", PyInt_FromLong(f->attrib));
173                         PyDict_SetItemString(dict, "mtime", PyInt_FromLong(f->mtime));
174
175                         PyList_Append(py_dirlist, dict);
176                 }
177         }
178 }
179
180 /*
181  * List the directory contents for specified directory (Ignore '.' and '..' dirs)
182  */
183 static PyObject *py_smb_list(PyObject *self, PyObject *args, PyObject *kwargs)
184 {
185         struct smb_private_data *spdata;
186         PyObject *py_dirlist;
187         const char *kwnames[] = { "directory", "mask", "attribs", NULL };
188         char *base_dir;
189         char *user_mask = NULL;
190         char *mask;
191         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY
192                                 | FILE_ATTRIBUTE_ARCHIVE;
193
194         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|sH:list",
195                                         discard_const_p(char *, kwnames),
196                                         &base_dir, &user_mask, &attribute)) {
197                 return NULL;
198         }
199
200         if (user_mask == NULL) {
201                 mask = talloc_asprintf(pytalloc_get_mem_ctx(self), "%s\\*", base_dir);
202         } else {
203                 mask = talloc_asprintf(pytalloc_get_mem_ctx(self), "%s\\%s", base_dir, user_mask);
204         }
205         dos_format(mask);
206
207         spdata = pytalloc_get_ptr(self);
208
209         if((py_dirlist = PyList_New(0)) == NULL) {
210                 PyErr_NoMemory();
211                 return NULL;
212         }
213
214         smbcli_list(spdata->tree, mask, attribute, py_smb_list_callback, (void *)py_dirlist);
215
216         talloc_free(mask);
217
218         return py_dirlist;
219 }
220
221 /*
222  * Create a directory
223  */
224 static PyObject *py_smb_mkdir(PyObject *self, PyObject *args)
225 {
226         NTSTATUS status;
227         const char *dirname;
228         struct smb_private_data *spdata;
229
230         if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
231                 return NULL;
232         }
233
234         spdata = pytalloc_get_ptr(self);
235         status = smbcli_mkdir(spdata->tree, dirname);
236         PyErr_NTSTATUS_IS_ERR_RAISE(status);
237
238         Py_RETURN_NONE;
239 }
240
241 /*
242  * Remove a directory
243  */
244 static PyObject *py_smb_rmdir(PyObject *self, PyObject *args)
245 {
246         NTSTATUS status;
247         const char *dirname;
248         struct smb_private_data *spdata;
249
250         if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
251                 return NULL;
252         }
253
254         spdata = pytalloc_get_ptr(self);
255         status = smbcli_rmdir(spdata->tree, dirname);
256         PyErr_NTSTATUS_IS_ERR_RAISE(status);
257
258         Py_RETURN_NONE;
259 }
260
261
262 /*
263  * Remove a file
264  */
265 static PyObject *py_smb_unlink(PyObject *self, PyObject *args)
266 {
267         NTSTATUS status;
268         const char *filename;
269         struct smb_private_data *spdata;
270
271         if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
272                 return NULL;
273         }
274
275         spdata = pytalloc_get_ptr(self);
276         status = smbcli_unlink(spdata->tree, filename);
277         PyErr_NTSTATUS_IS_ERR_RAISE(status);
278
279         Py_RETURN_NONE;
280 }
281
282 /*
283  * Remove a directory and all its contents
284  */
285 static PyObject *py_smb_deltree(PyObject *self, PyObject *args)
286 {
287         int status;
288         const char *dirname;
289         struct smb_private_data *spdata;
290
291         if (!PyArg_ParseTuple(args, "s:deltree", &dirname)) {
292                 return NULL;
293         }
294
295         spdata = pytalloc_get_ptr(self);
296         status = smbcli_deltree(spdata->tree, dirname);
297         if (status <= 0) {
298                 return NULL;
299         }
300
301         Py_RETURN_NONE;
302 }
303
304 /*
305  * Check existence of a path
306  */
307 static PyObject *py_smb_chkpath(PyObject *self, PyObject *args)
308 {
309         NTSTATUS status;
310         const char *path;
311         struct smb_private_data *spdata;
312
313         if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
314                 return NULL;
315         }
316
317         spdata = pytalloc_get_ptr(self);
318         status = smbcli_chkpath(spdata->tree, path);
319
320         if (NT_STATUS_IS_OK(status)) {
321                 Py_RETURN_TRUE;
322         }
323
324         Py_RETURN_FALSE;
325 }
326
327 /*
328  * Read ACL on a given file/directory as a security descriptor object
329  */
330 static PyObject *py_smb_getacl(PyObject *self, PyObject *args, PyObject *kwargs)
331 {
332         NTSTATUS status;
333         union smb_open io;
334         union smb_fileinfo fio;
335         struct smb_private_data *spdata;
336         const char *filename;
337         uint32_t sinfo = 0;
338         int access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
339         int fnum;
340
341         if (!PyArg_ParseTuple(args, "s|Ii:get_acl", &filename, &sinfo, &access_mask)) {
342                 return NULL;
343         }
344
345         ZERO_STRUCT(io);
346
347         spdata = pytalloc_get_ptr(self);
348
349         io.generic.level = RAW_OPEN_NTCREATEX;
350         io.ntcreatex.in.root_fid.fnum = 0;
351         io.ntcreatex.in.flags = 0;
352         io.ntcreatex.in.access_mask = access_mask;
353         io.ntcreatex.in.create_options = 0;
354         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
355         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | 
356                                         NTCREATEX_SHARE_ACCESS_WRITE;
357         io.ntcreatex.in.alloc_size = 0;
358         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
359         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
360         io.ntcreatex.in.security_flags = 0;
361         io.ntcreatex.in.fname = filename;
362         
363         status = smb_raw_open(spdata->tree, pytalloc_get_mem_ctx(self), &io);
364         PyErr_NTSTATUS_IS_ERR_RAISE(status);
365
366         fnum = io.ntcreatex.out.file.fnum;
367
368         ZERO_STRUCT(fio);
369
370         fio.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
371         fio.query_secdesc.in.file.fnum = fnum;
372         if (sinfo)
373                 fio.query_secdesc.in.secinfo_flags = sinfo;
374         else
375                 fio.query_secdesc.in.secinfo_flags = SECINFO_OWNER |
376                                                 SECINFO_GROUP |
377                                                 SECINFO_DACL |
378                                                 SECINFO_PROTECTED_DACL |
379                                                 SECINFO_UNPROTECTED_DACL |
380                                                 SECINFO_SACL |
381                                                 SECINFO_PROTECTED_SACL |
382                                                 SECINFO_UNPROTECTED_SACL;
383
384         status = smb_raw_query_secdesc(spdata->tree, pytalloc_get_mem_ctx(self), &fio);
385         smbcli_close(spdata->tree, fnum);
386
387         PyErr_NTSTATUS_IS_ERR_RAISE(status);
388
389         return py_return_ndr_struct("samba.dcerpc.security", "descriptor",
390                                 pytalloc_get_mem_ctx(self), fio.query_secdesc.out.sd);
391 }
392
393 /*
394  * Set ACL on file/directory using given security descriptor object
395  */
396 static PyObject *py_smb_setacl(PyObject *self, PyObject *args, PyObject *kwargs)
397 {
398         NTSTATUS status;
399         union smb_open io;
400         union smb_setfileinfo fio;
401         struct smb_private_data *spdata;
402         const char *filename;
403         PyObject *py_sd;
404         struct security_descriptor *sd;
405         uint32_t sinfo = 0;
406         int fnum;
407
408         if (!PyArg_ParseTuple(args, "sO|I:get_acl", &filename, &py_sd, &sinfo)) {
409                 return NULL;
410         }
411
412         spdata = pytalloc_get_ptr(self);
413
414         sd = pytalloc_get_type(py_sd, struct security_descriptor);
415         if (!sd) {
416                 PyErr_Format(PyExc_TypeError, 
417                         "Expected dcerpc.security.descriptor as argument, got %s", 
418                         talloc_get_name(pytalloc_get_ptr(py_sd)));
419                 return NULL;
420         }
421
422         ZERO_STRUCT(io);
423
424         spdata = pytalloc_get_ptr(self);
425
426         io.generic.level = RAW_OPEN_NTCREATEX;
427         io.ntcreatex.in.root_fid.fnum = 0;
428         io.ntcreatex.in.flags = 0;
429         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
430         io.ntcreatex.in.create_options = 0;
431         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
432         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | 
433                                         NTCREATEX_SHARE_ACCESS_WRITE;
434         io.ntcreatex.in.alloc_size = 0;
435         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
436         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
437         io.ntcreatex.in.security_flags = 0;
438         io.ntcreatex.in.fname = filename;
439         
440         status = smb_raw_open(spdata->tree, pytalloc_get_mem_ctx(self), &io);
441         PyErr_NTSTATUS_IS_ERR_RAISE(status);
442
443         fnum = io.ntcreatex.out.file.fnum;
444
445         ZERO_STRUCT(fio);
446
447         fio.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
448         fio.set_secdesc.in.file.fnum = fnum;
449         if (sinfo)
450                 fio.set_secdesc.in.secinfo_flags = sinfo;
451         else
452                 fio.set_secdesc.in.secinfo_flags = SECINFO_OWNER |
453                                                 SECINFO_GROUP |
454                                                 SECINFO_DACL |
455                                                 SECINFO_PROTECTED_DACL |
456                                                 SECINFO_UNPROTECTED_DACL |
457                                                 SECINFO_SACL |
458                                                 SECINFO_PROTECTED_SACL |
459                                                 SECINFO_UNPROTECTED_SACL;
460
461         fio.set_secdesc.in.sd = sd;
462
463         status = smb_raw_set_secdesc(spdata->tree, &fio);
464         smbcli_close(spdata->tree, fnum);
465
466         PyErr_NTSTATUS_IS_ERR_RAISE(status);
467
468         Py_RETURN_NONE;
469 }
470
471 /*
472  * Open the file with the parameters passed in and return an object if OK
473  */
474 static PyObject *py_open_file(PyObject *self, PyObject *args, PyObject *kwargs)
475 {
476         NTSTATUS status;
477         union smb_open io;
478         struct smb_private_data *spdata;
479         const char *filename;
480         uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
481         uint32_t share_access = NTCREATEX_SHARE_ACCESS_READ |
482                                 NTCREATEX_SHARE_ACCESS_WRITE;
483         uint32_t open_disposition = NTCREATEX_DISP_OPEN;
484         uint32_t create_options = 0;
485         TALLOC_CTX *mem_ctx;
486         int fnum;
487
488         if (!PyArg_ParseTuple(args, "s|iiii:open_file", 
489                                 &filename, 
490                                 &access_mask,
491                                 &share_access,
492                                 &open_disposition,
493                                 &create_options)) {
494                 return NULL;
495         }
496
497         ZERO_STRUCT(io);
498
499         spdata = pytalloc_get_ptr(self);
500
501         mem_ctx = talloc_new(NULL);
502
503         io.generic.level = RAW_OPEN_NTCREATEX;
504         io.ntcreatex.in.root_fid.fnum = 0;
505         io.ntcreatex.in.flags = 0;
506         io.ntcreatex.in.access_mask = access_mask;
507         io.ntcreatex.in.create_options = create_options;
508         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
509         io.ntcreatex.in.share_access = share_access;
510         io.ntcreatex.in.alloc_size = 0;
511         io.ntcreatex.in.open_disposition = open_disposition;
512         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
513         io.ntcreatex.in.security_flags = 0;
514         io.ntcreatex.in.fname = filename;
515         
516         status = smb_raw_open(spdata->tree, mem_ctx, &io);
517         talloc_free(mem_ctx);
518
519         PyErr_NTSTATUS_IS_ERR_RAISE(status);
520
521         fnum = io.ntcreatex.out.file.fnum;
522
523         return Py_BuildValue("i", fnum);
524 }
525
526 /*
527  * Close the file based on the fnum passed in
528  */
529 static PyObject *py_close_file(PyObject *self, PyObject *args, PyObject *kwargs)
530 {
531         struct smb_private_data *spdata;
532         int fnum;
533
534         if (!PyArg_ParseTuple(args, "i:close_file", &fnum)) {
535                 return NULL;
536         }
537
538         spdata = pytalloc_get_ptr(self);
539
540         /*
541          * Should check the status ...
542          */
543         smbcli_close(spdata->tree, fnum);
544
545         Py_RETURN_NONE;
546 }
547
548 static PyMethodDef py_smb_methods[] = {
549         { "loadfile", py_smb_loadfile, METH_VARARGS,
550                 "loadfile(path) -> file contents as a "
551                 PY_DESC_PY3_BYTES
552                 "\n\n Read contents of a file." },
553         { "savefile", py_smb_savefile, METH_VARARGS,
554                 "savefile(path, str) -> None\n\n Write "
555                 PY_DESC_PY3_BYTES
556                 " str to file." },
557         { "list", (PyCFunction)py_smb_list, METH_VARARGS|METH_KEYWORDS,
558                 "list(path, access_mask='*', attribs=DEFAULT_ATTRS) -> \
559 directory contents as a dictionary\n \
560                 DEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | \
561 FILE_ATTRIBUTE_DIRECTORY | \
562 FILE_ATTRIBUTE_ARCHIVE\n\n \
563                 List contents of a directory. The keys are, \n \
564                 \tname: Long name of the directory item\n \
565                 \tshort_name: Short name of the directory item\n \
566                 \tsize: File size in bytes\n \
567                 \tattrib: Attributes\n \
568                 \tmtime: Modification time\n" },
569         { "mkdir", py_smb_mkdir, METH_VARARGS,
570                 "mkdir(path) -> None\n\n \
571                 Create a directory." },
572         { "rmdir", py_smb_rmdir, METH_VARARGS,
573                 "rmdir(path) -> None\n\n \
574                 Delete a directory." },
575         { "unlink", py_smb_unlink, METH_VARARGS,
576                 "unlink(path) -> None\n\n \
577                 Delete a file." },
578         { "deltree", py_smb_deltree, METH_VARARGS,
579                 "deltree(path) -> None\n\n \
580                 Delete a directory and all its contents." },
581         { "chkpath", py_smb_chkpath, METH_VARARGS,
582                 "chkpath(path) -> True or False\n\n \
583                 Return true if path exists, false otherwise." },
584         { "get_acl", (PyCFunction)py_smb_getacl, METH_VARARGS,
585                 "get_acl(path[, security_info=0]) -> security_descriptor object\n\n \
586                 Get security descriptor for file." },
587         { "set_acl", (PyCFunction)py_smb_setacl, METH_VARARGS,
588                 "set_acl(path, security_descriptor[, security_info=0]) -> None\n\n \
589                 Set security descriptor for file." },
590         { "open_file", (PyCFunction)py_open_file, METH_VARARGS,
591                 "open_file(path, access_mask[, share_access[, open_disposition[, create_options]]] -> fnum\n\n \
592                 Open a file. Throws NTSTATUS exceptions on errors." },
593         { "close_file", (PyCFunction)py_close_file, METH_VARARGS,
594                 "close_file(fnum) -> None\n\n \
595                 Close the file based on fnum."},
596         { NULL },
597 };
598
599 static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
600 {
601         PyObject *py_creds = Py_None;
602         PyObject *py_lp = Py_None;
603         const char *kwnames[] = { "hostname", "service", "creds", "lp",
604                                   "ntlmv2_auth", "use_spnego", "sign", NULL };
605         const char *hostname = NULL;
606         const char *service = NULL;
607         PyObject *smb;
608         struct smb_private_data *spdata;
609         NTSTATUS status;
610         TALLOC_CTX *frame = NULL;
611         struct smbcli_options options;
612         struct smbcli_session_options session_options;
613         uint8_t ntlmv2_auth = 0xFF;
614         uint8_t use_spnego = 0xFF;
615         PyObject *sign = Py_False;
616
617         /*
618          * These Python bindings are now deprecated because the s4 SMB client
619          * code doesn't support SMBv2 (and is unlikely to ever support it).
620          * The s3 libsmb_samba_internal bindings are a better choice for use
621          * within the Samba codebase, and support much the same API.
622          * This warning is mostly for external consumers that might be using
623          * these Python bindings (in which case, note libsmb_samba_internal
624          * is not a stable API and may change in future).
625          */
626         DBG_ERR("The smb.SMB() Python bindings are now deprecated "
627                 "and will be removed in the next samba release\n");
628
629         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OObbO",
630                                          discard_const_p(char *, kwnames),
631                                          &hostname, &service, &py_creds, &py_lp,
632                                          &ntlmv2_auth, &use_spnego, &sign)) {
633                 return NULL;
634         }
635
636         frame = talloc_stackframe();
637
638         spdata = talloc_zero(frame, struct smb_private_data);
639         if (spdata == NULL) {
640                 PyErr_NoMemory();
641                 TALLOC_FREE(frame);
642                 return NULL;
643         }
644
645         spdata->lp_ctx = lpcfg_from_py_object(spdata, py_lp);
646         if (spdata->lp_ctx == NULL) {
647                 PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
648                 TALLOC_FREE(frame);
649                 return NULL;
650         }
651
652         spdata->creds = cli_credentials_from_py_object(py_creds);
653         if (spdata->creds == NULL) {
654                 PyErr_SetString(PyExc_TypeError, "Expected credentials");
655                 TALLOC_FREE(frame);
656                 return NULL;
657         }
658         spdata->ev_ctx = s4_event_context_init(spdata);
659         if (spdata->ev_ctx == NULL) {
660                 PyErr_NoMemory();
661                 TALLOC_FREE(frame);
662                 return NULL;
663         }
664
665         lpcfg_smbcli_options(spdata->lp_ctx, &options);
666         lpcfg_smbcli_session_options(spdata->lp_ctx, &session_options);
667
668         if (ntlmv2_auth != 0xFF) {
669                 session_options.ntlmv2_auth = ntlmv2_auth;
670         }
671         if (use_spnego != 0xFF) {
672                 options.use_spnego = use_spnego;
673         }
674         if (PyObject_IsTrue(sign)) {
675                 options.signing = SMB_SIGNING_REQUIRED;
676         }
677
678         status = do_smb_connect(spdata, spdata, hostname, service,
679                                 &options,
680                                 &session_options,
681                                 &spdata->tree);
682         PyErr_NTSTATUS_IS_ERR_RAISE(status);
683         if (spdata->tree == NULL) {
684                 TALLOC_FREE(frame);
685                 return NULL;
686         }
687
688         smb = pytalloc_steal(type, spdata);
689         TALLOC_FREE(frame);
690         return smb;
691 }
692
693 static PyTypeObject PySMB = {
694         .tp_name = "smb.SMB",
695         .tp_new = py_smb_new,
696         .tp_flags = Py_TPFLAGS_DEFAULT,
697         .tp_methods = py_smb_methods,
698         .tp_doc = "SMB(hostname, service[, creds[, lp]]) -> SMB connection object\n",
699
700 };
701
702 static struct PyModuleDef moduledef = {
703     PyModuleDef_HEAD_INIT,
704     .m_name = "smb",
705     .m_doc = "SMB File I/O support",
706     .m_size = -1,
707     .m_methods = NULL,
708 };
709
710 void initsmb(void);
711
712 MODULE_INIT_FUNC(smb)
713 {
714         PyObject *m = NULL;
715
716         if (pytalloc_BaseObject_PyType_Ready(&PySMB) < 0) {
717                 return m;
718         }
719
720         m = PyModule_Create(&moduledef);
721         if (m == NULL) {
722             return m;
723         }
724
725         Py_INCREF(&PySMB);
726         PyModule_AddObject(m, "SMB", (PyObject *)&PySMB);
727
728 #define ADD_FLAGS(val)  PyModule_AddObject(m, #val, PyInt_FromLong(val))
729
730         ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
731         ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
732         ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
733         ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
734         ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
735         ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
736         ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
737         ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
738         ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
739         ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
740         ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
741         ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
742         ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
743         ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
744         ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
745         ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
746         return m;
747 }