2 Unix SMB/CIFS implementation.
4 Copyright (C) Amitay Isaacs 2011
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.
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.
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/>.
24 #include "param/param.h"
25 #include "param/pyparam.h"
26 #include "system/dir.h"
27 #include "lib/events/events.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/credentials/pycredentials.h"
30 #include "auth/gensec/gensec.h"
31 #include "libcli/libcli.h"
32 #include "libcli/raw/libcliraw.h"
33 #include "libcli/raw/raw_proto.h"
34 #include "libcli/resolve/resolve.h"
35 #include "libcli/util/pyerrors.h"
36 #include "libcli/smb_composite/smb_composite.h"
37 #include "libcli/security/security_descriptor.h"
38 #include "librpc/rpc/pyrpc_util.h"
40 #ifndef Py_RETURN_NONE
41 #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
44 staticforward PyTypeObject PySMB;
48 struct smb_private_data {
49 struct loadparm_context *lp_ctx;
50 struct cli_credentials *creds;
51 struct tevent_context *ev_ctx;
52 struct smbcli_tree *tree;
56 static void dos_format(char *s)
58 string_replace(s, '/', '\\');
62 static struct smbcli_tree *do_smb_connect(TALLOC_CTX *mem_ctx, struct smb_private_data *spdata,
63 const char *hostname, const char *service)
65 struct smb_composite_connect io;
70 io.in.dest_host = hostname;
72 io.in.dest_ports = lpcfg_smb_ports(spdata->lp_ctx);
73 io.in.socket_options = lpcfg_socket_options(spdata->lp_ctx);
74 io.in.gensec_settings = lpcfg_gensec_settings(mem_ctx, spdata->lp_ctx);
76 io.in.called_name = lpcfg_netbios_name(spdata->lp_ctx);
77 io.in.workgroup = lpcfg_workgroup(spdata->lp_ctx);
79 lpcfg_smbcli_options(spdata->lp_ctx, &io.in.options);
80 lpcfg_smbcli_session_options(spdata->lp_ctx, &io.in.session_options);
82 io.in.service = service;
83 io.in.service_type = NULL;
85 io.in.credentials = spdata->creds;
86 io.in.fallback_to_anonymous = false;
88 status = smb_composite_connect(&io, mem_ctx,
89 lpcfg_resolve_context(spdata->lp_ctx),
91 PyErr_NTSTATUS_IS_ERR_RAISE(status);
97 static PyObject * py_smb_loadfile(py_talloc_Object *self, PyObject *args)
99 struct smb_composite_loadfile io;
100 const char *filename;
102 struct smb_private_data *spdata;
104 if (!PyArg_ParseTuple(args, "s", &filename)) {
108 io.in.fname = filename;
111 status = smb_composite_loadfile(spdata->tree, self->talloc_ctx, &io);
112 PyErr_NTSTATUS_IS_ERR_RAISE(status);
114 return Py_BuildValue("s#", io.out.data, io.out.size);
118 static PyObject * py_smb_savefile(py_talloc_Object *self, PyObject *args)
120 struct smb_composite_savefile io;
121 const char *filename;
124 struct smb_private_data *spdata;
126 if (!PyArg_ParseTuple(args, "ss", &filename, &data)) {
130 io.in.fname = filename;
131 io.in.data = (unsigned char *)data;
132 io.in.size = strlen(data);
135 status = smb_composite_savefile(spdata->tree, &io);
136 PyErr_NTSTATUS_IS_ERR_RAISE(status);
141 static void py_smb_list_callback(struct clilist_file_info *f, const char *mask, void *state)
143 PyObject *py_dirlist;
146 if(!ISDOT(f->name) && !ISDOTDOT(f->name)) {
147 py_dirlist = (PyObject *)state;
151 PyDict_SetItemString(dict, "name", PyString_FromString(f->name));
152 PyDict_SetItemString(dict, "short_name", PyString_FromString(f->short_name));
153 PyDict_SetItemString(dict, "size", PyLong_FromUnsignedLongLong(f->size));
154 PyDict_SetItemString(dict, "attrib", PyInt_FromLong(f->attrib));
155 PyDict_SetItemString(dict, "mtime", PyInt_FromLong(f->mtime));
157 PyList_Append(py_dirlist, dict);
163 static PyObject *py_smb_list(py_talloc_Object *self, PyObject *args, PyObject *kwargs)
165 struct smb_private_data *spdata;
166 PyObject *py_dirlist;
167 const char *kwnames[] = { "directory", "mask", "attribs", NULL };
169 char *user_mask = NULL;
170 uint16_t attribute = 0;
173 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|sH",
174 discard_const_p(char *, kwnames),
175 &base_dir, &user_mask, &attribute)) {
179 if (attribute == 0) {
180 attribute = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
181 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY |
182 FILE_ATTRIBUTE_ARCHIVE;
185 if (user_mask == NULL) {
186 mask = talloc_asprintf(self->talloc_ctx, "%s\\*", base_dir);
188 mask = talloc_asprintf(self->talloc_ctx, "%s\\%s", base_dir, user_mask);
194 if((py_dirlist = PyList_New(0)) == NULL) {
199 smbcli_list(spdata->tree, mask, attribute, py_smb_list_callback, (void *)py_dirlist);
206 static PyObject *py_smb_getacl(py_talloc_Object *self, PyObject *args, PyObject *kwargs)
209 union smb_fileinfo io;
210 struct smb_private_data *spdata;
211 const char *filename;
213 if (!PyArg_ParseTuple(args, "s", &filename)) {
219 io.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
220 io.query_secdesc.in.file.path = filename;
221 io.query_secdesc.in.secinfo_flags = 0;
223 status = smb_raw_query_secdesc(spdata->tree, self->talloc_ctx, &io);
224 PyErr_NTSTATUS_IS_ERR_RAISE(status);
226 return py_return_ndr_struct("samba.dcerpc.security", "descriptor",
227 self->talloc_ctx, io.query_secdesc.out.sd);
231 static PyObject *py_smb_setacl(py_talloc_Object *self, PyObject *args, PyObject *kwargs)
234 union smb_setfileinfo io;
235 struct smb_private_data *spdata;
236 const char *filename;
238 struct security_descriptor *sd;
240 if (!PyArg_ParseTuple(args, "sO", &filename, &py_sd)) {
246 sd = py_talloc_get_type(py_sd, struct security_descriptor);
248 PyErr_Format(PyExc_TypeError,
249 "Expected dcerpc.security.descriptor for security_descriptor argument, got %s", talloc_get_name(py_talloc_get_ptr(py_sd)));
253 io.set_secdesc.level = RAW_SFILEINFO_SEC_DESC;
254 io.set_secdesc.in.file.path = filename;
255 io.set_secdesc.in.secinfo_flags = 0;
256 io.set_secdesc.in.sd = sd;
258 status = smb_raw_set_secdesc(spdata->tree, &io);
259 PyErr_NTSTATUS_IS_ERR_RAISE(status);
265 static PyMethodDef py_smb_methods[] = {
266 { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
267 "Read contents of a file" },
268 { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
269 "Write contents to a file" },
270 { "list", (PyCFunction)py_smb_list, METH_VARARGS|METH_KEYWORDS,
271 "List contents of a directory" },
272 { "get_acl", (PyCFunction)py_smb_getacl, METH_VARARGS,
273 "Get security descriptor for a file" },
274 { "set_acl", (PyCFunction)py_smb_setacl, METH_VARARGS,
275 "Set security descriptor for a file" },
280 static PyObject *py_smb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
282 PyObject *py_creds = Py_None;
283 PyObject *py_lp = Py_None;
284 const char *kwnames[] = { "hostname", "service", "creds", "lp", NULL };
285 const char *hostname = NULL;
286 const char *service = NULL;
287 py_talloc_Object *smb;
288 struct smb_private_data *spdata;
290 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zz|OO",
291 discard_const_p(char *, kwnames),
292 &hostname, &service, &py_creds, &py_lp)) {
296 smb = (py_talloc_Object *)type->tp_alloc(type, 0);
301 smb->talloc_ctx = talloc_new(NULL);
302 if (smb->talloc_ctx == NULL) {
307 spdata = talloc_zero(smb->talloc_ctx, struct smb_private_data);
308 if (spdata == NULL) {
314 spdata->lp_ctx = lpcfg_from_py_object(smb->talloc_ctx, py_lp);
315 if (spdata->lp_ctx == NULL) {
319 spdata->creds = PyCredentials_AsCliCredentials(py_creds);
320 spdata->ev_ctx = s4_event_context_init(smb->talloc_ctx);
321 if (spdata->ev_ctx == NULL) {
327 spdata->tree = do_smb_connect(smb->talloc_ctx, spdata, hostname, service);
328 if (spdata->tree == NULL) {
334 return (PyObject *)smb;
338 static PyTypeObject PySMB = {
339 .tp_name = "smb.SMB",
340 .tp_basicsize = sizeof(py_talloc_Object),
341 .tp_new = py_smb_new,
342 .tp_flags = Py_TPFLAGS_DEFAULT,
343 .tp_methods = py_smb_methods,
344 .tp_doc = "Create a SMB connection to <hostname> using <service>",
350 PyTypeObject *talloc_type = PyTalloc_GetObjectType();
351 if (talloc_type == NULL) {
355 PySMB.tp_base = talloc_type;
357 if (PyType_Ready(&PySMB) < 0) {
361 m = Py_InitModule3("smb", NULL, "SMB File I/O support");
367 PyModule_AddObject(m, "SMB", (PyObject *)&PySMB);
369 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyInt_FromLong(val))
371 ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
372 ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
373 ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
374 ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
375 ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
376 ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
377 ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
378 ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
379 ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
380 ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
381 ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
382 ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
383 ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
384 ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
385 ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
386 ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);