ldb:kv_index: use subtransaction_cancel in transaction_cancel
[Samba.git] / source3 / libsmb / pylibsmb.c
blob8dbef93834b15226538862fdb4b7b9ddc6779be5
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/>.
25 Template code to use this library:
27 -------------------------
28 from samba.samba3 import libsmb_samba_internal as libsmb
29 from samba.samba3 import param as s3param
30 from samba import (credentials,NTSTATUSError)
32 lp = s3param.get_context()
33 lp.load("/etc/samba/smb.conf");
35 creds = credentials.Credentials()
36 creds.guess(lp)
37 creds.set_username("administrator")
38 creds.set_password("1234")
40 c = libsmb.Conn("127.0.0.1",
41 "tmp",
42 lp,
43 creds,
44 multi_threaded=True)
45 -------------------------
48 #include "lib/replace/system/python.h"
49 #include "includes.h"
50 #include "python/py3compat.h"
51 #include "python/modules.h"
52 #include "libcli/smb/smbXcli_base.h"
53 #include "libcli/smb/smb2_negotiate_context.h"
54 #include "libcli/smb/reparse.h"
55 #include "libsmb/libsmb.h"
56 #include "libcli/security/security.h"
57 #include "system/select.h"
58 #include "source4/libcli/util/pyerrors.h"
59 #include "auth/credentials/pycredentials.h"
60 #include "trans2.h"
61 #include "libsmb/clirap.h"
62 #include "librpc/rpc/pyrpc_util.h"
64 #define LIST_ATTRIBUTE_MASK \
65 (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
67 static PyTypeObject *dom_sid_Type = NULL;
69 static PyTypeObject *get_pytype(const char *module, const char *type)
71 PyObject *mod;
72 PyTypeObject *result;
74 mod = PyImport_ImportModule(module);
75 if (mod == NULL) {
76 PyErr_Format(PyExc_RuntimeError,
77 "Unable to import %s to check type %s",
78 module, type);
79 return NULL;
81 result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
82 Py_DECREF(mod);
83 if (result == NULL) {
84 PyErr_Format(PyExc_RuntimeError,
85 "Unable to find type %s in module %s",
86 module, type);
87 return NULL;
89 return result;
93 * We're using "const char * const *" for keywords,
94 * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
95 * inevitable warnings to just one place.
97 static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
98 const char *format, const char * const *keywords,
99 ...)
101 char **_keywords = discard_const_p(char *, keywords);
102 va_list a;
103 int ret;
104 va_start(a, keywords);
105 ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
106 _keywords, a);
107 va_end(a);
108 return ret;
111 struct py_cli_thread;
113 struct py_cli_oplock_break {
114 uint16_t fnum;
115 uint8_t level;
118 struct py_cli_state {
119 PyObject_HEAD
120 struct cli_state *cli;
121 struct tevent_context *ev;
122 int (*req_wait_fn)(struct tevent_context *ev,
123 struct tevent_req *req);
124 struct py_cli_thread *thread_state;
126 struct tevent_req *oplock_waiter;
127 struct py_cli_oplock_break *oplock_breaks;
128 struct py_tevent_cond *oplock_cond;
131 #ifdef HAVE_PTHREAD
133 #include <pthread.h>
135 struct py_cli_thread {
138 * Pipe to make the poll thread wake up in our destructor, so
139 * that we can exit and join the thread.
141 int shutdown_pipe[2];
142 struct tevent_fd *shutdown_fde;
143 bool do_shutdown;
144 pthread_t id;
147 * Thread state to release the GIL during the poll(2) syscall
149 PyThreadState *py_threadstate;
152 static void *py_cli_state_poll_thread(void *private_data)
154 struct py_cli_state *self = (struct py_cli_state *)private_data;
155 struct py_cli_thread *t = self->thread_state;
156 PyGILState_STATE gstate;
158 gstate = PyGILState_Ensure();
160 while (!t->do_shutdown) {
161 int ret;
162 ret = tevent_loop_once(self->ev);
163 assert(ret == 0);
165 PyGILState_Release(gstate);
166 return NULL;
169 static void py_cli_state_trace_callback(enum tevent_trace_point point,
170 void *private_data)
172 struct py_cli_state *self = (struct py_cli_state *)private_data;
173 struct py_cli_thread *t = self->thread_state;
175 switch(point) {
176 case TEVENT_TRACE_BEFORE_WAIT:
177 assert(t->py_threadstate == NULL);
178 t->py_threadstate = PyEval_SaveThread();
179 break;
180 case TEVENT_TRACE_AFTER_WAIT:
181 assert(t->py_threadstate != NULL);
182 PyEval_RestoreThread(t->py_threadstate);
183 t->py_threadstate = NULL;
184 break;
185 default:
186 break;
190 static void py_cli_state_shutdown_handler(struct tevent_context *ev,
191 struct tevent_fd *fde,
192 uint16_t flags,
193 void *private_data)
195 struct py_cli_state *self = (struct py_cli_state *)private_data;
196 struct py_cli_thread *t = self->thread_state;
198 if ((flags & TEVENT_FD_READ) == 0) {
199 return;
201 TALLOC_FREE(t->shutdown_fde);
202 t->do_shutdown = true;
205 static int py_cli_thread_destructor(struct py_cli_thread *t)
207 char c = 0;
208 ssize_t written;
209 int ret;
211 if (t->shutdown_pipe[1] != -1) {
212 do {
214 * This will wake the poll thread from the poll(2)
216 written = write(t->shutdown_pipe[1], &c, 1);
217 } while ((written == -1) && (errno == EINTR));
221 * Allow the poll thread to do its own cleanup under the GIL
223 Py_BEGIN_ALLOW_THREADS
224 ret = pthread_join(t->id, NULL);
225 Py_END_ALLOW_THREADS
226 assert(ret == 0);
228 if (t->shutdown_pipe[0] != -1) {
229 close(t->shutdown_pipe[0]);
230 t->shutdown_pipe[0] = -1;
232 if (t->shutdown_pipe[1] != -1) {
233 close(t->shutdown_pipe[1]);
234 t->shutdown_pipe[1] = -1;
236 return 0;
239 static int py_tevent_cond_req_wait(struct tevent_context *ev,
240 struct tevent_req *req);
242 static bool py_cli_state_setup_mt_ev(struct py_cli_state *self)
244 struct py_cli_thread *t = NULL;
245 int ret;
247 self->ev = tevent_context_init_byname(NULL, "poll_mt");
248 if (self->ev == NULL) {
249 goto fail;
251 samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
252 tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
254 self->req_wait_fn = py_tevent_cond_req_wait;
256 self->thread_state = talloc_zero(NULL, struct py_cli_thread);
257 if (self->thread_state == NULL) {
258 goto fail;
260 t = self->thread_state;
262 ret = pipe(t->shutdown_pipe);
263 if (ret == -1) {
264 goto fail;
266 t->shutdown_fde = tevent_add_fd(
267 self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ,
268 py_cli_state_shutdown_handler, self);
269 if (t->shutdown_fde == NULL) {
270 goto fail;
273 PyEval_InitThreads();
275 ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
276 if (ret != 0) {
277 goto fail;
279 talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
280 return true;
282 fail:
283 if (t != NULL) {
284 TALLOC_FREE(t->shutdown_fde);
286 if (t->shutdown_pipe[0] != -1) {
287 close(t->shutdown_pipe[0]);
288 t->shutdown_pipe[0] = -1;
290 if (t->shutdown_pipe[1] != -1) {
291 close(t->shutdown_pipe[1]);
292 t->shutdown_pipe[1] = -1;
296 TALLOC_FREE(self->thread_state);
297 TALLOC_FREE(self->ev);
298 return false;
301 struct py_tevent_cond {
302 pthread_mutex_t mutex;
303 pthread_cond_t cond;
304 bool is_done;
307 static void py_tevent_signalme(struct tevent_req *req);
309 static int py_tevent_cond_wait(struct py_tevent_cond *cond)
311 int ret, result;
313 result = pthread_mutex_init(&cond->mutex, NULL);
314 if (result != 0) {
315 goto fail;
317 result = pthread_cond_init(&cond->cond, NULL);
318 if (result != 0) {
319 goto fail_mutex;
322 result = pthread_mutex_lock(&cond->mutex);
323 if (result != 0) {
324 goto fail_cond;
327 cond->is_done = false;
329 while (!cond->is_done) {
331 Py_BEGIN_ALLOW_THREADS
332 result = pthread_cond_wait(&cond->cond, &cond->mutex);
333 Py_END_ALLOW_THREADS
335 if (result != 0) {
336 goto fail_unlock;
340 fail_unlock:
341 ret = pthread_mutex_unlock(&cond->mutex);
342 assert(ret == 0);
343 fail_cond:
344 ret = pthread_cond_destroy(&cond->cond);
345 assert(ret == 0);
346 fail_mutex:
347 ret = pthread_mutex_destroy(&cond->mutex);
348 assert(ret == 0);
349 fail:
350 return result;
353 static int py_tevent_cond_req_wait(struct tevent_context *ev,
354 struct tevent_req *req)
356 struct py_tevent_cond cond;
357 tevent_req_set_callback(req, py_tevent_signalme, &cond);
358 return py_tevent_cond_wait(&cond);
361 static void py_tevent_cond_signal(struct py_tevent_cond *cond)
363 int ret;
365 ret = pthread_mutex_lock(&cond->mutex);
366 assert(ret == 0);
368 cond->is_done = true;
370 ret = pthread_cond_signal(&cond->cond);
371 assert(ret == 0);
372 ret = pthread_mutex_unlock(&cond->mutex);
373 assert(ret == 0);
376 static void py_tevent_signalme(struct tevent_req *req)
378 struct py_tevent_cond *cond = (struct py_tevent_cond *)
379 tevent_req_callback_data_void(req);
381 py_tevent_cond_signal(cond);
384 #endif
386 static int py_tevent_req_wait(struct tevent_context *ev,
387 struct tevent_req *req);
389 static bool py_cli_state_setup_ev(struct py_cli_state *self)
391 self->ev = tevent_context_init(NULL);
392 if (self->ev == NULL) {
393 return false;
396 samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
398 self->req_wait_fn = py_tevent_req_wait;
400 return true;
403 static int py_tevent_req_wait(struct tevent_context *ev,
404 struct tevent_req *req)
406 while (tevent_req_is_in_progress(req)) {
407 int ret;
409 ret = tevent_loop_once(ev);
410 if (ret != 0) {
411 return ret;
414 return 0;
417 static bool py_tevent_req_wait_exc(struct py_cli_state *self,
418 struct tevent_req *req)
420 int ret;
422 if (req == NULL) {
423 PyErr_NoMemory();
424 return false;
426 ret = self->req_wait_fn(self->ev, req);
427 if (ret != 0) {
428 TALLOC_FREE(req);
429 errno = ret;
430 PyErr_SetFromErrno(PyExc_RuntimeError);
431 return false;
433 return true;
436 static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
437 PyObject *kwds)
439 struct py_cli_state *self;
441 self = (struct py_cli_state *)type->tp_alloc(type, 0);
442 if (self == NULL) {
443 return NULL;
445 self->cli = NULL;
446 self->ev = NULL;
447 self->thread_state = NULL;
448 self->oplock_waiter = NULL;
449 self->oplock_cond = NULL;
450 self->oplock_breaks = NULL;
451 return (PyObject *)self;
454 static struct smb2_negotiate_contexts *py_cli_get_negotiate_contexts(
455 TALLOC_CTX *mem_ctx, PyObject *list)
457 struct smb2_negotiate_contexts *ctxs = NULL;
458 Py_ssize_t i, len;
459 int ret;
461 ret = PyList_Check(list);
462 if (!ret) {
463 goto fail;
466 len = PyList_Size(list);
467 if (len == 0) {
468 goto fail;
471 ctxs = talloc_zero(mem_ctx, struct smb2_negotiate_contexts);
472 if (ctxs == NULL) {
473 goto fail;
476 for (i=0; i<len; i++) {
477 NTSTATUS status;
479 PyObject *t = PyList_GetItem(list, i);
480 Py_ssize_t tlen;
482 PyObject *ptype = NULL;
483 long type;
485 PyObject *pdata = NULL;
486 DATA_BLOB data = { .data = NULL, };
488 if (t == NULL) {
489 goto fail;
492 ret = PyTuple_Check(t);
493 if (!ret) {
494 goto fail;
497 tlen = PyTuple_Size(t);
498 if (tlen != 2) {
499 goto fail;
502 ptype = PyTuple_GetItem(t, 0);
503 if (ptype == NULL) {
504 goto fail;
506 type = PyLong_AsLong(ptype);
507 if ((type < 0) || (type > UINT16_MAX)) {
508 goto fail;
511 pdata = PyTuple_GetItem(t, 1);
513 ret = PyBytes_Check(pdata);
514 if (!ret) {
515 goto fail;
518 data.data = (uint8_t *)PyBytes_AsString(pdata);
519 data.length = PyBytes_Size(pdata);
521 status = smb2_negotiate_context_add(
522 ctxs, ctxs, type, data.data, data.length);
523 if (!NT_STATUS_IS_OK(status)) {
524 goto fail;
527 return ctxs;
529 fail:
530 TALLOC_FREE(ctxs);
531 return NULL;
534 static void py_cli_got_oplock_break(struct tevent_req *req);
536 static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
537 PyObject *kwds)
539 NTSTATUS status;
540 char *host, *share;
541 PyObject *creds = NULL;
542 struct cli_credentials *cli_creds;
543 PyObject *py_lp = Py_None;
544 PyObject *py_multi_threaded = Py_False;
545 bool multi_threaded = false;
546 PyObject *py_force_smb1 = Py_False;
547 bool force_smb1 = false;
548 PyObject *py_ipc = Py_False;
549 PyObject *py_posix = Py_False;
550 PyObject *py_negotiate_contexts = NULL;
551 struct smb2_negotiate_contexts *negotiate_contexts = NULL;
552 bool use_ipc = false;
553 bool request_posix = false;
554 struct tevent_req *req;
555 bool ret;
556 int flags = 0;
558 static const char *kwlist[] = {
559 "host", "share", "lp", "creds",
560 "multi_threaded", "force_smb1",
561 "ipc",
562 "posix",
563 "negotiate_contexts",
564 NULL
567 PyTypeObject *py_type_Credentials = get_pytype(
568 "samba.credentials", "Credentials");
569 if (py_type_Credentials == NULL) {
570 return -1;
573 ret = ParseTupleAndKeywords(
574 args, kwds, "ssO|O!OOOOO", kwlist,
575 &host, &share, &py_lp,
576 py_type_Credentials, &creds,
577 &py_multi_threaded,
578 &py_force_smb1,
579 &py_ipc,
580 &py_posix,
581 &py_negotiate_contexts);
583 Py_DECREF(py_type_Credentials);
585 if (!ret) {
586 return -1;
589 multi_threaded = PyObject_IsTrue(py_multi_threaded);
590 force_smb1 = PyObject_IsTrue(py_force_smb1);
592 if (force_smb1) {
594 * As most of the cli_*_send() function
595 * don't support SMB2 (it's only plugged
596 * into the sync wrapper functions currently)
597 * we have a way to force SMB1.
599 flags = CLI_FULL_CONNECTION_FORCE_SMB1;
602 use_ipc = PyObject_IsTrue(py_ipc);
603 if (use_ipc) {
604 flags |= CLI_FULL_CONNECTION_IPC;
607 request_posix = PyObject_IsTrue(py_posix);
608 if (request_posix) {
609 flags |= CLI_FULL_CONNECTION_REQUEST_POSIX;
612 if (py_negotiate_contexts != NULL) {
613 negotiate_contexts = py_cli_get_negotiate_contexts(
614 talloc_tos(), py_negotiate_contexts);
615 if (negotiate_contexts == NULL) {
616 return -1;
620 if (multi_threaded) {
621 #ifdef HAVE_PTHREAD
622 ret = py_cli_state_setup_mt_ev(self);
623 if (!ret) {
624 return -1;
626 #else
627 PyErr_SetString(PyExc_RuntimeError,
628 "No PTHREAD support available");
629 return -1;
630 #endif
631 } else {
632 ret = py_cli_state_setup_ev(self);
633 if (!ret) {
634 return -1;
638 if (creds == NULL) {
639 cli_creds = cli_credentials_init_anon(NULL);
640 } else {
641 cli_creds = PyCredentials_AsCliCredentials(creds);
644 req = cli_full_connection_creds_send(
645 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
646 cli_creds, flags,
647 negotiate_contexts);
648 if (!py_tevent_req_wait_exc(self, req)) {
649 return -1;
651 status = cli_full_connection_creds_recv(req, NULL, &self->cli);
652 TALLOC_FREE(req);
654 if (!NT_STATUS_IS_OK(status)) {
655 PyErr_SetNTSTATUS(status);
656 return -1;
660 * Oplocks require a multi threaded connection
662 if (self->thread_state == NULL) {
663 return 0;
666 self->oplock_waiter = cli_smb_oplock_break_waiter_send(
667 self->ev, self->ev, self->cli);
668 if (self->oplock_waiter == NULL) {
669 PyErr_NoMemory();
670 return -1;
672 tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
673 self);
674 return 0;
677 static void py_cli_got_oplock_break(struct tevent_req *req)
679 struct py_cli_state *self = (struct py_cli_state *)
680 tevent_req_callback_data_void(req);
681 struct py_cli_oplock_break b;
682 struct py_cli_oplock_break *tmp;
683 size_t num_breaks;
684 NTSTATUS status;
686 status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
687 TALLOC_FREE(req);
688 self->oplock_waiter = NULL;
690 if (!NT_STATUS_IS_OK(status)) {
691 return;
694 num_breaks = talloc_array_length(self->oplock_breaks);
695 tmp = talloc_realloc(self->ev, self->oplock_breaks,
696 struct py_cli_oplock_break, num_breaks+1);
697 if (tmp == NULL) {
698 return;
700 self->oplock_breaks = tmp;
701 self->oplock_breaks[num_breaks] = b;
703 if (self->oplock_cond != NULL) {
704 py_tevent_cond_signal(self->oplock_cond);
707 self->oplock_waiter = cli_smb_oplock_break_waiter_send(
708 self->ev, self->ev, self->cli);
709 if (self->oplock_waiter == NULL) {
710 return;
712 tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
713 self);
716 static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
717 PyObject *args)
719 size_t num_oplock_breaks;
721 if (!PyArg_ParseTuple(args, "")) {
722 return NULL;
725 if (self->thread_state == NULL) {
726 PyErr_SetString(PyExc_RuntimeError,
727 "get_oplock_break() only possible on "
728 "a multi_threaded connection");
729 return NULL;
732 if (self->oplock_cond != NULL) {
733 errno = EBUSY;
734 PyErr_SetFromErrno(PyExc_RuntimeError);
735 return NULL;
738 num_oplock_breaks = talloc_array_length(self->oplock_breaks);
740 if (num_oplock_breaks == 0) {
741 struct py_tevent_cond cond;
742 int ret;
744 self->oplock_cond = &cond;
745 ret = py_tevent_cond_wait(&cond);
746 self->oplock_cond = NULL;
748 if (ret != 0) {
749 errno = ret;
750 PyErr_SetFromErrno(PyExc_RuntimeError);
751 return NULL;
755 num_oplock_breaks = talloc_array_length(self->oplock_breaks);
756 if (num_oplock_breaks > 0) {
757 PyObject *result;
759 result = Py_BuildValue(
760 "{s:i,s:i}",
761 "fnum", self->oplock_breaks[0].fnum,
762 "level", self->oplock_breaks[0].level);
764 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
765 sizeof(self->oplock_breaks[0]) *
766 (num_oplock_breaks - 1));
767 self->oplock_breaks = talloc_realloc(
768 NULL, self->oplock_breaks, struct py_cli_oplock_break,
769 num_oplock_breaks - 1);
771 return result;
773 Py_RETURN_NONE;
776 static void py_cli_state_dealloc(struct py_cli_state *self)
778 TALLOC_FREE(self->thread_state);
779 TALLOC_FREE(self->oplock_waiter);
780 TALLOC_FREE(self->ev);
782 if (self->cli != NULL) {
783 cli_shutdown(self->cli);
784 self->cli = NULL;
786 Py_TYPE(self)->tp_free((PyObject *)self);
789 static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
791 unsigned int nmsecs = 0;
792 unsigned int omsecs = 0;
794 if (!PyArg_ParseTuple(args, "I", &nmsecs)) {
795 return NULL;
798 omsecs = cli_set_timeout(self->cli, nmsecs);
800 return PyLong_FromLong(omsecs);
803 static PyObject *py_cli_echo(struct py_cli_state *self,
804 PyObject *Py_UNUSED(ignored))
806 DATA_BLOB data = data_blob_string_const("keepalive");
807 struct tevent_req *req = NULL;
808 NTSTATUS status;
810 req = cli_echo_send(NULL, self->ev, self->cli, 1, data);
811 if (!py_tevent_req_wait_exc(self, req)) {
812 return NULL;
814 status = cli_echo_recv(req);
815 TALLOC_FREE(req);
816 PyErr_NTSTATUS_NOT_OK_RAISE(status);
818 Py_RETURN_NONE;
821 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
822 PyObject *kwds)
824 char *fname;
825 unsigned CreateFlags = 0;
826 unsigned DesiredAccess = FILE_GENERIC_READ;
827 unsigned FileAttributes = 0;
828 unsigned ShareAccess = 0;
829 unsigned CreateDisposition = FILE_OPEN;
830 unsigned CreateOptions = 0;
831 unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
832 unsigned SecurityFlags = 0;
833 uint16_t fnum;
834 struct tevent_req *req;
835 NTSTATUS status;
837 static const char *kwlist[] = {
838 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
839 "ShareAccess", "CreateDisposition", "CreateOptions",
840 "ImpersonationLevel", "SecurityFlags", NULL };
842 if (!ParseTupleAndKeywords(
843 args, kwds, "s|IIIIIIII", kwlist,
844 &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
845 &ShareAccess, &CreateDisposition, &CreateOptions,
846 &ImpersonationLevel, &SecurityFlags)) {
847 return NULL;
850 req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
851 DesiredAccess, FileAttributes, ShareAccess,
852 CreateDisposition, CreateOptions,
853 ImpersonationLevel, SecurityFlags);
854 if (!py_tevent_req_wait_exc(self, req)) {
855 return NULL;
857 status = cli_ntcreate_recv(req, &fnum, NULL);
858 TALLOC_FREE(req);
860 if (!NT_STATUS_IS_OK(status)) {
861 PyErr_SetNTSTATUS(status);
862 return NULL;
864 return Py_BuildValue("I", (unsigned)fnum);
867 static struct smb2_create_blobs *py_cli_get_create_contexts(
868 TALLOC_CTX *mem_ctx, PyObject *list)
870 struct smb2_create_blobs *ctxs = NULL;
871 Py_ssize_t i, len;
872 int ret;
874 ret = PyList_Check(list);
875 if (!ret) {
876 goto fail;
879 len = PyList_Size(list);
880 if (len == 0) {
881 goto fail;
884 ctxs = talloc_zero(mem_ctx, struct smb2_create_blobs);
885 if (ctxs == NULL) {
886 goto fail;
889 for (i=0; i<len; i++) {
890 NTSTATUS status;
892 PyObject *t = NULL;
893 Py_ssize_t tlen;
895 PyObject *pname = NULL;
896 char *name = NULL;
898 PyObject *pdata = NULL;
899 DATA_BLOB data = { .data = NULL, };
901 t = PyList_GetItem(list, i);
902 if (t == NULL) {
903 goto fail;
906 ret = PyTuple_Check(t);
907 if (!ret) {
908 goto fail;
911 tlen = PyTuple_Size(t);
912 if (tlen != 2) {
913 goto fail;
916 pname = PyTuple_GetItem(t, 0);
917 if (pname == NULL) {
918 goto fail;
920 ret = PyBytes_Check(pname);
921 if (!ret) {
922 goto fail;
924 name = PyBytes_AsString(pname);
926 pdata = PyTuple_GetItem(t, 1);
927 if (pdata == NULL) {
928 goto fail;
930 ret = PyBytes_Check(pdata);
931 if (!ret) {
932 goto fail;
934 data = (DATA_BLOB) {
935 .data = (uint8_t *)PyBytes_AsString(pdata),
936 .length = PyBytes_Size(pdata),
938 status = smb2_create_blob_add(ctxs, ctxs, name, data);
939 if (!NT_STATUS_IS_OK(status)) {
940 goto fail;
943 return ctxs;
945 fail:
946 TALLOC_FREE(ctxs);
947 return NULL;
950 static PyObject *py_cli_create_contexts(const struct smb2_create_blobs *blobs)
952 PyObject *py_blobs = NULL;
953 uint32_t i;
955 if (blobs == NULL) {
956 Py_RETURN_NONE;
959 py_blobs = PyList_New(blobs->num_blobs);
960 if (py_blobs == NULL) {
961 return NULL;
964 for (i=0; i<blobs->num_blobs; i++) {
965 struct smb2_create_blob *blob = &blobs->blobs[i];
966 PyObject *py_blob = NULL;
967 int ret;
969 py_blob = Py_BuildValue(
970 "(yy#)",
971 blob->tag,
972 blob->data.data,
973 (int)blob->data.length);
974 if (py_blob == NULL) {
975 goto fail;
978 ret = PyList_SetItem(py_blobs, i, py_blob);
979 if (ret == -1) {
980 Py_XDECREF(py_blob);
981 goto fail;
984 return py_blobs;
986 fail:
987 Py_XDECREF(py_blobs);
988 return NULL;
991 static PyObject *py_cli_create_returns(const struct smb_create_returns *r)
993 PyObject *v = NULL;
995 v = Py_BuildValue(
996 "{sLsLsLsLsLsLsLsLsLsL}",
997 "oplock_level",
998 (unsigned long long)r->oplock_level,
999 "flags",
1000 (unsigned long long)r->flags,
1001 "create_action",
1002 (unsigned long long)r->create_action,
1003 "creation_time",
1004 (unsigned long long)r->creation_time,
1005 "last_access_time",
1006 (unsigned long long)r->last_access_time,
1007 "last_write_time",
1008 (unsigned long long)r->last_write_time,
1009 "change_time",
1010 (unsigned long long)r->change_time,
1011 "allocation_size",
1012 (unsigned long long)r->allocation_size,
1013 "end_of_file",
1014 (unsigned long long)r->end_of_file,
1015 "file_attributes",
1016 (unsigned long long)r->file_attributes);
1017 return v;
1020 static PyObject *py_cli_symlink_error(const struct symlink_reparse_struct *s)
1022 char *subst_utf8 = NULL, *print_utf8 = NULL;
1023 size_t subst_utf8_len, print_utf8_len;
1024 PyObject *v = NULL;
1025 bool ok = true;
1028 * Python wants utf-8, regardless of our unix charset (which
1029 * most likely is utf-8 these days, but you never know).
1032 ok = convert_string_talloc(
1033 talloc_tos(),
1034 CH_UNIX,
1035 CH_UTF8,
1036 s->substitute_name,
1037 strlen(s->substitute_name),
1038 &subst_utf8,
1039 &subst_utf8_len);
1040 if (!ok) {
1041 goto fail;
1044 ok = convert_string_talloc(
1045 talloc_tos(),
1046 CH_UNIX,
1047 CH_UTF8,
1048 s->print_name,
1049 strlen(s->print_name),
1050 &print_utf8,
1051 &print_utf8_len);
1052 if (!ok) {
1053 goto fail;
1056 v = Py_BuildValue(
1057 "{sLsssssL}",
1058 "unparsed_path_length",
1059 (unsigned long long)s->unparsed_path_length,
1060 "substitute_name",
1061 subst_utf8,
1062 "print_name",
1063 print_utf8,
1064 "flags",
1065 (unsigned long long)s->flags);
1067 fail:
1068 TALLOC_FREE(subst_utf8);
1069 TALLOC_FREE(print_utf8);
1070 return v;
1073 static PyObject *py_cli_create_ex(
1074 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1076 char *fname = NULL;
1077 unsigned CreateFlags = 0;
1078 unsigned DesiredAccess = FILE_GENERIC_READ;
1079 unsigned FileAttributes = 0;
1080 unsigned ShareAccess = 0;
1081 unsigned CreateDisposition = FILE_OPEN;
1082 unsigned CreateOptions = 0;
1083 unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
1084 unsigned SecurityFlags = 0;
1085 PyObject *py_create_contexts_in = NULL;
1086 PyObject *py_create_contexts_out = NULL;
1087 struct smb2_create_blobs *create_contexts_in = NULL;
1088 struct smb2_create_blobs create_contexts_out = { .num_blobs = 0 };
1089 struct smb_create_returns cr = { .create_action = 0, };
1090 struct symlink_reparse_struct *symlink = NULL;
1091 PyObject *py_cr = NULL;
1092 uint16_t fnum;
1093 struct tevent_req *req;
1094 NTSTATUS status;
1095 int ret;
1096 bool ok;
1097 PyObject *v = NULL;
1099 static const char *kwlist[] = {
1100 "Name",
1101 "CreateFlags",
1102 "DesiredAccess",
1103 "FileAttributes",
1104 "ShareAccess",
1105 "CreateDisposition",
1106 "CreateOptions",
1107 "ImpersonationLevel",
1108 "SecurityFlags",
1109 "CreateContexts",
1110 NULL };
1112 ret = ParseTupleAndKeywords(
1113 args,
1114 kwds,
1115 "s|IIIIIIIIO",
1116 kwlist,
1117 &fname,
1118 &CreateFlags,
1119 &DesiredAccess,
1120 &FileAttributes,
1121 &ShareAccess,
1122 &CreateDisposition,
1123 &CreateOptions,
1124 &ImpersonationLevel,
1125 &SecurityFlags,
1126 &py_create_contexts_in);
1127 if (!ret) {
1128 return NULL;
1131 if (py_create_contexts_in != NULL) {
1132 create_contexts_in = py_cli_get_create_contexts(
1133 NULL, py_create_contexts_in);
1134 if (create_contexts_in == NULL) {
1135 errno = EINVAL;
1136 PyErr_SetFromErrno(PyExc_RuntimeError);
1137 return NULL;
1141 if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1142 struct cli_smb2_create_flags cflags = {
1143 .batch_oplock = (CreateFlags & REQUEST_BATCH_OPLOCK),
1144 .exclusive_oplock = (CreateFlags & REQUEST_OPLOCK),
1147 req = cli_smb2_create_fnum_send(
1148 NULL,
1149 self->ev,
1150 self->cli,
1151 fname,
1152 cflags,
1153 ImpersonationLevel,
1154 DesiredAccess,
1155 FileAttributes,
1156 ShareAccess,
1157 CreateDisposition,
1158 CreateOptions,
1159 create_contexts_in);
1160 } else {
1161 req = cli_ntcreate_send(
1162 NULL,
1163 self->ev,
1164 self->cli,
1165 fname,
1166 CreateFlags,
1167 DesiredAccess,
1168 FileAttributes,
1169 ShareAccess,
1170 CreateDisposition,
1171 CreateOptions,
1172 ImpersonationLevel,
1173 SecurityFlags);
1176 TALLOC_FREE(create_contexts_in);
1178 ok = py_tevent_req_wait_exc(self, req);
1179 if (!ok) {
1180 return NULL;
1183 if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1184 status = cli_smb2_create_fnum_recv(
1185 req,
1186 &fnum,
1187 &cr,
1188 NULL,
1189 &create_contexts_out,
1190 &symlink);
1191 } else {
1192 status = cli_ntcreate_recv(req, &fnum, &cr);
1195 TALLOC_FREE(req);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 goto fail;
1201 SMB_ASSERT(symlink == NULL);
1203 py_create_contexts_out = py_cli_create_contexts(&create_contexts_out);
1204 TALLOC_FREE(create_contexts_out.blobs);
1205 if (py_create_contexts_out == NULL) {
1206 goto nomem;
1209 py_cr = py_cli_create_returns(&cr);
1210 if (py_cr == NULL) {
1211 goto nomem;
1214 v = Py_BuildValue("(IOO)",
1215 (unsigned)fnum,
1216 py_cr,
1217 py_create_contexts_out);
1218 return v;
1219 nomem:
1220 status = NT_STATUS_NO_MEMORY;
1221 fail:
1222 Py_XDECREF(py_create_contexts_out);
1223 Py_XDECREF(py_cr);
1224 Py_XDECREF(v);
1226 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
1227 (symlink != NULL)) {
1228 PyErr_SetObject(
1229 PyObject_GetAttrString(
1230 PyImport_ImportModule("samba"),
1231 "NTSTATUSError"),
1232 Py_BuildValue(
1233 "I,s,O",
1234 NT_STATUS_V(status),
1235 get_friendly_nt_error_msg(status),
1236 py_cli_symlink_error(symlink)));
1237 } else {
1238 PyErr_SetNTSTATUS(status);
1240 return NULL;
1243 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
1245 struct tevent_req *req;
1246 int fnum;
1247 int flags = 0;
1248 NTSTATUS status;
1250 if (!PyArg_ParseTuple(args, "i|i", &fnum, &flags)) {
1251 return NULL;
1254 req = cli_close_send(NULL, self->ev, self->cli, fnum, flags);
1255 if (!py_tevent_req_wait_exc(self, req)) {
1256 return NULL;
1258 status = cli_close_recv(req);
1259 TALLOC_FREE(req);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 PyErr_SetNTSTATUS(status);
1263 return NULL;
1265 Py_RETURN_NONE;
1268 static PyObject *py_cli_qfileinfo(struct py_cli_state *self, PyObject *args)
1270 struct tevent_req *req = NULL;
1271 int fnum, level;
1272 uint16_t recv_flags2;
1273 uint8_t *rdata = NULL;
1274 uint32_t num_rdata;
1275 PyObject *result = NULL;
1276 NTSTATUS status;
1278 if (!PyArg_ParseTuple(args, "ii", &fnum, &level)) {
1279 return NULL;
1282 req = cli_qfileinfo_send(
1283 NULL, self->ev, self->cli, fnum, level, 0, UINT32_MAX);
1284 if (!py_tevent_req_wait_exc(self, req)) {
1285 return NULL;
1287 status = cli_qfileinfo_recv(
1288 req, NULL, &recv_flags2, &rdata, &num_rdata);
1289 TALLOC_FREE(req);
1291 if (!NT_STATUS_IS_OK(status)) {
1292 PyErr_SetNTSTATUS(status);
1293 return NULL;
1296 switch (level) {
1297 case FSCC_FILE_ATTRIBUTE_TAG_INFORMATION: {
1298 uint32_t mode = PULL_LE_U32(rdata, 0);
1299 uint32_t tag = PULL_LE_U32(rdata, 4);
1301 if (num_rdata != 8) {
1302 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1303 return NULL;
1306 result = Py_BuildValue("{s:K,s:K}",
1307 "mode",
1308 (unsigned long long)mode,
1309 "tag",
1310 (unsigned long long)tag);
1311 break;
1313 default:
1314 result = PyBytes_FromStringAndSize((char *)rdata, num_rdata);
1315 break;
1318 TALLOC_FREE(rdata);
1320 return result;
1323 static PyObject *py_cli_rename(
1324 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1326 char *fname_src = NULL, *fname_dst = NULL;
1327 int replace = false;
1328 struct tevent_req *req = NULL;
1329 NTSTATUS status;
1330 bool ok;
1332 static const char *kwlist[] = { "src", "dst", "replace", NULL };
1334 ok = ParseTupleAndKeywords(
1335 args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
1336 if (!ok) {
1337 return NULL;
1340 req = cli_rename_send(
1341 NULL, self->ev, self->cli, fname_src, fname_dst, replace);
1342 if (!py_tevent_req_wait_exc(self, req)) {
1343 return NULL;
1345 status = cli_rename_recv(req);
1346 TALLOC_FREE(req);
1348 if (!NT_STATUS_IS_OK(status)) {
1349 PyErr_SetNTSTATUS(status);
1350 return NULL;
1352 Py_RETURN_NONE;
1356 struct push_state {
1357 char *data;
1358 off_t nread;
1359 off_t total_data;
1363 * cli_push() helper to write a chunk of data to a remote file
1365 static size_t push_data(uint8_t *buf, size_t n, void *priv)
1367 struct push_state *state = (struct push_state *)priv;
1368 char *curr_ptr = NULL;
1369 off_t remaining;
1370 size_t copied_bytes;
1372 if (state->nread >= state->total_data) {
1373 return 0;
1376 curr_ptr = state->data + state->nread;
1377 remaining = state->total_data - state->nread;
1378 copied_bytes = MIN(remaining, n);
1380 memcpy(buf, curr_ptr, copied_bytes);
1381 state->nread += copied_bytes;
1382 return copied_bytes;
1386 * Writes a file with the contents specified
1388 static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
1390 uint16_t fnum;
1391 const char *filename = NULL;
1392 char *data = NULL;
1393 Py_ssize_t size = 0;
1394 NTSTATUS status;
1395 struct tevent_req *req = NULL;
1396 struct push_state state;
1398 if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
1399 &data, &size)) {
1400 return NULL;
1403 /* create a new file handle for writing to */
1404 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1405 FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
1406 FILE_SHARE_READ|FILE_SHARE_WRITE,
1407 FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
1408 SMB2_IMPERSONATION_IMPERSONATION, 0);
1409 if (!py_tevent_req_wait_exc(self, req)) {
1410 return NULL;
1412 status = cli_ntcreate_recv(req, &fnum, NULL);
1413 TALLOC_FREE(req);
1414 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1416 /* write the new file contents */
1417 state.data = data;
1418 state.nread = 0;
1419 state.total_data = size;
1421 req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
1422 push_data, &state);
1423 if (!py_tevent_req_wait_exc(self, req)) {
1424 return NULL;
1426 status = cli_push_recv(req);
1427 TALLOC_FREE(req);
1428 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1430 /* close the file handle */
1431 req = cli_close_send(NULL, self->ev, self->cli, fnum, 0);
1432 if (!py_tevent_req_wait_exc(self, req)) {
1433 return NULL;
1435 status = cli_close_recv(req);
1436 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1438 Py_RETURN_NONE;
1441 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
1442 PyObject *kwds)
1444 int fnum;
1445 unsigned mode = 0;
1446 char *buf;
1447 Py_ssize_t buflen;
1448 unsigned long long offset;
1449 struct tevent_req *req;
1450 NTSTATUS status;
1451 size_t written;
1453 static const char *kwlist[] = {
1454 "fnum", "buffer", "offset", "mode", NULL };
1456 if (!ParseTupleAndKeywords(
1457 args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
1458 &fnum, &buf, &buflen, &offset, &mode)) {
1459 return NULL;
1462 req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
1463 (uint8_t *)buf, offset, buflen);
1464 if (!py_tevent_req_wait_exc(self, req)) {
1465 return NULL;
1467 status = cli_write_recv(req, &written);
1468 TALLOC_FREE(req);
1470 if (!NT_STATUS_IS_OK(status)) {
1471 PyErr_SetNTSTATUS(status);
1472 return NULL;
1474 return Py_BuildValue("K", (unsigned long long)written);
1478 * Returns the size of the given file
1480 static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
1481 off_t *size)
1483 NTSTATUS status;
1484 struct tevent_req *req = NULL;
1486 req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
1487 if (!py_tevent_req_wait_exc(self, req)) {
1488 return NT_STATUS_INTERNAL_ERROR;
1490 status = cli_qfileinfo_basic_recv(
1491 req, NULL, size, NULL, NULL, NULL, NULL, NULL);
1492 TALLOC_FREE(req);
1493 return status;
1497 * Loads the specified file's contents and returns it
1499 static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
1501 NTSTATUS status;
1502 const char *filename = NULL;
1503 struct tevent_req *req = NULL;
1504 uint16_t fnum;
1505 off_t size;
1506 char *buf = NULL;
1507 off_t nread = 0;
1508 PyObject *result = NULL;
1510 if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
1511 return NULL;
1514 /* get a read file handle */
1515 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1516 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
1517 FILE_ATTRIBUTE_NORMAL,
1518 FILE_SHARE_READ, FILE_OPEN, 0,
1519 SMB2_IMPERSONATION_IMPERSONATION, 0);
1520 if (!py_tevent_req_wait_exc(self, req)) {
1521 return NULL;
1523 status = cli_ntcreate_recv(req, &fnum, NULL);
1524 TALLOC_FREE(req);
1525 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1527 /* get a buffer to hold the file contents */
1528 status = py_smb_filesize(self, fnum, &size);
1529 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1531 result = PyBytes_FromStringAndSize(NULL, size);
1532 if (result == NULL) {
1533 return NULL;
1536 /* read the file contents */
1537 buf = PyBytes_AS_STRING(result);
1538 req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
1539 size, cli_read_sink, &buf);
1540 if (!py_tevent_req_wait_exc(self, req)) {
1541 Py_XDECREF(result);
1542 return NULL;
1544 status = cli_pull_recv(req, &nread);
1545 TALLOC_FREE(req);
1546 if (!NT_STATUS_IS_OK(status)) {
1547 Py_XDECREF(result);
1548 PyErr_SetNTSTATUS(status);
1549 return NULL;
1552 /* close the file handle */
1553 req = cli_close_send(NULL, self->ev, self->cli, fnum, 0);
1554 if (!py_tevent_req_wait_exc(self, req)) {
1555 Py_XDECREF(result);
1556 return NULL;
1558 status = cli_close_recv(req);
1559 TALLOC_FREE(req);
1560 if (!NT_STATUS_IS_OK(status)) {
1561 Py_XDECREF(result);
1562 PyErr_SetNTSTATUS(status);
1563 return NULL;
1566 /* sanity-check we read the expected number of bytes */
1567 if (nread > size) {
1568 Py_XDECREF(result);
1569 PyErr_Format(PyExc_IOError,
1570 "read invalid - got %zu requested %zu",
1571 nread, size);
1572 return NULL;
1575 if (nread < size) {
1576 if (_PyBytes_Resize(&result, nread) < 0) {
1577 return NULL;
1581 return result;
1584 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
1585 PyObject *kwds)
1587 int fnum;
1588 unsigned long long offset;
1589 unsigned size;
1590 struct tevent_req *req;
1591 NTSTATUS status;
1592 char *buf;
1593 size_t received;
1594 PyObject *result;
1596 static const char *kwlist[] = {
1597 "fnum", "offset", "size", NULL };
1599 if (!ParseTupleAndKeywords(
1600 args, kwds, "iKI", kwlist, &fnum, &offset,
1601 &size)) {
1602 return NULL;
1605 result = PyBytes_FromStringAndSize(NULL, size);
1606 if (result == NULL) {
1607 return NULL;
1609 buf = PyBytes_AS_STRING(result);
1611 req = cli_read_send(NULL, self->ev, self->cli, fnum,
1612 buf, offset, size);
1613 if (!py_tevent_req_wait_exc(self, req)) {
1614 Py_XDECREF(result);
1615 return NULL;
1617 status = cli_read_recv(req, &received);
1618 TALLOC_FREE(req);
1620 if (!NT_STATUS_IS_OK(status)) {
1621 Py_XDECREF(result);
1622 PyErr_SetNTSTATUS(status);
1623 return NULL;
1626 if (received > size) {
1627 Py_XDECREF(result);
1628 PyErr_Format(PyExc_IOError,
1629 "read invalid - got %zu requested %u",
1630 received, size);
1631 return NULL;
1634 if (received < size) {
1635 if (_PyBytes_Resize(&result, received) < 0) {
1636 return NULL;
1640 return result;
1643 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
1644 PyObject *kwds)
1646 int fnum;
1647 unsigned long long size;
1648 struct tevent_req *req;
1649 NTSTATUS status;
1651 static const char *kwlist[] = {
1652 "fnum", "size", NULL };
1654 if (!ParseTupleAndKeywords(
1655 args, kwds, "IK", kwlist, &fnum, &size)) {
1656 return NULL;
1659 req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
1660 if (!py_tevent_req_wait_exc(self, req)) {
1661 return NULL;
1663 status = cli_ftruncate_recv(req);
1664 TALLOC_FREE(req);
1666 if (!NT_STATUS_IS_OK(status)) {
1667 PyErr_SetNTSTATUS(status);
1668 return NULL;
1670 Py_RETURN_NONE;
1673 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
1674 PyObject *args,
1675 PyObject *kwds)
1677 unsigned fnum, flag;
1678 struct tevent_req *req;
1679 NTSTATUS status;
1681 static const char *kwlist[] = {
1682 "fnum", "flag", NULL };
1684 if (!ParseTupleAndKeywords(
1685 args, kwds, "II", kwlist, &fnum, &flag)) {
1686 return NULL;
1689 req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
1690 flag);
1691 if (!py_tevent_req_wait_exc(self, req)) {
1692 return NULL;
1694 status = cli_nt_delete_on_close_recv(req);
1695 TALLOC_FREE(req);
1697 if (!NT_STATUS_IS_OK(status)) {
1698 PyErr_SetNTSTATUS(status);
1699 return NULL;
1701 Py_RETURN_NONE;
1704 struct py_cli_notify_state {
1705 PyObject_HEAD
1706 struct py_cli_state *py_cli_state;
1707 struct tevent_req *req;
1710 static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
1712 TALLOC_FREE(self->req);
1713 Py_CLEAR(self->py_cli_state);
1714 Py_TYPE(self)->tp_free(self);
1717 static PyTypeObject py_cli_notify_state_type;
1719 static PyObject *py_cli_notify(struct py_cli_state *self,
1720 PyObject *args,
1721 PyObject *kwds)
1723 static const char *kwlist[] = {
1724 "fnum",
1725 "buffer_size",
1726 "completion_filter",
1727 "recursive",
1728 NULL
1730 unsigned fnum = 0;
1731 unsigned buffer_size = 0;
1732 unsigned completion_filter = 0;
1733 PyObject *py_recursive = Py_False;
1734 bool recursive = false;
1735 struct tevent_req *req = NULL;
1736 struct tevent_queue *send_queue = NULL;
1737 struct tevent_req *flush_req = NULL;
1738 bool ok;
1739 struct py_cli_notify_state *py_notify_state = NULL;
1740 struct timeval endtime;
1742 ok = ParseTupleAndKeywords(args,
1743 kwds,
1744 "IIIO",
1745 kwlist,
1746 &fnum,
1747 &buffer_size,
1748 &completion_filter,
1749 &py_recursive);
1750 if (!ok) {
1751 return NULL;
1754 recursive = PyObject_IsTrue(py_recursive);
1756 req = cli_notify_send(NULL,
1757 self->ev,
1758 self->cli,
1759 fnum,
1760 buffer_size,
1761 completion_filter,
1762 recursive);
1763 if (req == NULL) {
1764 PyErr_NoMemory();
1765 return NULL;
1769 * Just wait for the request being submitted to
1770 * the kernel/socket/wire.
1772 send_queue = smbXcli_conn_send_queue(self->cli->conn);
1773 flush_req = tevent_queue_wait_send(req,
1774 self->ev,
1775 send_queue);
1776 endtime = timeval_current_ofs_msec(self->cli->timeout);
1777 ok = tevent_req_set_endtime(flush_req,
1778 self->ev,
1779 endtime);
1780 if (!ok) {
1781 TALLOC_FREE(req);
1782 PyErr_NoMemory();
1783 return NULL;
1785 ok = py_tevent_req_wait_exc(self, flush_req);
1786 if (!ok) {
1787 TALLOC_FREE(req);
1788 return NULL;
1790 TALLOC_FREE(flush_req);
1792 py_notify_state = (struct py_cli_notify_state *)
1793 py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
1794 if (py_notify_state == NULL) {
1795 TALLOC_FREE(req);
1796 PyErr_NoMemory();
1797 return NULL;
1799 Py_INCREF(self);
1800 py_notify_state->py_cli_state = self;
1801 py_notify_state->req = req;
1803 return (PyObject *)py_notify_state;
1806 static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
1807 PyObject *args,
1808 PyObject *kwds)
1810 struct py_cli_state *py_cli_state = self->py_cli_state;
1811 struct tevent_req *req = self->req;
1812 uint32_t i;
1813 uint32_t num_changes = 0;
1814 struct notify_change *changes = NULL;
1815 PyObject *result = NULL;
1816 NTSTATUS status;
1817 bool ok;
1818 static const char *kwlist[] = {
1819 "wait",
1820 NULL
1822 PyObject *py_wait = Py_False;
1823 bool wait = false;
1824 bool pending;
1826 ok = ParseTupleAndKeywords(args,
1827 kwds,
1828 "O",
1829 kwlist,
1830 &py_wait);
1831 if (!ok) {
1832 return NULL;
1835 wait = PyObject_IsTrue(py_wait);
1837 if (req == NULL) {
1838 PyErr_SetString(PyExc_RuntimeError,
1839 "TODO req == NULL "
1840 "- missing change notify request?");
1841 return NULL;
1844 pending = tevent_req_is_in_progress(req);
1845 if (pending && !wait) {
1846 Py_RETURN_NONE;
1849 if (pending) {
1850 struct timeval endtime;
1852 endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
1853 ok = tevent_req_set_endtime(req,
1854 py_cli_state->ev,
1855 endtime);
1856 if (!ok) {
1857 TALLOC_FREE(req);
1858 PyErr_NoMemory();
1859 return NULL;
1863 ok = py_tevent_req_wait_exc(py_cli_state, req);
1864 self->req = NULL;
1865 Py_CLEAR(self->py_cli_state);
1866 if (!ok) {
1867 return NULL;
1870 status = cli_notify_recv(req, req, &num_changes, &changes);
1871 if (!NT_STATUS_IS_OK(status)) {
1872 TALLOC_FREE(req);
1873 PyErr_SetNTSTATUS(status);
1874 return NULL;
1877 result = Py_BuildValue("[]");
1878 if (result == NULL) {
1879 TALLOC_FREE(req);
1880 return NULL;
1883 for (i = 0; i < num_changes; i++) {
1884 PyObject *change = NULL;
1885 int ret;
1887 change = Py_BuildValue("{s:s,s:I}",
1888 "name", changes[i].name,
1889 "action", changes[i].action);
1890 if (change == NULL) {
1891 Py_XDECREF(result);
1892 TALLOC_FREE(req);
1893 return NULL;
1896 ret = PyList_Append(result, change);
1897 Py_DECREF(change);
1898 if (ret == -1) {
1899 Py_XDECREF(result);
1900 TALLOC_FREE(req);
1901 return NULL;
1905 TALLOC_FREE(req);
1906 return result;
1909 static PyMethodDef py_cli_notify_state_methods[] = {
1911 .ml_name = "get_changes",
1912 .ml_meth = (PyCFunction)py_cli_notify_get_changes,
1913 .ml_flags = METH_VARARGS|METH_KEYWORDS,
1914 .ml_doc = "Wait for change notifications: \n"
1915 "N.get_changes(wait=BOOLEAN) -> "
1916 "change notifications as a dictionary\n"
1917 "\t\tList contents of a directory. The keys are, \n"
1918 "\t\t\tname: name of changed object\n"
1919 "\t\t\taction: type of the change\n"
1920 "None is returned if there's no response yet and "
1921 "wait=False is passed"
1924 .ml_name = NULL
1928 static PyTypeObject py_cli_notify_state_type = {
1929 PyVarObject_HEAD_INIT(NULL, 0)
1930 .tp_name = "libsmb_samba_cwrapper.Notify",
1931 .tp_basicsize = sizeof(struct py_cli_notify_state),
1932 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1933 .tp_doc = "notify request",
1934 .tp_dealloc = (destructor)py_cli_notify_state_dealloc,
1935 .tp_methods = py_cli_notify_state_methods,
1939 * Helper to add posix directory listing entries to an overall Python list
1941 static NTSTATUS list_posix_helper(struct file_info *finfo,
1942 const char *mask, void *state)
1944 PyObject *result = (PyObject *)state;
1945 PyObject *file = NULL;
1946 struct dom_sid_buf owner_buf, group_buf;
1947 int ret;
1950 * Build a dictionary representing the file info.
1952 file = Py_BuildValue("{s:s,s:I,"
1953 "s:K,s:K,"
1954 "s:l,s:l,s:l,s:l,"
1955 "s:i,s:K,s:i,s:i,s:I,"
1956 "s:s,s:s,s:k}",
1957 "name",
1958 finfo->name,
1959 "attrib",
1960 finfo->attr,
1961 "size",
1962 finfo->size,
1963 "allocaction_size",
1964 finfo->allocated_size,
1965 "btime",
1966 convert_timespec_to_time_t(finfo->btime_ts),
1967 "atime",
1968 convert_timespec_to_time_t(finfo->atime_ts),
1969 "mtime",
1970 convert_timespec_to_time_t(finfo->mtime_ts),
1971 "ctime",
1972 convert_timespec_to_time_t(finfo->ctime_ts),
1973 "perms",
1974 finfo->st_ex_mode,
1975 "ino",
1976 finfo->ino,
1977 "dev",
1978 finfo->st_ex_dev,
1979 "nlink",
1980 finfo->st_ex_nlink,
1981 "reparse_tag",
1982 finfo->reparse_tag,
1983 "owner_sid",
1984 dom_sid_str_buf(&finfo->owner_sid, &owner_buf),
1985 "group_sid",
1986 dom_sid_str_buf(&finfo->group_sid, &group_buf),
1987 "reparse_tag",
1988 (unsigned long)finfo->reparse_tag);
1989 if (file == NULL) {
1990 return NT_STATUS_NO_MEMORY;
1993 ret = PyList_Append(result, file);
1994 Py_CLEAR(file);
1995 if (ret == -1) {
1996 return NT_STATUS_INTERNAL_ERROR;
1999 return NT_STATUS_OK;
2003 * Helper to add directory listing entries to an overall Python list
2005 static NTSTATUS list_helper(struct file_info *finfo,
2006 const char *mask, void *state)
2008 PyObject *result = (PyObject *)state;
2009 PyObject *file = NULL;
2010 PyObject *size = NULL;
2011 int ret;
2013 /* suppress '.' and '..' in the results we return */
2014 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2015 return NT_STATUS_OK;
2017 size = PyLong_FromUnsignedLongLong(finfo->size);
2019 * Build a dictionary representing the file info.
2020 * Note: Windows does not always return short_name (so it may be None)
2022 file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l,s:k}",
2023 "name",
2024 finfo->name,
2025 "attrib",
2026 (int)finfo->attr,
2027 "short_name",
2028 finfo->short_name,
2029 "size",
2030 size,
2031 "mtime",
2032 convert_timespec_to_time_t(finfo->mtime_ts),
2033 "reparse_tag",
2034 (unsigned long)finfo->reparse_tag);
2036 Py_CLEAR(size);
2038 if (file == NULL) {
2039 return NT_STATUS_NO_MEMORY;
2042 if (finfo->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
2043 unsigned long tag = finfo->reparse_tag;
2045 ret = PyDict_SetItemString(
2046 file,
2047 "reparse_tag",
2048 PyLong_FromUnsignedLong(tag));
2049 if (ret == -1) {
2050 return NT_STATUS_INTERNAL_ERROR;
2054 ret = PyList_Append(result, file);
2055 Py_CLEAR(file);
2056 if (ret == -1) {
2057 return NT_STATUS_INTERNAL_ERROR;
2060 return NT_STATUS_OK;
2063 struct do_listing_state {
2064 const char *mask;
2065 NTSTATUS (*callback_fn)(
2066 struct file_info *finfo,
2067 const char *mask,
2068 void *private_data);
2069 void *private_data;
2070 NTSTATUS status;
2073 static void do_listing_cb(struct tevent_req *subreq)
2075 struct do_listing_state *state = tevent_req_callback_data_void(subreq);
2076 struct file_info *finfo = NULL;
2078 state->status = cli_list_recv(subreq, NULL, &finfo);
2079 if (!NT_STATUS_IS_OK(state->status)) {
2080 return;
2082 state->callback_fn(finfo, state->mask, state->private_data);
2083 TALLOC_FREE(finfo);
2086 static NTSTATUS do_listing(struct py_cli_state *self,
2087 const char *base_dir, const char *user_mask,
2088 uint16_t attribute,
2089 unsigned int info_level,
2090 NTSTATUS (*callback_fn)(struct file_info *,
2091 const char *, void *),
2092 void *priv)
2094 char *mask = NULL;
2095 struct do_listing_state state = {
2096 .mask = mask,
2097 .callback_fn = callback_fn,
2098 .private_data = priv,
2100 struct tevent_req *req = NULL;
2101 NTSTATUS status;
2103 if (user_mask == NULL) {
2104 mask = talloc_asprintf(NULL, "%s\\*", base_dir);
2105 } else {
2106 mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
2109 if (mask == NULL) {
2110 return NT_STATUS_NO_MEMORY;
2112 dos_format(mask);
2114 req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
2115 info_level);
2116 if (req == NULL) {
2117 status = NT_STATUS_NO_MEMORY;
2118 goto done;
2120 tevent_req_set_callback(req, do_listing_cb, &state);
2122 if (!py_tevent_req_wait_exc(self, req)) {
2123 return NT_STATUS_INTERNAL_ERROR;
2125 TALLOC_FREE(req);
2127 status = state.status;
2128 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
2129 status = NT_STATUS_OK;
2132 done:
2133 TALLOC_FREE(mask);
2134 return status;
2137 static PyObject *py_cli_list(struct py_cli_state *self,
2138 PyObject *args,
2139 PyObject *kwds)
2141 char *base_dir;
2142 char *user_mask = NULL;
2143 unsigned int attribute = LIST_ATTRIBUTE_MASK;
2144 unsigned int info_level = 0;
2145 NTSTATUS status;
2146 enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2147 PyObject *result = NULL;
2148 const char *kwlist[] = { "directory", "mask", "attribs",
2149 "info_level", NULL };
2150 NTSTATUS (*callback_fn)(struct file_info *, const char *, void *) =
2151 list_helper;
2153 if (!ParseTupleAndKeywords(args, kwds, "z|sII:list", kwlist,
2154 &base_dir, &user_mask, &attribute,
2155 &info_level)) {
2156 return NULL;
2159 result = Py_BuildValue("[]");
2160 if (result == NULL) {
2161 return NULL;
2164 if (!info_level) {
2165 if (proto >= PROTOCOL_SMB2_02) {
2166 info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
2167 } else {
2168 info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
2172 if (info_level == SMB2_FIND_POSIX_INFORMATION) {
2173 callback_fn = list_posix_helper;
2175 status = do_listing(self, base_dir, user_mask, attribute,
2176 info_level, callback_fn, result);
2178 if (!NT_STATUS_IS_OK(status)) {
2179 Py_XDECREF(result);
2180 PyErr_SetNTSTATUS(status);
2181 return NULL;
2184 return result;
2187 static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
2189 NTSTATUS status;
2190 const char *filename = NULL;
2191 struct tevent_req *req = NULL;
2192 const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2194 if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
2195 return NULL;
2198 req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
2199 if (!py_tevent_req_wait_exc(self, req)) {
2200 return NULL;
2202 status = cli_unlink_recv(req);
2203 TALLOC_FREE(req);
2204 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2206 Py_RETURN_NONE;
2209 static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
2211 NTSTATUS status;
2212 struct tevent_req *req = NULL;
2213 const char *dirname = NULL;
2215 if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
2216 return NULL;
2219 req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
2220 if (!py_tevent_req_wait_exc(self, req)) {
2221 return NULL;
2223 status = cli_rmdir_recv(req);
2224 TALLOC_FREE(req);
2225 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2227 Py_RETURN_NONE;
2231 * Create a directory
2233 static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
2235 NTSTATUS status;
2236 const char *dirname = NULL;
2237 struct tevent_req *req = NULL;
2239 if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
2240 return NULL;
2243 req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
2244 if (!py_tevent_req_wait_exc(self, req)) {
2245 return NULL;
2247 status = cli_mkdir_recv(req);
2248 TALLOC_FREE(req);
2249 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2251 Py_RETURN_NONE;
2255 * Does a whoami call
2257 static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
2258 PyObject *Py_UNUSED(ignored))
2260 TALLOC_CTX *frame = talloc_stackframe();
2261 NTSTATUS status;
2262 struct tevent_req *req = NULL;
2263 uint64_t uid;
2264 uint64_t gid;
2265 uint32_t num_gids;
2266 uint64_t *gids = NULL;
2267 uint32_t num_sids;
2268 struct dom_sid *sids = NULL;
2269 bool guest;
2270 PyObject *py_gids = NULL;
2271 PyObject *py_sids = NULL;
2272 PyObject *py_guest = NULL;
2273 PyObject *py_ret = NULL;
2274 Py_ssize_t i;
2276 req = cli_posix_whoami_send(frame, self->ev, self->cli);
2277 if (!py_tevent_req_wait_exc(self, req)) {
2278 goto fail;
2280 status = cli_posix_whoami_recv(req,
2281 frame,
2282 &uid,
2283 &gid,
2284 &num_gids,
2285 &gids,
2286 &num_sids,
2287 &sids,
2288 &guest);
2289 if (!NT_STATUS_IS_OK(status)) {
2290 PyErr_SetNTSTATUS(status);
2291 goto fail;
2293 if (num_gids > PY_SSIZE_T_MAX) {
2294 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
2295 goto fail;
2297 if (num_sids > PY_SSIZE_T_MAX) {
2298 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
2299 goto fail;
2302 py_gids = PyList_New(num_gids);
2303 if (!py_gids) {
2304 goto fail;
2306 for (i = 0; i < num_gids; ++i) {
2307 int ret;
2308 PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
2309 if (!py_item) {
2310 goto fail2;
2313 ret = PyList_SetItem(py_gids, i, py_item);
2314 if (ret) {
2315 goto fail2;
2318 py_sids = PyList_New(num_sids);
2319 if (!py_sids) {
2320 goto fail2;
2322 for (i = 0; i < num_sids; ++i) {
2323 int ret;
2324 struct dom_sid *sid;
2325 PyObject *py_item;
2327 sid = dom_sid_dup(frame, &sids[i]);
2328 if (!sid) {
2329 PyErr_NoMemory();
2330 goto fail3;
2333 py_item = pytalloc_steal(dom_sid_Type, sid);
2334 if (!py_item) {
2335 PyErr_NoMemory();
2336 goto fail3;
2339 ret = PyList_SetItem(py_sids, i, py_item);
2340 if (ret) {
2341 goto fail3;
2345 py_guest = guest ? Py_True : Py_False;
2347 py_ret = Py_BuildValue("KKNNO",
2348 uid,
2349 gid,
2350 py_gids,
2351 py_sids,
2352 py_guest);
2353 if (!py_ret) {
2354 goto fail3;
2357 TALLOC_FREE(frame);
2358 return py_ret;
2360 fail3:
2361 Py_CLEAR(py_sids);
2363 fail2:
2364 Py_CLEAR(py_gids);
2366 fail:
2367 TALLOC_FREE(frame);
2368 return NULL;
2372 * Checks existence of a directory
2374 static bool check_dir_path(struct py_cli_state *self, const char *path)
2376 NTSTATUS status;
2377 struct tevent_req *req = NULL;
2379 req = cli_chkpath_send(NULL, self->ev, self->cli, path);
2380 if (!py_tevent_req_wait_exc(self, req)) {
2381 return false;
2383 status = cli_chkpath_recv(req);
2384 TALLOC_FREE(req);
2386 return NT_STATUS_IS_OK(status);
2389 static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
2391 const char *path = NULL;
2392 bool dir_exists;
2394 if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
2395 return NULL;
2398 dir_exists = check_dir_path(self, path);
2399 return PyBool_FromLong(dir_exists);
2402 static PyObject *py_smb_have_posix(struct py_cli_state *self,
2403 PyObject *Py_UNUSED(ignored))
2405 bool posix = smbXcli_conn_have_posix(self->cli->conn);
2407 if (posix) {
2408 Py_RETURN_TRUE;
2410 Py_RETURN_FALSE;
2413 static PyObject *py_smb_protocol(struct py_cli_state *self,
2414 PyObject *Py_UNUSED(ignored))
2416 enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2417 PyObject *result = PyLong_FromLong(proto);
2418 return result;
2421 static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
2423 int fnum;
2424 unsigned sinfo;
2425 struct tevent_req *req = NULL;
2426 struct security_descriptor *sd = NULL;
2427 NTSTATUS status;
2429 if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
2430 return NULL;
2433 req = cli_query_security_descriptor_send(
2434 NULL, self->ev, self->cli, fnum, sinfo);
2435 if (!py_tevent_req_wait_exc(self, req)) {
2436 return NULL;
2438 status = cli_query_security_descriptor_recv(req, NULL, &sd);
2439 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2441 return py_return_ndr_struct(
2442 "samba.dcerpc.security", "descriptor", sd, sd);
2445 static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
2447 PyObject *py_sd = NULL;
2448 struct tevent_req *req = NULL;
2449 struct security_descriptor *sd = NULL;
2450 uint16_t fnum;
2451 unsigned int sinfo;
2452 NTSTATUS status;
2454 if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
2455 return NULL;
2458 sd = pytalloc_get_type(py_sd, struct security_descriptor);
2459 if (!sd) {
2460 PyErr_Format(PyExc_TypeError,
2461 "Expected dcerpc.security.descriptor as argument, got %s",
2462 pytalloc_get_name(py_sd));
2463 return NULL;
2466 req = cli_set_security_descriptor_send(
2467 NULL, self->ev, self->cli, fnum, sinfo, sd);
2468 if (!py_tevent_req_wait_exc(self, req)) {
2469 return NULL;
2472 status = cli_set_security_descriptor_recv(req);
2473 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2475 Py_RETURN_NONE;
2478 static PyObject *py_smb_smb1_posix(
2479 struct py_cli_state *self, PyObject *Py_UNUSED(ignored))
2481 NTSTATUS status;
2482 struct tevent_req *req = NULL;
2483 uint16_t major, minor;
2484 uint32_t caplow, caphigh;
2485 PyObject *result = NULL;
2487 req = cli_unix_extensions_version_send(NULL, self->ev, self->cli);
2488 if (!py_tevent_req_wait_exc(self, req)) {
2489 return NULL;
2491 status = cli_unix_extensions_version_recv(
2492 req, &major, &minor, &caplow, &caphigh);
2493 TALLOC_FREE(req);
2494 if (!NT_STATUS_IS_OK(status)) {
2495 PyErr_SetNTSTATUS(status);
2496 return NULL;
2499 req = cli_set_unix_extensions_capabilities_send(
2500 NULL, self->ev, self->cli, major, minor, caplow, caphigh);
2501 if (!py_tevent_req_wait_exc(self, req)) {
2502 return NULL;
2504 status = cli_set_unix_extensions_capabilities_recv(req);
2505 TALLOC_FREE(req);
2506 if (!NT_STATUS_IS_OK(status)) {
2507 PyErr_SetNTSTATUS(status);
2508 return NULL;
2511 result = Py_BuildValue(
2512 "[IIII]",
2513 (unsigned)minor,
2514 (unsigned)major,
2515 (unsigned)caplow,
2516 (unsigned)caphigh);
2517 return result;
2520 static PyObject *py_smb_smb1_readlink(
2521 struct py_cli_state *self, PyObject *args)
2523 NTSTATUS status;
2524 const char *filename = NULL;
2525 struct tevent_req *req = NULL;
2526 char *target = NULL;
2527 PyObject *result = NULL;
2529 if (!PyArg_ParseTuple(args, "s:smb1_readlink", &filename)) {
2530 return NULL;
2533 req = cli_posix_readlink_send(NULL, self->ev, self->cli, filename);
2534 if (!py_tevent_req_wait_exc(self, req)) {
2535 return NULL;
2537 status = cli_posix_readlink_recv(req, NULL, &target);
2538 TALLOC_FREE(req);
2539 if (!NT_STATUS_IS_OK(status)) {
2540 PyErr_SetNTSTATUS(status);
2541 return NULL;
2544 result = PyBytes_FromString(target);
2545 TALLOC_FREE(target);
2546 return result;
2549 static PyObject *py_smb_smb1_symlink(
2550 struct py_cli_state *self, PyObject *args)
2552 NTSTATUS status;
2553 const char *target = NULL, *newname = NULL;
2554 struct tevent_req *req = NULL;
2556 if (!PyArg_ParseTuple(args, "ss:smb1_symlink", &target, &newname)) {
2557 return NULL;
2560 req = cli_posix_symlink_send(
2561 NULL, self->ev, self->cli, target, newname);
2562 if (!py_tevent_req_wait_exc(self, req)) {
2563 return NULL;
2565 status = cli_posix_symlink_recv(req);
2566 TALLOC_FREE(req);
2567 if (!NT_STATUS_IS_OK(status)) {
2568 PyErr_SetNTSTATUS(status);
2569 return NULL;
2572 Py_RETURN_NONE;
2575 static PyObject *py_smb_smb1_stat(
2576 struct py_cli_state *self, PyObject *args)
2578 NTSTATUS status;
2579 const char *fname = NULL;
2580 struct tevent_req *req = NULL;
2581 struct stat_ex sbuf = { .st_ex_nlink = 0, };
2583 if (!PyArg_ParseTuple(args, "s:smb1_stat", &fname)) {
2584 return NULL;
2587 req = cli_posix_stat_send(NULL, self->ev, self->cli, fname);
2588 if (!py_tevent_req_wait_exc(self, req)) {
2589 return NULL;
2591 status = cli_posix_stat_recv(req, &sbuf);
2592 TALLOC_FREE(req);
2593 if (!NT_STATUS_IS_OK(status)) {
2594 PyErr_SetNTSTATUS(status);
2595 return NULL;
2598 return Py_BuildValue(
2599 "{sLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsL}",
2600 "dev",
2601 (unsigned long long)sbuf.st_ex_dev,
2602 "ino",
2603 (unsigned long long)sbuf.st_ex_ino,
2604 "mode",
2605 (unsigned long long)sbuf.st_ex_mode,
2606 "nlink",
2607 (unsigned long long)sbuf.st_ex_nlink,
2608 "uid",
2609 (unsigned long long)sbuf.st_ex_uid,
2610 "gid",
2611 (unsigned long long)sbuf.st_ex_gid,
2612 "rdev",
2613 (unsigned long long)sbuf.st_ex_size,
2614 "atime_sec",
2615 (unsigned long long)sbuf.st_ex_atime.tv_sec,
2616 "atime_nsec",
2617 (unsigned long long)sbuf.st_ex_atime.tv_nsec,
2618 "mtime_sec",
2619 (unsigned long long)sbuf.st_ex_mtime.tv_sec,
2620 "mtime_nsec",
2621 (unsigned long long)sbuf.st_ex_mtime.tv_nsec,
2622 "ctime_sec",
2623 (unsigned long long)sbuf.st_ex_ctime.tv_sec,
2624 "ctime_nsec",
2625 (unsigned long long)sbuf.st_ex_ctime.tv_nsec,
2626 "btime_sec",
2627 (unsigned long long)sbuf.st_ex_btime.tv_sec,
2628 "btime_nsec",
2629 (unsigned long long)sbuf.st_ex_btime.tv_nsec,
2630 "cached_dos_attributes",
2631 (unsigned long long)sbuf.cached_dos_attributes,
2632 "blksize",
2633 (unsigned long long)sbuf.st_ex_blksize,
2634 "blocks",
2635 (unsigned long long)sbuf.st_ex_blocks,
2636 "flags",
2637 (unsigned long long)sbuf.st_ex_flags,
2638 "iflags",
2639 (unsigned long long)sbuf.st_ex_iflags);
2642 static PyObject *py_cli_mknod(
2643 struct py_cli_state *self, PyObject *args, PyObject *kwds)
2645 char *fname = NULL;
2646 int mode = 0, major = 0, minor = 0, dev = 0;
2647 struct tevent_req *req = NULL;
2648 static const char *kwlist[] = {
2649 "fname", "mode", "major", "minor", NULL,
2651 NTSTATUS status;
2652 bool ok;
2654 ok = ParseTupleAndKeywords(
2655 args,
2656 kwds,
2657 "sI|II:mknod",
2658 kwlist,
2659 &fname,
2660 &mode,
2661 &major,
2662 &minor);
2663 if (!ok) {
2664 return NULL;
2667 #if defined(HAVE_MAKEDEV)
2668 dev = makedev(major, minor);
2669 #endif
2671 req = cli_mknod_send(
2672 NULL, self->ev, self->cli, fname, mode, dev);
2673 if (!py_tevent_req_wait_exc(self, req)) {
2674 return NULL;
2676 status = cli_mknod_recv(req);
2677 TALLOC_FREE(req);
2678 if (!NT_STATUS_IS_OK(status)) {
2679 PyErr_SetNTSTATUS(status);
2680 return NULL;
2682 Py_RETURN_NONE;
2685 static PyObject *py_cli_fsctl(
2686 struct py_cli_state *self, PyObject *args, PyObject *kwds)
2688 int fnum, ctl_code;
2689 int max_out = 0;
2690 char *buf = NULL;
2691 Py_ssize_t buflen;
2692 DATA_BLOB in = { .data = NULL, };
2693 DATA_BLOB out = { .data = NULL, };
2694 struct tevent_req *req = NULL;
2695 PyObject *result = NULL;
2696 static const char *kwlist[] = {
2697 "fnum", "ctl_code", "in", "max_out", NULL,
2699 NTSTATUS status;
2700 bool ok;
2702 ok = ParseTupleAndKeywords(
2703 args,
2704 kwds,
2705 "ii" PYARG_BYTES_LEN "i",
2706 kwlist,
2707 &fnum,
2708 &ctl_code,
2709 &buf,
2710 &buflen,
2711 &max_out);
2712 if (!ok) {
2713 return NULL;
2716 in = (DATA_BLOB) { .data = (uint8_t *)buf, .length = buflen, };
2718 req = cli_fsctl_send(
2719 NULL, self->ev, self->cli, fnum, ctl_code, &in, max_out);
2721 if (!py_tevent_req_wait_exc(self, req)) {
2722 return NULL;
2725 status = cli_fsctl_recv(req, NULL, &out);
2726 if (!NT_STATUS_IS_OK(status)) {
2727 PyErr_SetNTSTATUS(status);
2728 return NULL;
2731 result = PyBytes_FromStringAndSize((char *)out.data, out.length);
2732 data_blob_free(&out);
2733 return result;
2736 static PyMethodDef py_cli_state_methods[] = {
2737 { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
2738 "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
2739 { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
2740 "Ping the server connection" },
2741 { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
2742 METH_VARARGS|METH_KEYWORDS,
2743 "Open a file" },
2744 { "create_ex",
2745 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create_ex),
2746 METH_VARARGS|METH_KEYWORDS,
2747 "Open a file, SMB2 version returning create contexts" },
2748 { "close", (PyCFunction)py_cli_close, METH_VARARGS,
2749 "Close a file handle" },
2750 { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
2751 METH_VARARGS|METH_KEYWORDS,
2752 "Write to a file handle" },
2753 { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
2754 METH_VARARGS|METH_KEYWORDS,
2755 "Read from a file handle" },
2756 { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
2757 py_cli_ftruncate),
2758 METH_VARARGS|METH_KEYWORDS,
2759 "Truncate a file" },
2760 { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
2761 py_cli_delete_on_close),
2762 METH_VARARGS|METH_KEYWORDS,
2763 "Set/Reset the delete on close flag" },
2764 { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
2765 METH_VARARGS|METH_KEYWORDS,
2766 "Wait for change notifications: \n"
2767 "notify(fnum, buffer_size, completion_filter...) -> "
2768 "libsmb_samba_internal.Notify request handle\n" },
2769 { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
2770 METH_VARARGS|METH_KEYWORDS,
2771 "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
2772 "directory contents as a dictionary\n"
2773 "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
2774 "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
2775 "\t\tList contents of a directory. The keys are, \n"
2776 "\t\t\tname: Long name of the directory item\n"
2777 "\t\t\tshort_name: Short name of the directory item\n"
2778 "\t\t\tsize: File size in bytes\n"
2779 "\t\t\tattrib: Attributes\n"
2780 "\t\t\tmtime: Modification time\n" },
2781 { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
2782 METH_VARARGS, "Wait for an oplock break" },
2783 { "unlink", (PyCFunction)py_smb_unlink,
2784 METH_VARARGS,
2785 "unlink(path) -> None\n\n \t\tDelete a file." },
2786 { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
2787 "mkdir(path) -> None\n\n \t\tCreate a directory." },
2788 { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
2789 "posix_whoami() -> (uid, gid, gids, sids, guest)" },
2790 { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
2791 "rmdir(path) -> None\n\n \t\tDelete a directory." },
2792 { "rename",
2793 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
2794 METH_VARARGS|METH_KEYWORDS,
2795 "rename(src,dst) -> None\n\n \t\tRename a file." },
2796 { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
2797 "chkpath(dir_path) -> True or False\n\n"
2798 "\t\tReturn true if directory exists, false otherwise." },
2799 { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
2800 "savefile(path, bytes) -> None\n\n"
2801 "\t\tWrite bytes to file." },
2802 { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
2803 "loadfile(path) -> file contents as a bytes object"
2804 "\n\n\t\tRead contents of a file." },
2805 { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
2806 "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
2807 "\t\tGet security descriptor for opened file." },
2808 { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
2809 "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
2810 "\t\tSet security descriptor for opened file." },
2811 { "protocol",
2812 (PyCFunction)py_smb_protocol,
2813 METH_NOARGS,
2814 "protocol() -> Number"
2816 { "have_posix",
2817 (PyCFunction)py_smb_have_posix,
2818 METH_NOARGS,
2819 "have_posix() -> True/False\n\n"
2820 "\t\tReturn if the server has posix extensions"
2822 { "smb1_posix",
2823 (PyCFunction)py_smb_smb1_posix,
2824 METH_NOARGS,
2825 "Negotiate SMB1 posix extensions",
2827 { "smb1_readlink",
2828 (PyCFunction)py_smb_smb1_readlink,
2829 METH_VARARGS,
2830 "smb1_readlink(path) -> link target",
2832 { "smb1_symlink",
2833 (PyCFunction)py_smb_smb1_symlink,
2834 METH_VARARGS,
2835 "smb1_symlink(target, newname) -> None",
2837 { "smb1_stat",
2838 (PyCFunction)py_smb_smb1_stat,
2839 METH_VARARGS,
2840 "smb1_stat(path) -> stat info",
2842 { "fsctl",
2843 (PyCFunction)py_cli_fsctl,
2844 METH_VARARGS|METH_KEYWORDS,
2845 "fsctl(fnum, ctl_code, in_bytes, max_out) -> out_bytes",
2848 "qfileinfo",
2849 (PyCFunction)py_cli_qfileinfo,
2850 METH_VARARGS | METH_KEYWORDS,
2851 "qfileinfo(fnum, level) -> blob",
2853 { "mknod",
2854 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_mknod),
2855 METH_VARARGS|METH_KEYWORDS,
2856 "mknod(path, mode | major, minor)",
2858 { NULL, NULL, 0, NULL }
2861 static PyTypeObject py_cli_state_type = {
2862 PyVarObject_HEAD_INIT(NULL, 0)
2863 .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
2864 .tp_basicsize = sizeof(struct py_cli_state),
2865 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2866 .tp_doc = "libsmb cwrapper connection",
2867 .tp_new = py_cli_state_new,
2868 .tp_init = (initproc)py_cli_state_init,
2869 .tp_dealloc = (destructor)py_cli_state_dealloc,
2870 .tp_methods = py_cli_state_methods,
2873 static PyMethodDef py_libsmb_methods[] = {
2874 {0},
2877 void initlibsmb_samba_cwrapper(void);
2879 static struct PyModuleDef moduledef = {
2880 PyModuleDef_HEAD_INIT,
2881 .m_name = "libsmb_samba_cwrapper",
2882 .m_doc = "libsmb wrapper",
2883 .m_size = -1,
2884 .m_methods = py_libsmb_methods,
2887 MODULE_INIT_FUNC(libsmb_samba_cwrapper)
2889 PyObject *m = NULL;
2890 PyObject *mod = NULL;
2892 talloc_stackframe();
2894 if (PyType_Ready(&py_cli_state_type) < 0) {
2895 return NULL;
2897 if (PyType_Ready(&py_cli_notify_state_type) < 0) {
2898 return NULL;
2901 m = PyModule_Create(&moduledef);
2902 if (m == NULL) {
2903 return m;
2906 /* Import dom_sid type from dcerpc.security */
2907 mod = PyImport_ImportModule("samba.dcerpc.security");
2908 if (mod == NULL) {
2909 return NULL;
2912 dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
2913 if (dom_sid_Type == NULL) {
2914 Py_DECREF(mod);
2915 return NULL;
2918 Py_INCREF(&py_cli_state_type);
2919 PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
2921 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
2923 ADD_FLAGS(PROTOCOL_NONE);
2924 ADD_FLAGS(PROTOCOL_CORE);
2925 ADD_FLAGS(PROTOCOL_COREPLUS);
2926 ADD_FLAGS(PROTOCOL_LANMAN1);
2927 ADD_FLAGS(PROTOCOL_LANMAN2);
2928 ADD_FLAGS(PROTOCOL_NT1);
2929 ADD_FLAGS(PROTOCOL_SMB2_02);
2930 ADD_FLAGS(PROTOCOL_SMB2_10);
2931 ADD_FLAGS(PROTOCOL_SMB3_00);
2932 ADD_FLAGS(PROTOCOL_SMB3_02);
2933 ADD_FLAGS(PROTOCOL_SMB3_11);
2935 ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
2936 ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
2937 ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
2938 ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
2939 ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
2940 ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
2941 ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
2942 ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
2943 ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
2944 ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
2945 ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
2946 ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
2947 ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
2948 ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
2949 ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
2950 ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
2952 ADD_FLAGS(FILE_DIRECTORY_FILE);
2953 ADD_FLAGS(FILE_WRITE_THROUGH);
2954 ADD_FLAGS(FILE_SEQUENTIAL_ONLY);
2955 ADD_FLAGS(FILE_NO_INTERMEDIATE_BUFFERING);
2956 ADD_FLAGS(FILE_SYNCHRONOUS_IO_ALERT);
2957 ADD_FLAGS(FILE_SYNCHRONOUS_IO_NONALERT);
2958 ADD_FLAGS(FILE_NON_DIRECTORY_FILE);
2959 ADD_FLAGS(FILE_CREATE_TREE_CONNECTION);
2960 ADD_FLAGS(FILE_COMPLETE_IF_OPLOCKED);
2961 ADD_FLAGS(FILE_NO_EA_KNOWLEDGE);
2962 ADD_FLAGS(FILE_EIGHT_DOT_THREE_ONLY);
2963 ADD_FLAGS(FILE_RANDOM_ACCESS);
2964 ADD_FLAGS(FILE_DELETE_ON_CLOSE);
2965 ADD_FLAGS(FILE_OPEN_BY_FILE_ID);
2966 ADD_FLAGS(FILE_OPEN_FOR_BACKUP_INTENT);
2967 ADD_FLAGS(FILE_NO_COMPRESSION);
2968 ADD_FLAGS(FILE_RESERVER_OPFILTER);
2969 ADD_FLAGS(FILE_OPEN_REPARSE_POINT);
2970 ADD_FLAGS(FILE_OPEN_NO_RECALL);
2971 ADD_FLAGS(FILE_OPEN_FOR_FREE_SPACE_QUERY);
2973 ADD_FLAGS(FILE_SHARE_READ);
2974 ADD_FLAGS(FILE_SHARE_WRITE);
2975 ADD_FLAGS(FILE_SHARE_DELETE);
2977 /* change notify completion filter flags */
2978 ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
2979 ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
2980 ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
2981 ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
2982 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
2983 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
2984 ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
2985 ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
2986 ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
2987 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
2988 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
2989 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
2990 ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
2991 ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
2993 /* change notify action results */
2994 ADD_FLAGS(NOTIFY_ACTION_ADDED);
2995 ADD_FLAGS(NOTIFY_ACTION_REMOVED);
2996 ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
2997 ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
2998 ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
2999 ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
3000 ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
3001 ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
3003 /* CreateDisposition values */
3004 ADD_FLAGS(FILE_SUPERSEDE);
3005 ADD_FLAGS(FILE_OPEN);
3006 ADD_FLAGS(FILE_CREATE);
3007 ADD_FLAGS(FILE_OPEN_IF);
3008 ADD_FLAGS(FILE_OVERWRITE);
3009 ADD_FLAGS(FILE_OVERWRITE_IF);
3011 ADD_FLAGS(FSCTL_DFS_GET_REFERRALS);
3012 ADD_FLAGS(FSCTL_DFS_GET_REFERRALS_EX);
3013 ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_1);
3014 ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_2);
3015 ADD_FLAGS(FSCTL_REQUEST_BATCH_OPLOCK);
3016 ADD_FLAGS(FSCTL_OPLOCK_BREAK_ACKNOWLEDGE);
3017 ADD_FLAGS(FSCTL_OPBATCH_ACK_CLOSE_PENDING);
3018 ADD_FLAGS(FSCTL_OPLOCK_BREAK_NOTIFY);
3019 ADD_FLAGS(FSCTL_GET_COMPRESSION);
3020 ADD_FLAGS(FSCTL_FILESYS_GET_STATISTICS);
3021 ADD_FLAGS(FSCTL_GET_NTFS_VOLUME_DATA);
3022 ADD_FLAGS(FSCTL_IS_VOLUME_DIRTY);
3023 ADD_FLAGS(FSCTL_FIND_FILES_BY_SID);
3024 ADD_FLAGS(FSCTL_SET_OBJECT_ID);
3025 ADD_FLAGS(FSCTL_GET_OBJECT_ID);
3026 ADD_FLAGS(FSCTL_DELETE_OBJECT_ID);
3027 ADD_FLAGS(FSCTL_SET_REPARSE_POINT);
3028 ADD_FLAGS(FSCTL_GET_REPARSE_POINT);
3029 ADD_FLAGS(FSCTL_DELETE_REPARSE_POINT);
3030 ADD_FLAGS(FSCTL_SET_OBJECT_ID_EXTENDED);
3031 ADD_FLAGS(FSCTL_CREATE_OR_GET_OBJECT_ID);
3032 ADD_FLAGS(FSCTL_SET_SPARSE);
3033 ADD_FLAGS(FSCTL_SET_ZERO_DATA);
3034 ADD_FLAGS(FSCTL_SET_ZERO_ON_DEALLOCATION);
3035 ADD_FLAGS(FSCTL_READ_FILE_USN_DATA);
3036 ADD_FLAGS(FSCTL_WRITE_USN_CLOSE_RECORD);
3037 ADD_FLAGS(FSCTL_QUERY_ALLOCATED_RANGES);
3038 ADD_FLAGS(FSCTL_QUERY_ON_DISK_VOLUME_INFO);
3039 ADD_FLAGS(FSCTL_QUERY_SPARING_INFO);
3040 ADD_FLAGS(FSCTL_FILE_LEVEL_TRIM);
3041 ADD_FLAGS(FSCTL_OFFLOAD_READ);
3042 ADD_FLAGS(FSCTL_OFFLOAD_WRITE);
3043 ADD_FLAGS(FSCTL_SET_INTEGRITY_INFORMATION);
3044 ADD_FLAGS(FSCTL_DUP_EXTENTS_TO_FILE);
3045 ADD_FLAGS(FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX);
3046 ADD_FLAGS(FSCTL_STORAGE_QOS_CONTROL);
3047 ADD_FLAGS(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST);
3048 ADD_FLAGS(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT);
3049 ADD_FLAGS(FSCTL_PIPE_PEEK);
3050 ADD_FLAGS(FSCTL_NAMED_PIPE_READ_WRITE);
3051 ADD_FLAGS(FSCTL_PIPE_TRANSCEIVE);
3052 ADD_FLAGS(FSCTL_PIPE_WAIT);
3053 ADD_FLAGS(FSCTL_GET_SHADOW_COPY_DATA);
3054 ADD_FLAGS(FSCTL_SRV_ENUM_SNAPS);
3055 ADD_FLAGS(FSCTL_SRV_REQUEST_RESUME_KEY);
3056 ADD_FLAGS(FSCTL_SRV_COPYCHUNK);
3057 ADD_FLAGS(FSCTL_SRV_COPYCHUNK_WRITE);
3058 ADD_FLAGS(FSCTL_SRV_READ_HASH);
3059 ADD_FLAGS(FSCTL_LMR_REQ_RESILIENCY);
3060 ADD_FLAGS(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION);
3061 ADD_FLAGS(FSCTL_QUERY_NETWORK_INTERFACE_INFO);
3063 ADD_FLAGS(SYMLINK_ERROR_TAG);
3064 ADD_FLAGS(SYMLINK_FLAG_RELATIVE);
3065 ADD_FLAGS(SYMLINK_ADMIN);
3066 ADD_FLAGS(SYMLINK_UNTRUSTED);
3067 ADD_FLAGS(SYMLINK_TRUST_UNKNOWN);
3068 ADD_FLAGS(SYMLINK_TRUST_MASK);
3070 ADD_FLAGS(IO_REPARSE_TAG_RESERVED_ZERO);
3071 ADD_FLAGS(IO_REPARSE_TAG_SYMLINK);
3072 ADD_FLAGS(IO_REPARSE_TAG_MOUNT_POINT);
3073 ADD_FLAGS(IO_REPARSE_TAG_HSM);
3074 ADD_FLAGS(IO_REPARSE_TAG_SIS);
3075 ADD_FLAGS(IO_REPARSE_TAG_DFS);
3076 ADD_FLAGS(IO_REPARSE_TAG_NFS);
3078 ADD_FLAGS(FSCC_FILE_DIRECTORY_INFORMATION);
3079 ADD_FLAGS(FSCC_FILE_FULL_DIRECTORY_INFORMATION);
3080 ADD_FLAGS(FSCC_FILE_BOTH_DIRECTORY_INFORMATION);
3081 ADD_FLAGS(FSCC_FILE_BASIC_INFORMATION);
3082 ADD_FLAGS(FSCC_FILE_STANDARD_INFORMATION);
3083 ADD_FLAGS(FSCC_FILE_INTERNAL_INFORMATION);
3084 ADD_FLAGS(FSCC_FILE_EA_INFORMATION);
3085 ADD_FLAGS(FSCC_FILE_ACCESS_INFORMATION);
3086 ADD_FLAGS(FSCC_FILE_NAME_INFORMATION);
3087 ADD_FLAGS(FSCC_FILE_RENAME_INFORMATION);
3088 ADD_FLAGS(FSCC_FILE_LINK_INFORMATION);
3089 ADD_FLAGS(FSCC_FILE_NAMES_INFORMATION);
3090 ADD_FLAGS(FSCC_FILE_DISPOSITION_INFORMATION);
3091 ADD_FLAGS(FSCC_FILE_POSITION_INFORMATION);
3092 ADD_FLAGS(FSCC_FILE_FULL_EA_INFORMATION);
3093 ADD_FLAGS(FSCC_FILE_MODE_INFORMATION);
3094 ADD_FLAGS(FSCC_FILE_ALIGNMENT_INFORMATION);
3095 ADD_FLAGS(FSCC_FILE_ALL_INFORMATION);
3096 ADD_FLAGS(FSCC_FILE_ALLOCATION_INFORMATION);
3097 ADD_FLAGS(FSCC_FILE_END_OF_FILE_INFORMATION);
3098 ADD_FLAGS(FSCC_FILE_ALTERNATE_NAME_INFORMATION);
3099 ADD_FLAGS(FSCC_FILE_STREAM_INFORMATION);
3100 ADD_FLAGS(FSCC_FILE_PIPE_INFORMATION);
3101 ADD_FLAGS(FSCC_FILE_PIPE_LOCAL_INFORMATION);
3102 ADD_FLAGS(FSCC_FILE_PIPE_REMOTE_INFORMATION);
3103 ADD_FLAGS(FSCC_FILE_MAILSLOT_QUERY_INFORMATION);
3104 ADD_FLAGS(FSCC_FILE_MAILSLOT_SET_INFORMATION);
3105 ADD_FLAGS(FSCC_FILE_COMPRESSION_INFORMATION);
3106 ADD_FLAGS(FSCC_FILE_OBJECTID_INFORMATION);
3107 ADD_FLAGS(FSCC_FILE_COMPLETION_INFORMATION);
3108 ADD_FLAGS(FSCC_FILE_MOVE_CLUSTER_INFORMATION);
3109 ADD_FLAGS(FSCC_FILE_QUOTA_INFORMATION);
3110 ADD_FLAGS(FSCC_FILE_REPARSEPOINT_INFORMATION);
3111 ADD_FLAGS(FSCC_FILE_NETWORK_OPEN_INFORMATION);
3112 ADD_FLAGS(FSCC_FILE_ATTRIBUTE_TAG_INFORMATION);
3113 ADD_FLAGS(FSCC_FILE_TRACKING_INFORMATION);
3114 ADD_FLAGS(FSCC_FILE_ID_BOTH_DIRECTORY_INFORMATION);
3115 ADD_FLAGS(FSCC_FILE_ID_FULL_DIRECTORY_INFORMATION);
3116 ADD_FLAGS(FSCC_FILE_VALID_DATA_LENGTH_INFORMATION);
3117 ADD_FLAGS(FSCC_FILE_SHORT_NAME_INFORMATION);
3118 ADD_FLAGS(FSCC_FILE_SFIO_RESERVE_INFORMATION);
3119 ADD_FLAGS(FSCC_FILE_SFIO_VOLUME_INFORMATION);
3120 ADD_FLAGS(FSCC_FILE_HARD_LINK_INFORMATION);
3121 ADD_FLAGS(FSCC_FILE_NORMALIZED_NAME_INFORMATION);
3122 ADD_FLAGS(FSCC_FILE_ID_GLOBAL_TX_DIRECTORY_INFORMATION);
3123 ADD_FLAGS(FSCC_FILE_STANDARD_LINK_INFORMATION);
3124 ADD_FLAGS(FSCC_FILE_MAXIMUM_INFORMATION);
3126 #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
3128 ADD_STRING(SMB2_CREATE_TAG_EXTA);
3129 ADD_STRING(SMB2_CREATE_TAG_MXAC);
3130 ADD_STRING(SMB2_CREATE_TAG_SECD);
3131 ADD_STRING(SMB2_CREATE_TAG_DHNQ);
3132 ADD_STRING(SMB2_CREATE_TAG_DHNC);
3133 ADD_STRING(SMB2_CREATE_TAG_ALSI);
3134 ADD_STRING(SMB2_CREATE_TAG_TWRP);
3135 ADD_STRING(SMB2_CREATE_TAG_QFID);
3136 ADD_STRING(SMB2_CREATE_TAG_RQLS);
3137 ADD_STRING(SMB2_CREATE_TAG_DH2Q);
3138 ADD_STRING(SMB2_CREATE_TAG_DH2C);
3139 ADD_STRING(SMB2_CREATE_TAG_AAPL);
3140 ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
3141 ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
3142 ADD_STRING(SMB2_CREATE_TAG_POSIX);
3143 ADD_FLAGS(SMB2_FIND_POSIX_INFORMATION);
3144 ADD_FLAGS(FILE_SUPERSEDE);
3145 ADD_FLAGS(FILE_OPEN);
3146 ADD_FLAGS(FILE_CREATE);
3147 ADD_FLAGS(FILE_OPEN_IF);
3148 ADD_FLAGS(FILE_OVERWRITE);
3149 ADD_FLAGS(FILE_OVERWRITE_IF);
3150 ADD_FLAGS(FILE_DIRECTORY_FILE);
3152 ADD_FLAGS(SMB2_CLOSE_FLAGS_FULL_INFORMATION);
3154 return m;