pylibsmb: Add smb2 create tag strings
[Samba.git] / source3 / libsmb / pylibsmb.c
blob803e3163b7bfe22a51d76e8f2d0c696211edf544
1 /*
2 * Unix SMB/CIFS implementation.
4 * SMB client Python bindings used internally by Samba (for things like
5 * samba-tool). These Python bindings may change without warning, and so
6 * should not be used outside of the Samba codebase.
8 * Copyright (C) Volker Lendecke 2012
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <Python.h>
25 #include "includes.h"
26 #include "python/py3compat.h"
27 #include "python/modules.h"
28 #include "libcli/smb/smbXcli_base.h"
29 #include "libcli/smb/smb2_negotiate_context.h"
30 #include "libsmb/libsmb.h"
31 #include "libcli/security/security.h"
32 #include "system/select.h"
33 #include "source4/libcli/util/pyerrors.h"
34 #include "auth/credentials/pycredentials.h"
35 #include "trans2.h"
36 #include "libsmb/clirap.h"
37 #include "librpc/rpc/pyrpc_util.h"
39 #define LIST_ATTRIBUTE_MASK \
40 (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
42 static PyTypeObject *dom_sid_Type = NULL;
44 static PyTypeObject *get_pytype(const char *module, const char *type)
46 PyObject *mod;
47 PyTypeObject *result;
49 mod = PyImport_ImportModule(module);
50 if (mod == NULL) {
51 PyErr_Format(PyExc_RuntimeError,
52 "Unable to import %s to check type %s",
53 module, type);
54 return NULL;
56 result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
57 Py_DECREF(mod);
58 if (result == NULL) {
59 PyErr_Format(PyExc_RuntimeError,
60 "Unable to find type %s in module %s",
61 module, type);
62 return NULL;
64 return result;
68 * We're using "const char * const *" for keywords,
69 * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
70 * inevitable warnings to just one place.
72 static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
73 const char *format, const char * const *keywords,
74 ...)
76 char **_keywords = discard_const_p(char *, keywords);
77 va_list a;
78 int ret;
79 va_start(a, keywords);
80 ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
81 _keywords, a);
82 va_end(a);
83 return ret;
86 struct py_cli_thread;
88 struct py_cli_oplock_break {
89 uint16_t fnum;
90 uint8_t level;
93 struct py_cli_state {
94 PyObject_HEAD
95 struct cli_state *cli;
96 struct tevent_context *ev;
97 int (*req_wait_fn)(struct tevent_context *ev,
98 struct tevent_req *req);
99 struct py_cli_thread *thread_state;
101 struct tevent_req *oplock_waiter;
102 struct py_cli_oplock_break *oplock_breaks;
103 struct py_tevent_cond *oplock_cond;
106 #ifdef HAVE_PTHREAD
108 #include <pthread.h>
110 struct py_cli_thread {
113 * Pipe to make the poll thread wake up in our destructor, so
114 * that we can exit and join the thread.
116 int shutdown_pipe[2];
117 struct tevent_fd *shutdown_fde;
118 bool do_shutdown;
119 pthread_t id;
122 * Thread state to release the GIL during the poll(2) syscall
124 PyThreadState *py_threadstate;
127 static void *py_cli_state_poll_thread(void *private_data)
129 struct py_cli_state *self = (struct py_cli_state *)private_data;
130 struct py_cli_thread *t = self->thread_state;
131 PyGILState_STATE gstate;
133 gstate = PyGILState_Ensure();
135 while (!t->do_shutdown) {
136 int ret;
137 ret = tevent_loop_once(self->ev);
138 assert(ret == 0);
140 PyGILState_Release(gstate);
141 return NULL;
144 static void py_cli_state_trace_callback(enum tevent_trace_point point,
145 void *private_data)
147 struct py_cli_state *self = (struct py_cli_state *)private_data;
148 struct py_cli_thread *t = self->thread_state;
150 switch(point) {
151 case TEVENT_TRACE_BEFORE_WAIT:
152 assert(t->py_threadstate == NULL);
153 t->py_threadstate = PyEval_SaveThread();
154 break;
155 case TEVENT_TRACE_AFTER_WAIT:
156 assert(t->py_threadstate != NULL);
157 PyEval_RestoreThread(t->py_threadstate);
158 t->py_threadstate = NULL;
159 break;
160 default:
161 break;
165 static void py_cli_state_shutdown_handler(struct tevent_context *ev,
166 struct tevent_fd *fde,
167 uint16_t flags,
168 void *private_data)
170 struct py_cli_state *self = (struct py_cli_state *)private_data;
171 struct py_cli_thread *t = self->thread_state;
173 if ((flags & TEVENT_FD_READ) == 0) {
174 return;
176 TALLOC_FREE(t->shutdown_fde);
177 t->do_shutdown = true;
180 static int py_cli_thread_destructor(struct py_cli_thread *t)
182 char c = 0;
183 ssize_t written;
184 int ret;
186 do {
188 * This will wake the poll thread from the poll(2)
190 written = write(t->shutdown_pipe[1], &c, 1);
191 } while ((written == -1) && (errno == EINTR));
194 * Allow the poll thread to do its own cleanup under the GIL
196 Py_BEGIN_ALLOW_THREADS
197 ret = pthread_join(t->id, NULL);
198 Py_END_ALLOW_THREADS
199 assert(ret == 0);
201 if (t->shutdown_pipe[0] != -1) {
202 close(t->shutdown_pipe[0]);
203 t->shutdown_pipe[0] = -1;
205 if (t->shutdown_pipe[1] != -1) {
206 close(t->shutdown_pipe[1]);
207 t->shutdown_pipe[1] = -1;
209 return 0;
212 static int py_tevent_cond_req_wait(struct tevent_context *ev,
213 struct tevent_req *req);
215 static bool py_cli_state_setup_mt_ev(struct py_cli_state *self)
217 struct py_cli_thread *t = NULL;
218 int ret;
220 self->ev = tevent_context_init_byname(NULL, "poll_mt");
221 if (self->ev == NULL) {
222 goto fail;
224 samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
225 tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
227 self->req_wait_fn = py_tevent_cond_req_wait;
229 self->thread_state = talloc_zero(NULL, struct py_cli_thread);
230 if (self->thread_state == NULL) {
231 goto fail;
233 t = self->thread_state;
235 ret = pipe(t->shutdown_pipe);
236 if (ret == -1) {
237 goto fail;
239 t->shutdown_fde = tevent_add_fd(
240 self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ,
241 py_cli_state_shutdown_handler, self);
242 if (t->shutdown_fde == NULL) {
243 goto fail;
246 PyEval_InitThreads();
248 ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
249 if (ret != 0) {
250 goto fail;
252 talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
253 return true;
255 fail:
256 if (t != NULL) {
257 TALLOC_FREE(t->shutdown_fde);
259 if (t->shutdown_pipe[0] != -1) {
260 close(t->shutdown_pipe[0]);
261 t->shutdown_pipe[0] = -1;
263 if (t->shutdown_pipe[1] != -1) {
264 close(t->shutdown_pipe[1]);
265 t->shutdown_pipe[1] = -1;
269 TALLOC_FREE(self->thread_state);
270 TALLOC_FREE(self->ev);
271 return false;
274 struct py_tevent_cond {
275 pthread_mutex_t mutex;
276 pthread_cond_t cond;
277 bool is_done;
280 static void py_tevent_signalme(struct tevent_req *req);
282 static int py_tevent_cond_wait(struct py_tevent_cond *cond)
284 int ret, result;
286 result = pthread_mutex_init(&cond->mutex, NULL);
287 if (result != 0) {
288 goto fail;
290 result = pthread_cond_init(&cond->cond, NULL);
291 if (result != 0) {
292 goto fail_mutex;
295 result = pthread_mutex_lock(&cond->mutex);
296 if (result != 0) {
297 goto fail_cond;
300 cond->is_done = false;
302 while (!cond->is_done) {
304 Py_BEGIN_ALLOW_THREADS
305 result = pthread_cond_wait(&cond->cond, &cond->mutex);
306 Py_END_ALLOW_THREADS
308 if (result != 0) {
309 goto fail_unlock;
313 fail_unlock:
314 ret = pthread_mutex_unlock(&cond->mutex);
315 assert(ret == 0);
316 fail_cond:
317 ret = pthread_cond_destroy(&cond->cond);
318 assert(ret == 0);
319 fail_mutex:
320 ret = pthread_mutex_destroy(&cond->mutex);
321 assert(ret == 0);
322 fail:
323 return result;
326 static int py_tevent_cond_req_wait(struct tevent_context *ev,
327 struct tevent_req *req)
329 struct py_tevent_cond cond;
330 tevent_req_set_callback(req, py_tevent_signalme, &cond);
331 return py_tevent_cond_wait(&cond);
334 static void py_tevent_cond_signal(struct py_tevent_cond *cond)
336 int ret;
338 ret = pthread_mutex_lock(&cond->mutex);
339 assert(ret == 0);
341 cond->is_done = true;
343 ret = pthread_cond_signal(&cond->cond);
344 assert(ret == 0);
345 ret = pthread_mutex_unlock(&cond->mutex);
346 assert(ret == 0);
349 static void py_tevent_signalme(struct tevent_req *req)
351 struct py_tevent_cond *cond = (struct py_tevent_cond *)
352 tevent_req_callback_data_void(req);
354 py_tevent_cond_signal(cond);
357 #endif
359 static int py_tevent_req_wait(struct tevent_context *ev,
360 struct tevent_req *req);
362 static bool py_cli_state_setup_ev(struct py_cli_state *self)
364 self->ev = tevent_context_init(NULL);
365 if (self->ev == NULL) {
366 return false;
369 samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
371 self->req_wait_fn = py_tevent_req_wait;
373 return true;
376 static int py_tevent_req_wait(struct tevent_context *ev,
377 struct tevent_req *req)
379 while (tevent_req_is_in_progress(req)) {
380 int ret;
382 ret = tevent_loop_once(ev);
383 if (ret != 0) {
384 return ret;
387 return 0;
390 static bool py_tevent_req_wait_exc(struct py_cli_state *self,
391 struct tevent_req *req)
393 int ret;
395 if (req == NULL) {
396 PyErr_NoMemory();
397 return false;
399 ret = self->req_wait_fn(self->ev, req);
400 if (ret != 0) {
401 TALLOC_FREE(req);
402 errno = ret;
403 PyErr_SetFromErrno(PyExc_RuntimeError);
404 return false;
406 return true;
409 static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
410 PyObject *kwds)
412 struct py_cli_state *self;
414 self = (struct py_cli_state *)type->tp_alloc(type, 0);
415 if (self == NULL) {
416 return NULL;
418 self->cli = NULL;
419 self->ev = NULL;
420 self->thread_state = NULL;
421 self->oplock_waiter = NULL;
422 self->oplock_cond = NULL;
423 self->oplock_breaks = NULL;
424 return (PyObject *)self;
427 static struct smb2_negotiate_contexts *py_cli_get_negotiate_contexts(
428 TALLOC_CTX *mem_ctx, PyObject *list)
430 struct smb2_negotiate_contexts *ctxs = NULL;
431 Py_ssize_t i, len;
432 int ret;
434 ret = PyList_Check(list);
435 if (!ret) {
436 goto fail;
439 len = PyList_Size(list);
440 if (len == 0) {
441 goto fail;
444 ctxs = talloc_zero(mem_ctx, struct smb2_negotiate_contexts);
445 if (ctxs == NULL) {
446 goto fail;
449 for (i=0; i<len; i++) {
450 NTSTATUS status;
452 PyObject *t = PyList_GetItem(list, i);
453 Py_ssize_t tlen;
455 PyObject *ptype = NULL;
456 long type;
458 PyObject *pdata = NULL;
459 DATA_BLOB data = { .data = NULL, };
461 if (t == NULL) {
462 goto fail;
465 ret = PyTuple_Check(t);
466 if (!ret) {
467 goto fail;
470 tlen = PyTuple_Size(t);
471 if (tlen != 2) {
472 goto fail;
475 ptype = PyTuple_GetItem(t, 0);
476 if (ptype == NULL) {
477 goto fail;
479 type = PyLong_AsLong(ptype);
480 if ((type < 0) || (type > UINT16_MAX)) {
481 goto fail;
484 pdata = PyTuple_GetItem(t, 1);
486 ret = PyBytes_Check(pdata);
487 if (!ret) {
488 goto fail;
491 data.data = (uint8_t *)PyBytes_AsString(pdata);
492 data.length = PyBytes_Size(pdata);
494 status = smb2_negotiate_context_add(
495 ctxs, ctxs, type, data.data, data.length);
496 if (!NT_STATUS_IS_OK(status)) {
497 goto fail;
500 return ctxs;
502 fail:
503 TALLOC_FREE(ctxs);
504 return NULL;
507 static void py_cli_got_oplock_break(struct tevent_req *req);
509 static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
510 PyObject *kwds)
512 NTSTATUS status;
513 char *host, *share;
514 PyObject *creds = NULL;
515 struct cli_credentials *cli_creds;
516 PyObject *py_lp = Py_None;
517 PyObject *py_multi_threaded = Py_False;
518 bool multi_threaded = false;
519 PyObject *py_force_smb1 = Py_False;
520 bool force_smb1 = false;
521 PyObject *py_ipc = Py_False;
522 PyObject *py_posix = Py_False;
523 PyObject *py_negotiate_contexts = NULL;
524 struct smb2_negotiate_contexts *negotiate_contexts = NULL;
525 bool use_ipc = false;
526 bool request_posix = false;
527 struct tevent_req *req;
528 bool ret;
529 int flags = 0;
531 static const char *kwlist[] = {
532 "host", "share", "lp", "creds",
533 "multi_threaded", "force_smb1",
534 "ipc",
535 "posix",
536 "negotiate_contexts",
537 NULL
540 PyTypeObject *py_type_Credentials = get_pytype(
541 "samba.credentials", "Credentials");
542 if (py_type_Credentials == NULL) {
543 return -1;
546 ret = ParseTupleAndKeywords(
547 args, kwds, "ssO|O!OOOOO", kwlist,
548 &host, &share, &py_lp,
549 py_type_Credentials, &creds,
550 &py_multi_threaded,
551 &py_force_smb1,
552 &py_ipc,
553 &py_posix,
554 &py_negotiate_contexts);
556 Py_DECREF(py_type_Credentials);
558 if (!ret) {
559 return -1;
562 multi_threaded = PyObject_IsTrue(py_multi_threaded);
563 force_smb1 = PyObject_IsTrue(py_force_smb1);
565 if (force_smb1) {
567 * As most of the cli_*_send() function
568 * don't support SMB2 (it's only plugged
569 * into the sync wrapper functions currently)
570 * we have a way to force SMB1.
572 flags = CLI_FULL_CONNECTION_FORCE_SMB1;
575 use_ipc = PyObject_IsTrue(py_ipc);
576 if (use_ipc) {
577 flags |= CLI_FULL_CONNECTION_IPC;
580 request_posix = PyObject_IsTrue(py_posix);
581 if (request_posix) {
582 flags |= CLI_FULL_CONNECTION_REQUEST_POSIX;
585 if (py_negotiate_contexts != NULL) {
586 negotiate_contexts = py_cli_get_negotiate_contexts(
587 talloc_tos(), py_negotiate_contexts);
588 if (negotiate_contexts == NULL) {
589 return -1;
593 if (multi_threaded) {
594 #ifdef HAVE_PTHREAD
595 ret = py_cli_state_setup_mt_ev(self);
596 if (!ret) {
597 return -1;
599 #else
600 PyErr_SetString(PyExc_RuntimeError,
601 "No PTHREAD support available");
602 return -1;
603 #endif
604 } else {
605 ret = py_cli_state_setup_ev(self);
606 if (!ret) {
607 return -1;
611 if (creds == NULL) {
612 cli_creds = cli_credentials_init_anon(NULL);
613 } else {
614 cli_creds = PyCredentials_AsCliCredentials(creds);
617 req = cli_full_connection_creds_send(
618 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
619 cli_creds, flags,
620 negotiate_contexts);
621 if (!py_tevent_req_wait_exc(self, req)) {
622 return -1;
624 status = cli_full_connection_creds_recv(req, &self->cli);
625 TALLOC_FREE(req);
627 if (!NT_STATUS_IS_OK(status)) {
628 PyErr_SetNTSTATUS(status);
629 return -1;
633 * Oplocks require a multi threaded connection
635 if (self->thread_state == NULL) {
636 return 0;
639 self->oplock_waiter = cli_smb_oplock_break_waiter_send(
640 self->ev, self->ev, self->cli);
641 if (self->oplock_waiter == NULL) {
642 PyErr_NoMemory();
643 return -1;
645 tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
646 self);
647 return 0;
650 static void py_cli_got_oplock_break(struct tevent_req *req)
652 struct py_cli_state *self = (struct py_cli_state *)
653 tevent_req_callback_data_void(req);
654 struct py_cli_oplock_break b;
655 struct py_cli_oplock_break *tmp;
656 size_t num_breaks;
657 NTSTATUS status;
659 status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
660 TALLOC_FREE(req);
661 self->oplock_waiter = NULL;
663 if (!NT_STATUS_IS_OK(status)) {
664 return;
667 num_breaks = talloc_array_length(self->oplock_breaks);
668 tmp = talloc_realloc(self->ev, self->oplock_breaks,
669 struct py_cli_oplock_break, num_breaks+1);
670 if (tmp == NULL) {
671 return;
673 self->oplock_breaks = tmp;
674 self->oplock_breaks[num_breaks] = b;
676 if (self->oplock_cond != NULL) {
677 py_tevent_cond_signal(self->oplock_cond);
680 self->oplock_waiter = cli_smb_oplock_break_waiter_send(
681 self->ev, self->ev, self->cli);
682 if (self->oplock_waiter == NULL) {
683 return;
685 tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
686 self);
689 static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
690 PyObject *args)
692 size_t num_oplock_breaks;
694 if (!PyArg_ParseTuple(args, "")) {
695 return NULL;
698 if (self->thread_state == NULL) {
699 PyErr_SetString(PyExc_RuntimeError,
700 "get_oplock_break() only possible on "
701 "a multi_threaded connection");
702 return NULL;
705 if (self->oplock_cond != NULL) {
706 errno = EBUSY;
707 PyErr_SetFromErrno(PyExc_RuntimeError);
708 return NULL;
711 num_oplock_breaks = talloc_array_length(self->oplock_breaks);
713 if (num_oplock_breaks == 0) {
714 struct py_tevent_cond cond;
715 int ret;
717 self->oplock_cond = &cond;
718 ret = py_tevent_cond_wait(&cond);
719 self->oplock_cond = NULL;
721 if (ret != 0) {
722 errno = ret;
723 PyErr_SetFromErrno(PyExc_RuntimeError);
724 return NULL;
728 num_oplock_breaks = talloc_array_length(self->oplock_breaks);
729 if (num_oplock_breaks > 0) {
730 PyObject *result;
732 result = Py_BuildValue(
733 "{s:i,s:i}",
734 "fnum", self->oplock_breaks[0].fnum,
735 "level", self->oplock_breaks[0].level);
737 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
738 sizeof(self->oplock_breaks[0]) *
739 (num_oplock_breaks - 1));
740 self->oplock_breaks = talloc_realloc(
741 NULL, self->oplock_breaks, struct py_cli_oplock_break,
742 num_oplock_breaks - 1);
744 return result;
746 Py_RETURN_NONE;
749 static void py_cli_state_dealloc(struct py_cli_state *self)
751 TALLOC_FREE(self->thread_state);
752 TALLOC_FREE(self->oplock_waiter);
753 TALLOC_FREE(self->ev);
755 if (self->cli != NULL) {
756 cli_shutdown(self->cli);
757 self->cli = NULL;
759 Py_TYPE(self)->tp_free((PyObject *)self);
762 static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
764 unsigned int nmsecs = 0;
765 unsigned int omsecs = 0;
767 if (!PyArg_ParseTuple(args, "I", &nmsecs)) {
768 return NULL;
771 omsecs = cli_set_timeout(self->cli, nmsecs);
773 return PyLong_FromLong(omsecs);
776 static PyObject *py_cli_echo(struct py_cli_state *self,
777 PyObject *Py_UNUSED(ignored))
779 DATA_BLOB data = data_blob_string_const("keepalive");
780 struct tevent_req *req = NULL;
781 NTSTATUS status;
783 req = cli_echo_send(NULL, self->ev, self->cli, 1, data);
784 if (!py_tevent_req_wait_exc(self, req)) {
785 return NULL;
787 status = cli_echo_recv(req);
788 TALLOC_FREE(req);
789 PyErr_NTSTATUS_NOT_OK_RAISE(status);
791 Py_RETURN_NONE;
794 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
795 PyObject *kwds)
797 char *fname;
798 unsigned CreateFlags = 0;
799 unsigned DesiredAccess = FILE_GENERIC_READ;
800 unsigned FileAttributes = 0;
801 unsigned ShareAccess = 0;
802 unsigned CreateDisposition = FILE_OPEN;
803 unsigned CreateOptions = 0;
804 unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
805 unsigned SecurityFlags = 0;
806 uint16_t fnum;
807 struct tevent_req *req;
808 NTSTATUS status;
810 static const char *kwlist[] = {
811 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
812 "ShareAccess", "CreateDisposition", "CreateOptions",
813 "ImpersonationLevel", "SecurityFlags", NULL };
815 if (!ParseTupleAndKeywords(
816 args, kwds, "s|IIIIIIII", kwlist,
817 &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
818 &ShareAccess, &CreateDisposition, &CreateOptions,
819 &ImpersonationLevel, &SecurityFlags)) {
820 return NULL;
823 req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
824 DesiredAccess, FileAttributes, ShareAccess,
825 CreateDisposition, CreateOptions,
826 ImpersonationLevel, SecurityFlags);
827 if (!py_tevent_req_wait_exc(self, req)) {
828 return NULL;
830 status = cli_ntcreate_recv(req, &fnum, NULL);
831 TALLOC_FREE(req);
833 if (!NT_STATUS_IS_OK(status)) {
834 PyErr_SetNTSTATUS(status);
835 return NULL;
837 return Py_BuildValue("I", (unsigned)fnum);
840 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
842 struct tevent_req *req;
843 int fnum;
844 NTSTATUS status;
846 if (!PyArg_ParseTuple(args, "i", &fnum)) {
847 return NULL;
850 req = cli_close_send(NULL, self->ev, self->cli, fnum);
851 if (!py_tevent_req_wait_exc(self, req)) {
852 return NULL;
854 status = cli_close_recv(req);
855 TALLOC_FREE(req);
857 if (!NT_STATUS_IS_OK(status)) {
858 PyErr_SetNTSTATUS(status);
859 return NULL;
861 Py_RETURN_NONE;
864 static PyObject *py_cli_rename(
865 struct py_cli_state *self, PyObject *args, PyObject *kwds)
867 char *fname_src = NULL, *fname_dst = NULL;
868 int replace = false;
869 struct tevent_req *req = NULL;
870 NTSTATUS status;
871 bool ok;
873 static const char *kwlist[] = { "src", "dst", "replace", NULL };
875 ok = ParseTupleAndKeywords(
876 args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
877 if (!ok) {
878 return NULL;
881 req = cli_rename_send(
882 NULL, self->ev, self->cli, fname_src, fname_dst, replace);
883 if (!py_tevent_req_wait_exc(self, req)) {
884 return NULL;
886 status = cli_rename_recv(req);
887 TALLOC_FREE(req);
889 if (!NT_STATUS_IS_OK(status)) {
890 PyErr_SetNTSTATUS(status);
891 return NULL;
893 Py_RETURN_NONE;
897 struct push_state {
898 char *data;
899 off_t nread;
900 off_t total_data;
904 * cli_push() helper to write a chunk of data to a remote file
906 static size_t push_data(uint8_t *buf, size_t n, void *priv)
908 struct push_state *state = (struct push_state *)priv;
909 char *curr_ptr = NULL;
910 off_t remaining;
911 size_t copied_bytes;
913 if (state->nread >= state->total_data) {
914 return 0;
917 curr_ptr = state->data + state->nread;
918 remaining = state->total_data - state->nread;
919 copied_bytes = MIN(remaining, n);
921 memcpy(buf, curr_ptr, copied_bytes);
922 state->nread += copied_bytes;
923 return copied_bytes;
927 * Writes a file with the contents specified
929 static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
931 uint16_t fnum;
932 const char *filename = NULL;
933 char *data = NULL;
934 Py_ssize_t size = 0;
935 NTSTATUS status;
936 struct tevent_req *req = NULL;
937 struct push_state state;
939 if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
940 &data, &size)) {
941 return NULL;
944 /* create a new file handle for writing to */
945 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
946 FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
947 FILE_SHARE_READ|FILE_SHARE_WRITE,
948 FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
949 SMB2_IMPERSONATION_IMPERSONATION, 0);
950 if (!py_tevent_req_wait_exc(self, req)) {
951 return NULL;
953 status = cli_ntcreate_recv(req, &fnum, NULL);
954 TALLOC_FREE(req);
955 PyErr_NTSTATUS_NOT_OK_RAISE(status);
957 /* write the new file contents */
958 state.data = data;
959 state.nread = 0;
960 state.total_data = size;
962 req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
963 push_data, &state);
964 if (!py_tevent_req_wait_exc(self, req)) {
965 return NULL;
967 status = cli_push_recv(req);
968 TALLOC_FREE(req);
969 PyErr_NTSTATUS_NOT_OK_RAISE(status);
971 /* close the file handle */
972 req = cli_close_send(NULL, self->ev, self->cli, fnum);
973 if (!py_tevent_req_wait_exc(self, req)) {
974 return NULL;
976 status = cli_close_recv(req);
977 PyErr_NTSTATUS_NOT_OK_RAISE(status);
979 Py_RETURN_NONE;
982 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
983 PyObject *kwds)
985 int fnum;
986 unsigned mode = 0;
987 char *buf;
988 Py_ssize_t buflen;
989 unsigned long long offset;
990 struct tevent_req *req;
991 NTSTATUS status;
992 size_t written;
994 static const char *kwlist[] = {
995 "fnum", "buffer", "offset", "mode", NULL };
997 if (!ParseTupleAndKeywords(
998 args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
999 &fnum, &buf, &buflen, &offset, &mode)) {
1000 return NULL;
1003 req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
1004 (uint8_t *)buf, offset, buflen);
1005 if (!py_tevent_req_wait_exc(self, req)) {
1006 return NULL;
1008 status = cli_write_recv(req, &written);
1009 TALLOC_FREE(req);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 PyErr_SetNTSTATUS(status);
1013 return NULL;
1015 return Py_BuildValue("K", (unsigned long long)written);
1019 * Returns the size of the given file
1021 static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
1022 off_t *size)
1024 NTSTATUS status;
1025 struct tevent_req *req = NULL;
1027 req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
1028 if (!py_tevent_req_wait_exc(self, req)) {
1029 return NT_STATUS_INTERNAL_ERROR;
1031 status = cli_qfileinfo_basic_recv(
1032 req, NULL, size, NULL, NULL, NULL, NULL, NULL);
1033 TALLOC_FREE(req);
1034 return status;
1038 * Loads the specified file's contents and returns it
1040 static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
1042 NTSTATUS status;
1043 const char *filename = NULL;
1044 struct tevent_req *req = NULL;
1045 uint16_t fnum;
1046 off_t size;
1047 char *buf = NULL;
1048 off_t nread = 0;
1049 PyObject *result = NULL;
1051 if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
1052 return NULL;
1055 /* get a read file handle */
1056 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1057 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
1058 FILE_ATTRIBUTE_NORMAL,
1059 FILE_SHARE_READ, FILE_OPEN, 0,
1060 SMB2_IMPERSONATION_IMPERSONATION, 0);
1061 if (!py_tevent_req_wait_exc(self, req)) {
1062 return NULL;
1064 status = cli_ntcreate_recv(req, &fnum, NULL);
1065 TALLOC_FREE(req);
1066 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1068 /* get a buffer to hold the file contents */
1069 status = py_smb_filesize(self, fnum, &size);
1070 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1072 result = PyBytes_FromStringAndSize(NULL, size);
1073 if (result == NULL) {
1074 return NULL;
1077 /* read the file contents */
1078 buf = PyBytes_AS_STRING(result);
1079 req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
1080 size, cli_read_sink, &buf);
1081 if (!py_tevent_req_wait_exc(self, req)) {
1082 Py_XDECREF(result);
1083 return NULL;
1085 status = cli_pull_recv(req, &nread);
1086 TALLOC_FREE(req);
1087 if (!NT_STATUS_IS_OK(status)) {
1088 Py_XDECREF(result);
1089 PyErr_SetNTSTATUS(status);
1090 return NULL;
1093 /* close the file handle */
1094 req = cli_close_send(NULL, self->ev, self->cli, fnum);
1095 if (!py_tevent_req_wait_exc(self, req)) {
1096 Py_XDECREF(result);
1097 return NULL;
1099 status = cli_close_recv(req);
1100 TALLOC_FREE(req);
1101 if (!NT_STATUS_IS_OK(status)) {
1102 Py_XDECREF(result);
1103 PyErr_SetNTSTATUS(status);
1104 return NULL;
1107 /* sanity-check we read the expected number of bytes */
1108 if (nread > size) {
1109 Py_XDECREF(result);
1110 PyErr_Format(PyExc_IOError,
1111 "read invalid - got %zu requested %zu",
1112 nread, size);
1113 return NULL;
1116 if (nread < size) {
1117 if (_PyBytes_Resize(&result, nread) < 0) {
1118 return NULL;
1122 return result;
1125 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
1126 PyObject *kwds)
1128 int fnum;
1129 unsigned long long offset;
1130 unsigned size;
1131 struct tevent_req *req;
1132 NTSTATUS status;
1133 char *buf;
1134 size_t received;
1135 PyObject *result;
1137 static const char *kwlist[] = {
1138 "fnum", "offset", "size", NULL };
1140 if (!ParseTupleAndKeywords(
1141 args, kwds, "iKI", kwlist, &fnum, &offset,
1142 &size)) {
1143 return NULL;
1146 result = PyBytes_FromStringAndSize(NULL, size);
1147 if (result == NULL) {
1148 return NULL;
1150 buf = PyBytes_AS_STRING(result);
1152 req = cli_read_send(NULL, self->ev, self->cli, fnum,
1153 buf, offset, size);
1154 if (!py_tevent_req_wait_exc(self, req)) {
1155 Py_XDECREF(result);
1156 return NULL;
1158 status = cli_read_recv(req, &received);
1159 TALLOC_FREE(req);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 Py_XDECREF(result);
1163 PyErr_SetNTSTATUS(status);
1164 return NULL;
1167 if (received > size) {
1168 Py_XDECREF(result);
1169 PyErr_Format(PyExc_IOError,
1170 "read invalid - got %zu requested %u",
1171 received, size);
1172 return NULL;
1175 if (received < size) {
1176 if (_PyBytes_Resize(&result, received) < 0) {
1177 return NULL;
1181 return result;
1184 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
1185 PyObject *kwds)
1187 int fnum;
1188 unsigned long long size;
1189 struct tevent_req *req;
1190 NTSTATUS status;
1192 static const char *kwlist[] = {
1193 "fnum", "size", NULL };
1195 if (!ParseTupleAndKeywords(
1196 args, kwds, "IK", kwlist, &fnum, &size)) {
1197 return NULL;
1200 req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
1201 if (!py_tevent_req_wait_exc(self, req)) {
1202 return NULL;
1204 status = cli_ftruncate_recv(req);
1205 TALLOC_FREE(req);
1207 if (!NT_STATUS_IS_OK(status)) {
1208 PyErr_SetNTSTATUS(status);
1209 return NULL;
1211 Py_RETURN_NONE;
1214 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
1215 PyObject *args,
1216 PyObject *kwds)
1218 unsigned fnum, flag;
1219 struct tevent_req *req;
1220 NTSTATUS status;
1222 static const char *kwlist[] = {
1223 "fnum", "flag", NULL };
1225 if (!ParseTupleAndKeywords(
1226 args, kwds, "II", kwlist, &fnum, &flag)) {
1227 return NULL;
1230 req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
1231 flag);
1232 if (!py_tevent_req_wait_exc(self, req)) {
1233 return NULL;
1235 status = cli_nt_delete_on_close_recv(req);
1236 TALLOC_FREE(req);
1238 if (!NT_STATUS_IS_OK(status)) {
1239 PyErr_SetNTSTATUS(status);
1240 return NULL;
1242 Py_RETURN_NONE;
1245 struct py_cli_notify_state {
1246 PyObject_HEAD
1247 struct py_cli_state *py_cli_state;
1248 struct tevent_req *req;
1251 static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
1253 TALLOC_FREE(self->req);
1254 if (self->py_cli_state != NULL) {
1255 Py_DECREF(self->py_cli_state);
1256 self->py_cli_state = NULL;
1258 Py_TYPE(self)->tp_free(self);
1261 static PyTypeObject py_cli_notify_state_type;
1263 static PyObject *py_cli_notify(struct py_cli_state *self,
1264 PyObject *args,
1265 PyObject *kwds)
1267 static const char *kwlist[] = {
1268 "fnum",
1269 "buffer_size",
1270 "completion_filter",
1271 "recursive",
1272 NULL
1274 unsigned fnum = 0;
1275 unsigned buffer_size = 0;
1276 unsigned completion_filter = 0;
1277 PyObject *py_recursive = Py_False;
1278 bool recursive = false;
1279 struct tevent_req *req = NULL;
1280 struct tevent_queue *send_queue = NULL;
1281 struct tevent_req *flush_req = NULL;
1282 bool ok;
1283 struct py_cli_notify_state *py_notify_state = NULL;
1284 struct timeval endtime;
1286 ok = ParseTupleAndKeywords(args,
1287 kwds,
1288 "IIIO",
1289 kwlist,
1290 &fnum,
1291 &buffer_size,
1292 &completion_filter,
1293 &py_recursive);
1294 if (!ok) {
1295 return NULL;
1298 recursive = PyObject_IsTrue(py_recursive);
1300 req = cli_notify_send(NULL,
1301 self->ev,
1302 self->cli,
1303 fnum,
1304 buffer_size,
1305 completion_filter,
1306 recursive);
1307 if (req == NULL) {
1308 PyErr_NoMemory();
1309 return NULL;
1313 * Just wait for the request being submitted to
1314 * the kernel/socket/wire.
1316 send_queue = smbXcli_conn_send_queue(self->cli->conn);
1317 flush_req = tevent_queue_wait_send(req,
1318 self->ev,
1319 send_queue);
1320 endtime = timeval_current_ofs_msec(self->cli->timeout);
1321 ok = tevent_req_set_endtime(flush_req,
1322 self->ev,
1323 endtime);
1324 if (!ok) {
1325 TALLOC_FREE(req);
1326 PyErr_NoMemory();
1327 return NULL;
1329 ok = py_tevent_req_wait_exc(self, flush_req);
1330 if (!ok) {
1331 TALLOC_FREE(req);
1332 return NULL;
1334 TALLOC_FREE(flush_req);
1336 py_notify_state = (struct py_cli_notify_state *)
1337 py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
1338 if (py_notify_state == NULL) {
1339 TALLOC_FREE(req);
1340 PyErr_NoMemory();
1341 return NULL;
1343 Py_INCREF(self);
1344 py_notify_state->py_cli_state = self;
1345 py_notify_state->req = req;
1347 return (PyObject *)py_notify_state;
1350 static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
1351 PyObject *args,
1352 PyObject *kwds)
1354 struct py_cli_state *py_cli_state = self->py_cli_state;
1355 struct tevent_req *req = self->req;
1356 uint32_t i;
1357 uint32_t num_changes = 0;
1358 struct notify_change *changes = NULL;
1359 PyObject *result = NULL;
1360 NTSTATUS status;
1361 bool ok;
1362 static const char *kwlist[] = {
1363 "wait",
1364 NULL
1366 PyObject *py_wait = Py_False;
1367 bool wait = false;
1368 bool pending;
1370 ok = ParseTupleAndKeywords(args,
1371 kwds,
1372 "O",
1373 kwlist,
1374 &py_wait);
1375 if (!ok) {
1376 return NULL;
1379 wait = PyObject_IsTrue(py_wait);
1381 if (req == NULL) {
1382 PyErr_SetString(PyExc_RuntimeError,
1383 "TODO req == NULL "
1384 "- missing change notify request?");
1385 return NULL;
1388 pending = tevent_req_is_in_progress(req);
1389 if (pending && !wait) {
1390 Py_RETURN_NONE;
1393 if (pending) {
1394 struct timeval endtime;
1396 endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
1397 ok = tevent_req_set_endtime(req,
1398 py_cli_state->ev,
1399 endtime);
1400 if (!ok) {
1401 TALLOC_FREE(req);
1402 PyErr_NoMemory();
1403 return NULL;
1407 ok = py_tevent_req_wait_exc(py_cli_state, req);
1408 self->req = NULL;
1409 Py_DECREF(self->py_cli_state);
1410 self->py_cli_state = NULL;
1411 if (!ok) {
1412 return NULL;
1415 status = cli_notify_recv(req, req, &num_changes, &changes);
1416 if (!NT_STATUS_IS_OK(status)) {
1417 TALLOC_FREE(req);
1418 PyErr_SetNTSTATUS(status);
1419 return NULL;
1422 result = Py_BuildValue("[]");
1423 if (result == NULL) {
1424 TALLOC_FREE(req);
1425 return NULL;
1428 for (i = 0; i < num_changes; i++) {
1429 PyObject *change = NULL;
1430 int ret;
1432 change = Py_BuildValue("{s:s,s:I}",
1433 "name", changes[i].name,
1434 "action", changes[i].action);
1435 if (change == NULL) {
1436 Py_XDECREF(result);
1437 TALLOC_FREE(req);
1438 return NULL;
1441 ret = PyList_Append(result, change);
1442 Py_DECREF(change);
1443 if (ret == -1) {
1444 Py_XDECREF(result);
1445 TALLOC_FREE(req);
1446 return NULL;
1450 TALLOC_FREE(req);
1451 return result;
1454 static PyMethodDef py_cli_notify_state_methods[] = {
1456 .ml_name = "get_changes",
1457 .ml_meth = (PyCFunction)py_cli_notify_get_changes,
1458 .ml_flags = METH_VARARGS|METH_KEYWORDS,
1459 .ml_doc = "Wait for change notifications: \n"
1460 "N.get_changes(wait=BOOLEAN) -> "
1461 "change notifications as a dictionary\n"
1462 "\t\tList contents of a directory. The keys are, \n"
1463 "\t\t\tname: name of changed object\n"
1464 "\t\t\taction: type of the change\n"
1465 "None is returned if there's no response jet and "
1466 "wait=False is passed"
1469 .ml_name = NULL
1473 static PyTypeObject py_cli_notify_state_type = {
1474 PyVarObject_HEAD_INIT(NULL, 0)
1475 .tp_name = "libsmb_samba_cwrapper.Notify",
1476 .tp_basicsize = sizeof(struct py_cli_notify_state),
1477 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1478 .tp_doc = "notify request",
1479 .tp_dealloc = (destructor)py_cli_notify_state_dealloc,
1480 .tp_methods = py_cli_notify_state_methods,
1484 * Helper to add directory listing entries to an overall Python list
1486 static NTSTATUS list_helper(struct file_info *finfo,
1487 const char *mask, void *state)
1489 PyObject *result = (PyObject *)state;
1490 PyObject *file = NULL;
1491 PyObject *size = NULL;
1492 int ret;
1494 /* suppress '.' and '..' in the results we return */
1495 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1496 return NT_STATUS_OK;
1498 size = PyLong_FromUnsignedLongLong(finfo->size);
1500 * Build a dictionary representing the file info.
1501 * Note: Windows does not always return short_name (so it may be None)
1503 file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l}",
1504 "name", finfo->name,
1505 "attrib", (int)finfo->attr,
1506 "short_name", finfo->short_name,
1507 "size", size,
1508 "mtime",
1509 convert_timespec_to_time_t(finfo->mtime_ts));
1511 Py_CLEAR(size);
1513 if (file == NULL) {
1514 return NT_STATUS_NO_MEMORY;
1517 ret = PyList_Append(result, file);
1518 Py_CLEAR(file);
1519 if (ret == -1) {
1520 return NT_STATUS_INTERNAL_ERROR;
1523 return NT_STATUS_OK;
1526 struct do_listing_state {
1527 const char *mask;
1528 NTSTATUS (*callback_fn)(
1529 struct file_info *finfo,
1530 const char *mask,
1531 void *private_data);
1532 void *private_data;
1533 NTSTATUS status;
1536 static void do_listing_cb(struct tevent_req *subreq)
1538 struct do_listing_state *state = tevent_req_callback_data_void(subreq);
1539 struct file_info *finfo = NULL;
1541 state->status = cli_list_recv(subreq, NULL, &finfo);
1542 if (!NT_STATUS_IS_OK(state->status)) {
1543 return;
1545 state->callback_fn(finfo, state->mask, state->private_data);
1546 TALLOC_FREE(finfo);
1549 static NTSTATUS do_listing(struct py_cli_state *self,
1550 const char *base_dir, const char *user_mask,
1551 uint16_t attribute,
1552 NTSTATUS (*callback_fn)(struct file_info *,
1553 const char *, void *),
1554 void *priv)
1556 char *mask = NULL;
1557 unsigned int info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
1558 struct do_listing_state state = {
1559 .mask = mask,
1560 .callback_fn = callback_fn,
1561 .private_data = priv,
1563 struct tevent_req *req = NULL;
1564 NTSTATUS status;
1566 if (user_mask == NULL) {
1567 mask = talloc_asprintf(NULL, "%s\\*", base_dir);
1568 } else {
1569 mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
1572 if (mask == NULL) {
1573 return NT_STATUS_NO_MEMORY;
1575 dos_format(mask);
1577 req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
1578 info_level);
1579 if (req == NULL) {
1580 status = NT_STATUS_NO_MEMORY;
1581 goto done;
1583 tevent_req_set_callback(req, do_listing_cb, &state);
1585 if (!py_tevent_req_wait_exc(self, req)) {
1586 return NT_STATUS_INTERNAL_ERROR;
1588 TALLOC_FREE(req);
1590 status = state.status;
1591 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
1592 status = NT_STATUS_OK;
1595 done:
1596 TALLOC_FREE(mask);
1597 return status;
1600 static PyObject *py_cli_list(struct py_cli_state *self,
1601 PyObject *args,
1602 PyObject *kwds)
1604 char *base_dir;
1605 char *user_mask = NULL;
1606 unsigned int attribute = LIST_ATTRIBUTE_MASK;
1607 NTSTATUS status;
1608 PyObject *result = NULL;
1609 const char *kwlist[] = { "directory", "mask", "attribs", NULL };
1611 if (!ParseTupleAndKeywords(args, kwds, "z|sI:list", kwlist,
1612 &base_dir, &user_mask, &attribute)) {
1613 return NULL;
1616 result = Py_BuildValue("[]");
1617 if (result == NULL) {
1618 return NULL;
1621 status = do_listing(self, base_dir, user_mask, attribute,
1622 list_helper, result);
1624 if (!NT_STATUS_IS_OK(status)) {
1625 Py_XDECREF(result);
1626 PyErr_SetNTSTATUS(status);
1627 return NULL;
1630 return result;
1633 static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
1635 NTSTATUS status;
1636 const char *filename = NULL;
1637 struct tevent_req *req = NULL;
1638 const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
1640 if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
1641 return NULL;
1644 req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
1645 if (!py_tevent_req_wait_exc(self, req)) {
1646 return NULL;
1648 status = cli_unlink_recv(req);
1649 TALLOC_FREE(req);
1650 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1652 Py_RETURN_NONE;
1655 static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
1657 NTSTATUS status;
1658 struct tevent_req *req = NULL;
1659 const char *dirname = NULL;
1661 if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
1662 return NULL;
1665 req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
1666 if (!py_tevent_req_wait_exc(self, req)) {
1667 return NULL;
1669 status = cli_rmdir_recv(req);
1670 TALLOC_FREE(req);
1671 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1673 Py_RETURN_NONE;
1677 * Create a directory
1679 static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
1681 NTSTATUS status;
1682 const char *dirname = NULL;
1683 struct tevent_req *req = NULL;
1685 if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
1686 return NULL;
1689 req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
1690 if (!py_tevent_req_wait_exc(self, req)) {
1691 return NULL;
1693 status = cli_mkdir_recv(req);
1694 TALLOC_FREE(req);
1695 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1697 Py_RETURN_NONE;
1701 * Does a whoami call
1703 static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
1704 PyObject *Py_UNUSED(ignored))
1706 TALLOC_CTX *frame = talloc_stackframe();
1707 NTSTATUS status;
1708 struct tevent_req *req = NULL;
1709 uint64_t uid;
1710 uint64_t gid;
1711 uint32_t num_gids;
1712 uint64_t *gids = NULL;
1713 uint32_t num_sids;
1714 struct dom_sid *sids = NULL;
1715 bool guest;
1716 PyObject *py_gids = NULL;
1717 PyObject *py_sids = NULL;
1718 PyObject *py_guest = NULL;
1719 PyObject *py_ret = NULL;
1720 Py_ssize_t i;
1722 req = cli_posix_whoami_send(frame, self->ev, self->cli);
1723 if (!py_tevent_req_wait_exc(self, req)) {
1724 goto fail;
1726 status = cli_posix_whoami_recv(req,
1727 frame,
1728 &uid,
1729 &gid,
1730 &num_gids,
1731 &gids,
1732 &num_sids,
1733 &sids,
1734 &guest);
1735 if (!NT_STATUS_IS_OK(status)) {
1736 PyErr_SetNTSTATUS(status);
1737 goto fail;
1739 if (num_gids > PY_SSIZE_T_MAX) {
1740 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
1741 goto fail;
1743 if (num_sids > PY_SSIZE_T_MAX) {
1744 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
1745 goto fail;
1748 py_gids = PyList_New(num_gids);
1749 if (!py_gids) {
1750 goto fail;
1752 for (i = 0; i < num_gids; ++i) {
1753 int ret;
1754 PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
1755 if (!py_item) {
1756 goto fail2;
1759 ret = PyList_SetItem(py_gids, i, py_item);
1760 if (ret) {
1761 goto fail2;
1764 py_sids = PyList_New(num_sids);
1765 if (!py_sids) {
1766 goto fail2;
1768 for (i = 0; i < num_sids; ++i) {
1769 int ret;
1770 struct dom_sid *sid;
1771 PyObject *py_item;
1773 sid = dom_sid_dup(frame, &sids[i]);
1774 if (!sid) {
1775 PyErr_NoMemory();
1776 goto fail3;
1779 py_item = pytalloc_steal(dom_sid_Type, sid);
1780 if (!py_item) {
1781 PyErr_NoMemory();
1782 goto fail3;
1785 ret = PyList_SetItem(py_sids, i, py_item);
1786 if (ret) {
1787 goto fail3;
1791 py_guest = guest ? Py_True : Py_False;
1793 py_ret = Py_BuildValue("KKNNO",
1794 uid,
1795 gid,
1796 py_gids,
1797 py_sids,
1798 py_guest);
1799 if (!py_ret) {
1800 goto fail3;
1803 TALLOC_FREE(frame);
1804 return py_ret;
1806 fail3:
1807 Py_CLEAR(py_sids);
1809 fail2:
1810 Py_CLEAR(py_gids);
1812 fail:
1813 TALLOC_FREE(frame);
1814 return NULL;
1818 * Checks existence of a directory
1820 static bool check_dir_path(struct py_cli_state *self, const char *path)
1822 NTSTATUS status;
1823 struct tevent_req *req = NULL;
1825 req = cli_chkpath_send(NULL, self->ev, self->cli, path);
1826 if (!py_tevent_req_wait_exc(self, req)) {
1827 return false;
1829 status = cli_chkpath_recv(req);
1830 TALLOC_FREE(req);
1832 return NT_STATUS_IS_OK(status);
1835 static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
1837 const char *path = NULL;
1838 bool dir_exists;
1840 if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
1841 return NULL;
1844 dir_exists = check_dir_path(self, path);
1845 return PyBool_FromLong(dir_exists);
1848 static PyObject *py_smb_have_posix(struct py_cli_state *self,
1849 PyObject *Py_UNUSED(ignored))
1851 bool posix = smbXcli_conn_have_posix(self->cli->conn);
1853 if (posix) {
1854 Py_RETURN_TRUE;
1856 Py_RETURN_FALSE;
1859 static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
1861 int fnum;
1862 unsigned sinfo;
1863 struct tevent_req *req = NULL;
1864 struct security_descriptor *sd = NULL;
1865 NTSTATUS status;
1867 if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
1868 return NULL;
1871 req = cli_query_security_descriptor_send(
1872 NULL, self->ev, self->cli, fnum, sinfo);
1873 if (!py_tevent_req_wait_exc(self, req)) {
1874 return NULL;
1876 status = cli_query_security_descriptor_recv(req, NULL, &sd);
1877 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1879 return py_return_ndr_struct(
1880 "samba.dcerpc.security", "descriptor", sd, sd);
1883 static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
1885 PyObject *py_sd = NULL;
1886 struct tevent_req *req = NULL;
1887 struct security_descriptor *sd = NULL;
1888 uint16_t fnum;
1889 unsigned int sinfo;
1890 NTSTATUS status;
1892 if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
1893 return NULL;
1896 sd = pytalloc_get_type(py_sd, struct security_descriptor);
1897 if (!sd) {
1898 PyErr_Format(PyExc_TypeError,
1899 "Expected dcerpc.security.descriptor as argument, got %s",
1900 pytalloc_get_name(py_sd));
1901 return NULL;
1904 req = cli_set_security_descriptor_send(
1905 NULL, self->ev, self->cli, fnum, sinfo, sd);
1906 if (!py_tevent_req_wait_exc(self, req)) {
1907 return NULL;
1910 status = cli_set_security_descriptor_recv(req);
1911 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1913 Py_RETURN_NONE;
1916 static PyMethodDef py_cli_state_methods[] = {
1917 { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
1918 "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
1919 { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
1920 "Ping the server connection" },
1921 { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
1922 METH_VARARGS|METH_KEYWORDS,
1923 "Open a file" },
1924 { "close", (PyCFunction)py_cli_close, METH_VARARGS,
1925 "Close a file handle" },
1926 { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
1927 METH_VARARGS|METH_KEYWORDS,
1928 "Write to a file handle" },
1929 { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
1930 METH_VARARGS|METH_KEYWORDS,
1931 "Read from a file handle" },
1932 { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
1933 py_cli_ftruncate),
1934 METH_VARARGS|METH_KEYWORDS,
1935 "Truncate a file" },
1936 { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
1937 py_cli_delete_on_close),
1938 METH_VARARGS|METH_KEYWORDS,
1939 "Set/Reset the delete on close flag" },
1940 { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
1941 METH_VARARGS|METH_KEYWORDS,
1942 "Wait for change notifications: \n"
1943 "notify(fnum, buffer_size, completion_filter...) -> "
1944 "libsmb_samba_internal.Notify request handle\n" },
1945 { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
1946 METH_VARARGS|METH_KEYWORDS,
1947 "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
1948 "directory contents as a dictionary\n"
1949 "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
1950 "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
1951 "\t\tList contents of a directory. The keys are, \n"
1952 "\t\t\tname: Long name of the directory item\n"
1953 "\t\t\tshort_name: Short name of the directory item\n"
1954 "\t\t\tsize: File size in bytes\n"
1955 "\t\t\tattrib: Attributes\n"
1956 "\t\t\tmtime: Modification time\n" },
1957 { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
1958 METH_VARARGS, "Wait for an oplock break" },
1959 { "unlink", (PyCFunction)py_smb_unlink,
1960 METH_VARARGS,
1961 "unlink(path) -> None\n\n \t\tDelete a file." },
1962 { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
1963 "mkdir(path) -> None\n\n \t\tCreate a directory." },
1964 { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
1965 "posix_whoami() -> (uid, gid, gids, sids, guest)" },
1966 { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
1967 "rmdir(path) -> None\n\n \t\tDelete a directory." },
1968 { "rename",
1969 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
1970 METH_VARARGS|METH_KEYWORDS,
1971 "rename(src,dst) -> None\n\n \t\tRename a file." },
1972 { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
1973 "chkpath(dir_path) -> True or False\n\n"
1974 "\t\tReturn true if directory exists, false otherwise." },
1975 { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
1976 "savefile(path, bytes) -> None\n\n"
1977 "\t\tWrite bytes to file." },
1978 { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
1979 "loadfile(path) -> file contents as a bytes object"
1980 "\n\n\t\tRead contents of a file." },
1981 { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
1982 "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
1983 "\t\tGet security descriptor for opened file." },
1984 { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
1985 "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
1986 "\t\tSet security descriptor for opened file." },
1987 { "have_posix",
1988 (PyCFunction)py_smb_have_posix,
1989 METH_NOARGS,
1990 "have_posix() -> True/False\n\n"
1991 "\t\tReturn if the server has posix extensions"
1993 { NULL, NULL, 0, NULL }
1996 static PyTypeObject py_cli_state_type = {
1997 PyVarObject_HEAD_INIT(NULL, 0)
1998 .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
1999 .tp_basicsize = sizeof(struct py_cli_state),
2000 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2001 .tp_doc = "libsmb cwrapper connection",
2002 .tp_new = py_cli_state_new,
2003 .tp_init = (initproc)py_cli_state_init,
2004 .tp_dealloc = (destructor)py_cli_state_dealloc,
2005 .tp_methods = py_cli_state_methods,
2008 static PyMethodDef py_libsmb_methods[] = {
2009 {0},
2012 void initlibsmb_samba_cwrapper(void);
2014 static struct PyModuleDef moduledef = {
2015 PyModuleDef_HEAD_INIT,
2016 .m_name = "libsmb_samba_cwrapper",
2017 .m_doc = "libsmb wrapper",
2018 .m_size = -1,
2019 .m_methods = py_libsmb_methods,
2022 MODULE_INIT_FUNC(libsmb_samba_cwrapper)
2024 PyObject *m = NULL;
2025 PyObject *mod = NULL;
2027 talloc_stackframe();
2029 if (PyType_Ready(&py_cli_state_type) < 0) {
2030 return NULL;
2032 if (PyType_Ready(&py_cli_notify_state_type) < 0) {
2033 return NULL;
2036 m = PyModule_Create(&moduledef);
2037 if (m == NULL) {
2038 return m;
2041 /* Import dom_sid type from dcerpc.security */
2042 mod = PyImport_ImportModule("samba.dcerpc.security");
2043 if (mod == NULL) {
2044 return NULL;
2047 dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
2048 if (dom_sid_Type == NULL) {
2049 Py_DECREF(mod);
2050 return NULL;
2053 Py_INCREF(&py_cli_state_type);
2054 PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
2056 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
2058 ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
2059 ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
2060 ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
2061 ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
2062 ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
2063 ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
2064 ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
2065 ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
2066 ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
2067 ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
2068 ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
2069 ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
2070 ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
2071 ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
2072 ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
2073 ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
2075 ADD_FLAGS(FILE_SHARE_READ);
2076 ADD_FLAGS(FILE_SHARE_WRITE);
2077 ADD_FLAGS(FILE_SHARE_DELETE);
2079 /* change notify completion filter flags */
2080 ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
2081 ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
2082 ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
2083 ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
2084 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
2085 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
2086 ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
2087 ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
2088 ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
2089 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
2090 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
2091 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
2092 ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
2093 ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
2095 /* change notify action results */
2096 ADD_FLAGS(NOTIFY_ACTION_ADDED);
2097 ADD_FLAGS(NOTIFY_ACTION_REMOVED);
2098 ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
2099 ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
2100 ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
2101 ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
2102 ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
2103 ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
2105 #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
2107 ADD_STRING(SMB2_CREATE_TAG_EXTA);
2108 ADD_STRING(SMB2_CREATE_TAG_MXAC);
2109 ADD_STRING(SMB2_CREATE_TAG_SECD);
2110 ADD_STRING(SMB2_CREATE_TAG_DHNQ);
2111 ADD_STRING(SMB2_CREATE_TAG_DHNC);
2112 ADD_STRING(SMB2_CREATE_TAG_ALSI);
2113 ADD_STRING(SMB2_CREATE_TAG_TWRP);
2114 ADD_STRING(SMB2_CREATE_TAG_QFID);
2115 ADD_STRING(SMB2_CREATE_TAG_RQLS);
2116 ADD_STRING(SMB2_CREATE_TAG_DH2Q);
2117 ADD_STRING(SMB2_CREATE_TAG_DH2C);
2118 ADD_STRING(SMB2_CREATE_TAG_AAPL);
2119 ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
2120 ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
2121 ADD_STRING(SMB2_CREATE_TAG_POSIX);
2123 return m;