ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source3 / libsmb / pylibsmb.c
blob7ce481e9f3f8e7b9101b07c0f446fd0ac710fa2d
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_get_posix_fs_info(
1074 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1076 NTSTATUS status;
1077 struct tevent_req *req = NULL;
1078 uint32_t optimal_transfer_size = 0;
1079 uint32_t block_size = 0;
1080 uint64_t total_blocks = 0;
1081 uint64_t blocks_available = 0;
1082 uint64_t user_blocks_available = 0;
1083 uint64_t total_file_nodes = 0;
1084 uint64_t free_file_nodes = 0;
1085 uint64_t fs_identifier = 0;
1087 req = cli_get_posix_fs_info_send(NULL, self->ev, self->cli);
1088 if (!py_tevent_req_wait_exc(self, req)) {
1089 return NULL;
1092 status = cli_get_posix_fs_info_recv(req,
1093 &optimal_transfer_size,
1094 &block_size,
1095 &total_blocks,
1096 &blocks_available,
1097 &user_blocks_available,
1098 &total_file_nodes,
1099 &free_file_nodes,
1100 &fs_identifier);
1101 TALLOC_FREE(req);
1102 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1104 return Py_BuildValue("{s:I,s:I,s:I,s:I,s:I,s:I,s:I,s:I}",
1105 "optimal_transfer_size", optimal_transfer_size,
1106 "block_size", block_size,
1107 "total_blocks", total_blocks,
1108 "blocks_available", blocks_available,
1109 "user_blocks_available", user_blocks_available,
1110 "total_file_nodes", total_file_nodes,
1111 "free_file_nodes", free_file_nodes,
1112 "fs_identifier", fs_identifier);
1115 static PyObject *py_cli_create_ex(
1116 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1118 char *fname = NULL;
1119 unsigned CreateFlags = 0;
1120 unsigned DesiredAccess = FILE_GENERIC_READ;
1121 unsigned FileAttributes = 0;
1122 unsigned ShareAccess = 0;
1123 unsigned CreateDisposition = FILE_OPEN;
1124 unsigned CreateOptions = 0;
1125 unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
1126 unsigned SecurityFlags = 0;
1127 PyObject *py_create_contexts_in = NULL;
1128 PyObject *py_create_contexts_out = NULL;
1129 struct smb2_create_blobs *create_contexts_in = NULL;
1130 struct smb2_create_blobs create_contexts_out = { .num_blobs = 0 };
1131 struct smb_create_returns cr = { .create_action = 0, };
1132 struct symlink_reparse_struct *symlink = NULL;
1133 PyObject *py_cr = NULL;
1134 uint16_t fnum;
1135 struct tevent_req *req;
1136 NTSTATUS status;
1137 int ret;
1138 bool ok;
1139 PyObject *v = NULL;
1141 static const char *kwlist[] = {
1142 "Name",
1143 "CreateFlags",
1144 "DesiredAccess",
1145 "FileAttributes",
1146 "ShareAccess",
1147 "CreateDisposition",
1148 "CreateOptions",
1149 "ImpersonationLevel",
1150 "SecurityFlags",
1151 "CreateContexts",
1152 NULL };
1154 ret = ParseTupleAndKeywords(
1155 args,
1156 kwds,
1157 "s|IIIIIIIIO",
1158 kwlist,
1159 &fname,
1160 &CreateFlags,
1161 &DesiredAccess,
1162 &FileAttributes,
1163 &ShareAccess,
1164 &CreateDisposition,
1165 &CreateOptions,
1166 &ImpersonationLevel,
1167 &SecurityFlags,
1168 &py_create_contexts_in);
1169 if (!ret) {
1170 return NULL;
1173 if (py_create_contexts_in != NULL) {
1174 create_contexts_in = py_cli_get_create_contexts(
1175 NULL, py_create_contexts_in);
1176 if (create_contexts_in == NULL) {
1177 errno = EINVAL;
1178 PyErr_SetFromErrno(PyExc_RuntimeError);
1179 return NULL;
1183 if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1184 struct cli_smb2_create_flags cflags = {
1185 .batch_oplock = (CreateFlags & REQUEST_BATCH_OPLOCK),
1186 .exclusive_oplock = (CreateFlags & REQUEST_OPLOCK),
1189 req = cli_smb2_create_fnum_send(
1190 NULL,
1191 self->ev,
1192 self->cli,
1193 fname,
1194 cflags,
1195 ImpersonationLevel,
1196 DesiredAccess,
1197 FileAttributes,
1198 ShareAccess,
1199 CreateDisposition,
1200 CreateOptions,
1201 create_contexts_in);
1202 } else {
1203 req = cli_ntcreate_send(
1204 NULL,
1205 self->ev,
1206 self->cli,
1207 fname,
1208 CreateFlags,
1209 DesiredAccess,
1210 FileAttributes,
1211 ShareAccess,
1212 CreateDisposition,
1213 CreateOptions,
1214 ImpersonationLevel,
1215 SecurityFlags);
1218 TALLOC_FREE(create_contexts_in);
1220 ok = py_tevent_req_wait_exc(self, req);
1221 if (!ok) {
1222 return NULL;
1225 if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1226 status = cli_smb2_create_fnum_recv(
1227 req,
1228 &fnum,
1229 &cr,
1230 NULL,
1231 &create_contexts_out,
1232 &symlink);
1233 } else {
1234 status = cli_ntcreate_recv(req, &fnum, &cr);
1237 TALLOC_FREE(req);
1239 if (!NT_STATUS_IS_OK(status)) {
1240 goto fail;
1243 SMB_ASSERT(symlink == NULL);
1245 py_create_contexts_out = py_cli_create_contexts(&create_contexts_out);
1246 TALLOC_FREE(create_contexts_out.blobs);
1247 if (py_create_contexts_out == NULL) {
1248 goto nomem;
1251 py_cr = py_cli_create_returns(&cr);
1252 if (py_cr == NULL) {
1253 goto nomem;
1256 v = Py_BuildValue("(IOO)",
1257 (unsigned)fnum,
1258 py_cr,
1259 py_create_contexts_out);
1260 return v;
1261 nomem:
1262 status = NT_STATUS_NO_MEMORY;
1263 fail:
1264 Py_XDECREF(py_create_contexts_out);
1265 Py_XDECREF(py_cr);
1266 Py_XDECREF(v);
1268 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
1269 (symlink != NULL)) {
1270 PyErr_SetObject(
1271 PyObject_GetAttrString(
1272 PyImport_ImportModule("samba"),
1273 "NTSTATUSError"),
1274 Py_BuildValue(
1275 "I,s,O",
1276 NT_STATUS_V(status),
1277 get_friendly_nt_error_msg(status),
1278 py_cli_symlink_error(symlink)));
1279 } else {
1280 PyErr_SetNTSTATUS(status);
1282 return NULL;
1285 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
1287 struct tevent_req *req;
1288 int fnum;
1289 int flags = 0;
1290 NTSTATUS status;
1292 if (!PyArg_ParseTuple(args, "i|i", &fnum, &flags)) {
1293 return NULL;
1296 req = cli_close_send(NULL, self->ev, self->cli, fnum, flags);
1297 if (!py_tevent_req_wait_exc(self, req)) {
1298 return NULL;
1300 status = cli_close_recv(req);
1301 TALLOC_FREE(req);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 PyErr_SetNTSTATUS(status);
1305 return NULL;
1307 Py_RETURN_NONE;
1310 static PyObject *py_wire_mode_to_unix(struct py_cli_state *self,
1311 PyObject *args)
1313 unsigned long long wire = 0;
1314 mode_t mode;
1315 bool ok;
1316 PyObject *v = NULL;
1318 ok = PyArg_ParseTuple(args, "K", &wire);
1319 if (!ok) {
1320 return NULL;
1322 mode = wire_mode_to_unix(wire);
1324 v = Py_BuildValue("I", (unsigned)mode);
1325 return v;
1328 static PyObject *py_unix_mode_to_wire(struct py_cli_state *self,
1329 PyObject *args)
1331 unsigned long long mode = 0;
1332 uint32_t wire;
1333 bool ok;
1334 PyObject *v = NULL;
1336 ok = PyArg_ParseTuple(args, "K", &mode);
1337 if (!ok) {
1338 return NULL;
1340 wire = unix_mode_to_wire(mode);
1342 v = Py_BuildValue("I", (unsigned)wire);
1343 return v;
1346 static PyObject *py_cli_qfileinfo(struct py_cli_state *self, PyObject *args)
1348 struct tevent_req *req = NULL;
1349 int fnum, level;
1350 uint16_t recv_flags2;
1351 uint8_t *rdata = NULL;
1352 uint32_t num_rdata;
1353 PyObject *result = NULL;
1354 NTSTATUS status;
1356 if (!PyArg_ParseTuple(args, "ii", &fnum, &level)) {
1357 return NULL;
1360 req = cli_qfileinfo_send(
1361 NULL, self->ev, self->cli, fnum, level, 0, UINT32_MAX);
1362 if (!py_tevent_req_wait_exc(self, req)) {
1363 return NULL;
1365 status = cli_qfileinfo_recv(
1366 req, NULL, &recv_flags2, &rdata, &num_rdata);
1367 TALLOC_FREE(req);
1369 if (!NT_STATUS_IS_OK(status)) {
1370 PyErr_SetNTSTATUS(status);
1371 return NULL;
1374 switch (level) {
1375 case FSCC_FILE_ATTRIBUTE_TAG_INFORMATION: {
1376 uint32_t mode = PULL_LE_U32(rdata, 0);
1377 uint32_t tag = PULL_LE_U32(rdata, 4);
1379 if (num_rdata != 8) {
1380 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1381 return NULL;
1384 result = Py_BuildValue("{s:K,s:K}",
1385 "mode",
1386 (unsigned long long)mode,
1387 "tag",
1388 (unsigned long long)tag);
1389 break;
1391 default:
1392 result = PyBytes_FromStringAndSize((char *)rdata, num_rdata);
1393 break;
1396 TALLOC_FREE(rdata);
1398 return result;
1401 static PyObject *py_cli_rename(
1402 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1404 char *fname_src = NULL, *fname_dst = NULL;
1405 int replace = false;
1406 struct tevent_req *req = NULL;
1407 NTSTATUS status;
1408 bool ok;
1410 static const char *kwlist[] = { "src", "dst", "replace", NULL };
1412 ok = ParseTupleAndKeywords(
1413 args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
1414 if (!ok) {
1415 return NULL;
1418 req = cli_rename_send(
1419 NULL, self->ev, self->cli, fname_src, fname_dst, replace);
1420 if (!py_tevent_req_wait_exc(self, req)) {
1421 return NULL;
1423 status = cli_rename_recv(req);
1424 TALLOC_FREE(req);
1426 if (!NT_STATUS_IS_OK(status)) {
1427 PyErr_SetNTSTATUS(status);
1428 return NULL;
1430 Py_RETURN_NONE;
1434 struct push_state {
1435 char *data;
1436 off_t nread;
1437 off_t total_data;
1441 * cli_push() helper to write a chunk of data to a remote file
1443 static size_t push_data(uint8_t *buf, size_t n, void *priv)
1445 struct push_state *state = (struct push_state *)priv;
1446 char *curr_ptr = NULL;
1447 off_t remaining;
1448 size_t copied_bytes;
1450 if (state->nread >= state->total_data) {
1451 return 0;
1454 curr_ptr = state->data + state->nread;
1455 remaining = state->total_data - state->nread;
1456 copied_bytes = MIN(remaining, n);
1458 memcpy(buf, curr_ptr, copied_bytes);
1459 state->nread += copied_bytes;
1460 return copied_bytes;
1464 * Writes a file with the contents specified
1466 static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
1468 uint16_t fnum;
1469 const char *filename = NULL;
1470 char *data = NULL;
1471 Py_ssize_t size = 0;
1472 NTSTATUS status;
1473 struct tevent_req *req = NULL;
1474 struct push_state state;
1476 if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
1477 &data, &size)) {
1478 return NULL;
1481 /* create a new file handle for writing to */
1482 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1483 FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
1484 FILE_SHARE_READ|FILE_SHARE_WRITE,
1485 FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
1486 SMB2_IMPERSONATION_IMPERSONATION, 0);
1487 if (!py_tevent_req_wait_exc(self, req)) {
1488 return NULL;
1490 status = cli_ntcreate_recv(req, &fnum, NULL);
1491 TALLOC_FREE(req);
1492 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1494 /* write the new file contents */
1495 state.data = data;
1496 state.nread = 0;
1497 state.total_data = size;
1499 req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
1500 push_data, &state);
1501 if (!py_tevent_req_wait_exc(self, req)) {
1502 return NULL;
1504 status = cli_push_recv(req);
1505 TALLOC_FREE(req);
1506 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1508 /* close the file handle */
1509 req = cli_close_send(NULL, self->ev, self->cli, fnum, 0);
1510 if (!py_tevent_req_wait_exc(self, req)) {
1511 return NULL;
1513 status = cli_close_recv(req);
1514 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1516 Py_RETURN_NONE;
1519 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
1520 PyObject *kwds)
1522 int fnum;
1523 unsigned mode = 0;
1524 char *buf;
1525 Py_ssize_t buflen;
1526 unsigned long long offset;
1527 struct tevent_req *req;
1528 NTSTATUS status;
1529 size_t written;
1531 static const char *kwlist[] = {
1532 "fnum", "buffer", "offset", "mode", NULL };
1534 if (!ParseTupleAndKeywords(
1535 args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
1536 &fnum, &buf, &buflen, &offset, &mode)) {
1537 return NULL;
1540 req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
1541 (uint8_t *)buf, offset, buflen);
1542 if (!py_tevent_req_wait_exc(self, req)) {
1543 return NULL;
1545 status = cli_write_recv(req, &written);
1546 TALLOC_FREE(req);
1548 if (!NT_STATUS_IS_OK(status)) {
1549 PyErr_SetNTSTATUS(status);
1550 return NULL;
1552 return Py_BuildValue("K", (unsigned long long)written);
1556 * Returns the size of the given file
1558 static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
1559 off_t *size)
1561 NTSTATUS status;
1562 struct tevent_req *req = NULL;
1564 req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
1565 if (!py_tevent_req_wait_exc(self, req)) {
1566 return NT_STATUS_INTERNAL_ERROR;
1568 status = cli_qfileinfo_basic_recv(
1569 req, NULL, size, NULL, NULL, NULL, NULL, NULL);
1570 TALLOC_FREE(req);
1571 return status;
1575 * Loads the specified file's contents and returns it
1577 static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
1579 NTSTATUS status;
1580 const char *filename = NULL;
1581 struct tevent_req *req = NULL;
1582 uint16_t fnum;
1583 off_t size;
1584 char *buf = NULL;
1585 off_t nread = 0;
1586 PyObject *result = NULL;
1588 if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
1589 return NULL;
1592 /* get a read file handle */
1593 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1594 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
1595 FILE_ATTRIBUTE_NORMAL,
1596 FILE_SHARE_READ, FILE_OPEN, 0,
1597 SMB2_IMPERSONATION_IMPERSONATION, 0);
1598 if (!py_tevent_req_wait_exc(self, req)) {
1599 return NULL;
1601 status = cli_ntcreate_recv(req, &fnum, NULL);
1602 TALLOC_FREE(req);
1603 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1605 /* get a buffer to hold the file contents */
1606 status = py_smb_filesize(self, fnum, &size);
1607 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1609 result = PyBytes_FromStringAndSize(NULL, size);
1610 if (result == NULL) {
1611 return NULL;
1614 /* read the file contents */
1615 buf = PyBytes_AS_STRING(result);
1616 req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
1617 size, cli_read_sink, &buf);
1618 if (!py_tevent_req_wait_exc(self, req)) {
1619 Py_XDECREF(result);
1620 return NULL;
1622 status = cli_pull_recv(req, &nread);
1623 TALLOC_FREE(req);
1624 if (!NT_STATUS_IS_OK(status)) {
1625 Py_XDECREF(result);
1626 PyErr_SetNTSTATUS(status);
1627 return NULL;
1630 /* close the file handle */
1631 req = cli_close_send(NULL, self->ev, self->cli, fnum, 0);
1632 if (!py_tevent_req_wait_exc(self, req)) {
1633 Py_XDECREF(result);
1634 return NULL;
1636 status = cli_close_recv(req);
1637 TALLOC_FREE(req);
1638 if (!NT_STATUS_IS_OK(status)) {
1639 Py_XDECREF(result);
1640 PyErr_SetNTSTATUS(status);
1641 return NULL;
1644 /* sanity-check we read the expected number of bytes */
1645 if (nread > size) {
1646 Py_XDECREF(result);
1647 PyErr_Format(PyExc_IOError,
1648 "read invalid - got %zu requested %zu",
1649 nread, size);
1650 return NULL;
1653 if (nread < size) {
1654 if (_PyBytes_Resize(&result, nread) < 0) {
1655 return NULL;
1659 return result;
1662 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
1663 PyObject *kwds)
1665 int fnum;
1666 unsigned long long offset;
1667 unsigned size;
1668 struct tevent_req *req;
1669 NTSTATUS status;
1670 char *buf;
1671 size_t received;
1672 PyObject *result;
1674 static const char *kwlist[] = {
1675 "fnum", "offset", "size", NULL };
1677 if (!ParseTupleAndKeywords(
1678 args, kwds, "iKI", kwlist, &fnum, &offset,
1679 &size)) {
1680 return NULL;
1683 result = PyBytes_FromStringAndSize(NULL, size);
1684 if (result == NULL) {
1685 return NULL;
1687 buf = PyBytes_AS_STRING(result);
1689 req = cli_read_send(NULL, self->ev, self->cli, fnum,
1690 buf, offset, size);
1691 if (!py_tevent_req_wait_exc(self, req)) {
1692 Py_XDECREF(result);
1693 return NULL;
1695 status = cli_read_recv(req, &received);
1696 TALLOC_FREE(req);
1698 if (!NT_STATUS_IS_OK(status)) {
1699 Py_XDECREF(result);
1700 PyErr_SetNTSTATUS(status);
1701 return NULL;
1704 if (received > size) {
1705 Py_XDECREF(result);
1706 PyErr_Format(PyExc_IOError,
1707 "read invalid - got %zu requested %u",
1708 received, size);
1709 return NULL;
1712 if (received < size) {
1713 if (_PyBytes_Resize(&result, received) < 0) {
1714 return NULL;
1718 return result;
1721 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
1722 PyObject *kwds)
1724 int fnum;
1725 unsigned long long size;
1726 struct tevent_req *req;
1727 NTSTATUS status;
1729 static const char *kwlist[] = {
1730 "fnum", "size", NULL };
1732 if (!ParseTupleAndKeywords(
1733 args, kwds, "IK", kwlist, &fnum, &size)) {
1734 return NULL;
1737 req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
1738 if (!py_tevent_req_wait_exc(self, req)) {
1739 return NULL;
1741 status = cli_ftruncate_recv(req);
1742 TALLOC_FREE(req);
1744 if (!NT_STATUS_IS_OK(status)) {
1745 PyErr_SetNTSTATUS(status);
1746 return NULL;
1748 Py_RETURN_NONE;
1751 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
1752 PyObject *args,
1753 PyObject *kwds)
1755 unsigned fnum, flag;
1756 struct tevent_req *req;
1757 NTSTATUS status;
1759 static const char *kwlist[] = {
1760 "fnum", "flag", NULL };
1762 if (!ParseTupleAndKeywords(
1763 args, kwds, "II", kwlist, &fnum, &flag)) {
1764 return NULL;
1767 req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
1768 flag);
1769 if (!py_tevent_req_wait_exc(self, req)) {
1770 return NULL;
1772 status = cli_nt_delete_on_close_recv(req);
1773 TALLOC_FREE(req);
1775 if (!NT_STATUS_IS_OK(status)) {
1776 PyErr_SetNTSTATUS(status);
1777 return NULL;
1779 Py_RETURN_NONE;
1782 struct py_cli_notify_state {
1783 PyObject_HEAD
1784 struct py_cli_state *py_cli_state;
1785 struct tevent_req *req;
1788 static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
1790 TALLOC_FREE(self->req);
1791 Py_CLEAR(self->py_cli_state);
1792 Py_TYPE(self)->tp_free(self);
1795 static PyTypeObject py_cli_notify_state_type;
1797 static PyObject *py_cli_notify(struct py_cli_state *self,
1798 PyObject *args,
1799 PyObject *kwds)
1801 static const char *kwlist[] = {
1802 "fnum",
1803 "buffer_size",
1804 "completion_filter",
1805 "recursive",
1806 NULL
1808 unsigned fnum = 0;
1809 unsigned buffer_size = 0;
1810 unsigned completion_filter = 0;
1811 PyObject *py_recursive = Py_False;
1812 bool recursive = false;
1813 struct tevent_req *req = NULL;
1814 struct tevent_queue *send_queue = NULL;
1815 struct tevent_req *flush_req = NULL;
1816 bool ok;
1817 struct py_cli_notify_state *py_notify_state = NULL;
1818 struct timeval endtime;
1820 ok = ParseTupleAndKeywords(args,
1821 kwds,
1822 "IIIO",
1823 kwlist,
1824 &fnum,
1825 &buffer_size,
1826 &completion_filter,
1827 &py_recursive);
1828 if (!ok) {
1829 return NULL;
1832 recursive = PyObject_IsTrue(py_recursive);
1834 req = cli_notify_send(NULL,
1835 self->ev,
1836 self->cli,
1837 fnum,
1838 buffer_size,
1839 completion_filter,
1840 recursive);
1841 if (req == NULL) {
1842 PyErr_NoMemory();
1843 return NULL;
1847 * Just wait for the request being submitted to
1848 * the kernel/socket/wire.
1850 send_queue = smbXcli_conn_send_queue(self->cli->conn);
1851 flush_req = tevent_queue_wait_send(req,
1852 self->ev,
1853 send_queue);
1854 endtime = timeval_current_ofs_msec(self->cli->timeout);
1855 ok = tevent_req_set_endtime(flush_req,
1856 self->ev,
1857 endtime);
1858 if (!ok) {
1859 TALLOC_FREE(req);
1860 PyErr_NoMemory();
1861 return NULL;
1863 ok = py_tevent_req_wait_exc(self, flush_req);
1864 if (!ok) {
1865 TALLOC_FREE(req);
1866 return NULL;
1868 TALLOC_FREE(flush_req);
1870 py_notify_state = (struct py_cli_notify_state *)
1871 py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
1872 if (py_notify_state == NULL) {
1873 TALLOC_FREE(req);
1874 PyErr_NoMemory();
1875 return NULL;
1877 Py_INCREF(self);
1878 py_notify_state->py_cli_state = self;
1879 py_notify_state->req = req;
1881 return (PyObject *)py_notify_state;
1884 static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
1885 PyObject *args,
1886 PyObject *kwds)
1888 struct py_cli_state *py_cli_state = self->py_cli_state;
1889 struct tevent_req *req = self->req;
1890 uint32_t i;
1891 uint32_t num_changes = 0;
1892 struct notify_change *changes = NULL;
1893 PyObject *result = NULL;
1894 NTSTATUS status;
1895 bool ok;
1896 static const char *kwlist[] = {
1897 "wait",
1898 NULL
1900 PyObject *py_wait = Py_False;
1901 bool wait = false;
1902 bool pending;
1904 ok = ParseTupleAndKeywords(args,
1905 kwds,
1906 "O",
1907 kwlist,
1908 &py_wait);
1909 if (!ok) {
1910 return NULL;
1913 wait = PyObject_IsTrue(py_wait);
1915 if (req == NULL) {
1916 PyErr_SetString(PyExc_RuntimeError,
1917 "TODO req == NULL "
1918 "- missing change notify request?");
1919 return NULL;
1922 pending = tevent_req_is_in_progress(req);
1923 if (pending && !wait) {
1924 Py_RETURN_NONE;
1927 if (pending) {
1928 struct timeval endtime;
1930 endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
1931 ok = tevent_req_set_endtime(req,
1932 py_cli_state->ev,
1933 endtime);
1934 if (!ok) {
1935 TALLOC_FREE(req);
1936 PyErr_NoMemory();
1937 return NULL;
1941 ok = py_tevent_req_wait_exc(py_cli_state, req);
1942 self->req = NULL;
1943 Py_CLEAR(self->py_cli_state);
1944 if (!ok) {
1945 return NULL;
1948 status = cli_notify_recv(req, req, &num_changes, &changes);
1949 if (!NT_STATUS_IS_OK(status)) {
1950 TALLOC_FREE(req);
1951 PyErr_SetNTSTATUS(status);
1952 return NULL;
1955 result = Py_BuildValue("[]");
1956 if (result == NULL) {
1957 TALLOC_FREE(req);
1958 return NULL;
1961 for (i = 0; i < num_changes; i++) {
1962 PyObject *change = NULL;
1963 int ret;
1965 change = Py_BuildValue("{s:s,s:I}",
1966 "name", changes[i].name,
1967 "action", changes[i].action);
1968 if (change == NULL) {
1969 Py_XDECREF(result);
1970 TALLOC_FREE(req);
1971 return NULL;
1974 ret = PyList_Append(result, change);
1975 Py_DECREF(change);
1976 if (ret == -1) {
1977 Py_XDECREF(result);
1978 TALLOC_FREE(req);
1979 return NULL;
1983 TALLOC_FREE(req);
1984 return result;
1987 static PyMethodDef py_cli_notify_state_methods[] = {
1989 .ml_name = "get_changes",
1990 .ml_meth = (PyCFunction)py_cli_notify_get_changes,
1991 .ml_flags = METH_VARARGS|METH_KEYWORDS,
1992 .ml_doc = "Wait for change notifications: \n"
1993 "N.get_changes(wait=BOOLEAN) -> "
1994 "change notifications as a dictionary\n"
1995 "\t\tList contents of a directory. The keys are, \n"
1996 "\t\t\tname: name of changed object\n"
1997 "\t\t\taction: type of the change\n"
1998 "None is returned if there's no response yet and "
1999 "wait=False is passed"
2002 .ml_name = NULL
2006 static PyTypeObject py_cli_notify_state_type = {
2007 PyVarObject_HEAD_INIT(NULL, 0)
2008 .tp_name = "libsmb_samba_cwrapper.Notify",
2009 .tp_basicsize = sizeof(struct py_cli_notify_state),
2010 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2011 .tp_doc = "notify request",
2012 .tp_dealloc = (destructor)py_cli_notify_state_dealloc,
2013 .tp_methods = py_cli_notify_state_methods,
2017 * Helper to add posix directory listing entries to an overall Python list
2019 static NTSTATUS list_posix_helper(struct file_info *finfo,
2020 const char *mask, void *state)
2022 PyObject *result = (PyObject *)state;
2023 PyObject *file = NULL;
2024 struct dom_sid_buf owner_buf, group_buf;
2025 int ret;
2028 * Build a dictionary representing the file info.
2030 file = Py_BuildValue("{s:s,s:I,"
2031 "s:K,s:K,"
2032 "s:l,s:l,s:l,s:l,"
2033 "s:i,s:K,s:i,s:i,s:I,"
2034 "s:s,s:s,s:k}",
2035 "name",
2036 finfo->name,
2037 "attrib",
2038 finfo->attr,
2039 "size",
2040 finfo->size,
2041 "allocation_size",
2042 finfo->allocated_size,
2043 "btime",
2044 convert_timespec_to_time_t(finfo->btime_ts),
2045 "atime",
2046 convert_timespec_to_time_t(finfo->atime_ts),
2047 "mtime",
2048 convert_timespec_to_time_t(finfo->mtime_ts),
2049 "ctime",
2050 convert_timespec_to_time_t(finfo->ctime_ts),
2051 "perms",
2052 finfo->st_ex_mode,
2053 "ino",
2054 finfo->ino,
2055 "dev",
2056 finfo->st_ex_dev,
2057 "nlink",
2058 finfo->st_ex_nlink,
2059 "reparse_tag",
2060 finfo->reparse_tag,
2061 "owner_sid",
2062 dom_sid_str_buf(&finfo->owner_sid, &owner_buf),
2063 "group_sid",
2064 dom_sid_str_buf(&finfo->group_sid, &group_buf),
2065 "reparse_tag",
2066 (unsigned long)finfo->reparse_tag);
2067 if (file == NULL) {
2068 return NT_STATUS_NO_MEMORY;
2071 ret = PyList_Append(result, file);
2072 Py_CLEAR(file);
2073 if (ret == -1) {
2074 return NT_STATUS_INTERNAL_ERROR;
2077 return NT_STATUS_OK;
2081 * Helper to add directory listing entries to an overall Python list
2083 static NTSTATUS list_helper(struct file_info *finfo,
2084 const char *mask, void *state)
2086 PyObject *result = (PyObject *)state;
2087 PyObject *file = NULL;
2088 PyObject *size = NULL;
2089 int ret;
2091 /* suppress '.' and '..' in the results we return */
2092 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2093 return NT_STATUS_OK;
2095 size = PyLong_FromUnsignedLongLong(finfo->size);
2097 * Build a dictionary representing the file info.
2098 * Note: Windows does not always return short_name (so it may be None)
2100 file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l,s:k}",
2101 "name",
2102 finfo->name,
2103 "attrib",
2104 (int)finfo->attr,
2105 "short_name",
2106 finfo->short_name,
2107 "size",
2108 size,
2109 "mtime",
2110 convert_timespec_to_time_t(finfo->mtime_ts),
2111 "reparse_tag",
2112 (unsigned long)finfo->reparse_tag);
2114 Py_CLEAR(size);
2116 if (file == NULL) {
2117 return NT_STATUS_NO_MEMORY;
2120 if (finfo->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
2121 unsigned long tag = finfo->reparse_tag;
2123 ret = PyDict_SetItemString(
2124 file,
2125 "reparse_tag",
2126 PyLong_FromUnsignedLong(tag));
2127 if (ret == -1) {
2128 return NT_STATUS_INTERNAL_ERROR;
2132 ret = PyList_Append(result, file);
2133 Py_CLEAR(file);
2134 if (ret == -1) {
2135 return NT_STATUS_INTERNAL_ERROR;
2138 return NT_STATUS_OK;
2141 struct do_listing_state {
2142 const char *mask;
2143 NTSTATUS (*callback_fn)(
2144 struct file_info *finfo,
2145 const char *mask,
2146 void *private_data);
2147 void *private_data;
2148 NTSTATUS status;
2151 static void do_listing_cb(struct tevent_req *subreq)
2153 struct do_listing_state *state = tevent_req_callback_data_void(subreq);
2154 struct file_info *finfo = NULL;
2156 state->status = cli_list_recv(subreq, NULL, &finfo);
2157 if (!NT_STATUS_IS_OK(state->status)) {
2158 return;
2160 state->callback_fn(finfo, state->mask, state->private_data);
2161 TALLOC_FREE(finfo);
2164 static NTSTATUS do_listing(struct py_cli_state *self,
2165 const char *base_dir, const char *user_mask,
2166 uint16_t attribute,
2167 unsigned int info_level,
2168 NTSTATUS (*callback_fn)(struct file_info *,
2169 const char *, void *),
2170 void *priv)
2172 char *mask = NULL;
2173 struct do_listing_state state = {
2174 .mask = mask,
2175 .callback_fn = callback_fn,
2176 .private_data = priv,
2178 struct tevent_req *req = NULL;
2179 NTSTATUS status;
2181 if (user_mask == NULL) {
2182 mask = talloc_asprintf(NULL, "%s\\*", base_dir);
2183 } else {
2184 mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
2187 if (mask == NULL) {
2188 return NT_STATUS_NO_MEMORY;
2190 dos_format(mask);
2192 req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
2193 info_level);
2194 if (req == NULL) {
2195 status = NT_STATUS_NO_MEMORY;
2196 goto done;
2198 tevent_req_set_callback(req, do_listing_cb, &state);
2200 if (!py_tevent_req_wait_exc(self, req)) {
2201 return NT_STATUS_INTERNAL_ERROR;
2203 TALLOC_FREE(req);
2205 status = state.status;
2206 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
2207 status = NT_STATUS_OK;
2210 done:
2211 TALLOC_FREE(mask);
2212 return status;
2215 static PyObject *py_cli_list(struct py_cli_state *self,
2216 PyObject *args,
2217 PyObject *kwds)
2219 char *base_dir;
2220 char *user_mask = NULL;
2221 unsigned int attribute = LIST_ATTRIBUTE_MASK;
2222 unsigned int info_level = 0;
2223 NTSTATUS status;
2224 enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2225 PyObject *result = NULL;
2226 const char *kwlist[] = { "directory", "mask", "attribs",
2227 "info_level", NULL };
2228 NTSTATUS (*callback_fn)(struct file_info *, const char *, void *) =
2229 list_helper;
2231 if (!ParseTupleAndKeywords(args, kwds, "z|sII:list", kwlist,
2232 &base_dir, &user_mask, &attribute,
2233 &info_level)) {
2234 return NULL;
2237 result = Py_BuildValue("[]");
2238 if (result == NULL) {
2239 return NULL;
2242 if (!info_level) {
2243 if (proto >= PROTOCOL_SMB2_02) {
2244 info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
2245 } else {
2246 info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
2250 if (info_level == SMB2_FIND_POSIX_INFORMATION) {
2251 callback_fn = list_posix_helper;
2253 status = do_listing(self, base_dir, user_mask, attribute,
2254 info_level, callback_fn, result);
2256 if (!NT_STATUS_IS_OK(status)) {
2257 Py_XDECREF(result);
2258 PyErr_SetNTSTATUS(status);
2259 return NULL;
2262 return result;
2265 static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
2267 NTSTATUS status;
2268 const char *filename = NULL;
2269 struct tevent_req *req = NULL;
2270 const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2272 if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
2273 return NULL;
2276 req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
2277 if (!py_tevent_req_wait_exc(self, req)) {
2278 return NULL;
2280 status = cli_unlink_recv(req);
2281 TALLOC_FREE(req);
2282 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2284 Py_RETURN_NONE;
2287 static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
2289 NTSTATUS status;
2290 struct tevent_req *req = NULL;
2291 const char *dirname = NULL;
2293 if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
2294 return NULL;
2297 req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
2298 if (!py_tevent_req_wait_exc(self, req)) {
2299 return NULL;
2301 status = cli_rmdir_recv(req);
2302 TALLOC_FREE(req);
2303 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2305 Py_RETURN_NONE;
2309 * Create a directory
2311 static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
2313 NTSTATUS status;
2314 const char *dirname = NULL;
2315 struct tevent_req *req = NULL;
2317 if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
2318 return NULL;
2321 req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
2322 if (!py_tevent_req_wait_exc(self, req)) {
2323 return NULL;
2325 status = cli_mkdir_recv(req);
2326 TALLOC_FREE(req);
2327 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2329 Py_RETURN_NONE;
2333 * Does a whoami call
2335 static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
2336 PyObject *Py_UNUSED(ignored))
2338 TALLOC_CTX *frame = talloc_stackframe();
2339 NTSTATUS status;
2340 struct tevent_req *req = NULL;
2341 uint64_t uid;
2342 uint64_t gid;
2343 uint32_t num_gids;
2344 uint64_t *gids = NULL;
2345 uint32_t num_sids;
2346 struct dom_sid *sids = NULL;
2347 bool guest;
2348 PyObject *py_gids = NULL;
2349 PyObject *py_sids = NULL;
2350 PyObject *py_guest = NULL;
2351 PyObject *py_ret = NULL;
2352 Py_ssize_t i;
2354 req = cli_posix_whoami_send(frame, self->ev, self->cli);
2355 if (!py_tevent_req_wait_exc(self, req)) {
2356 goto fail;
2358 status = cli_posix_whoami_recv(req,
2359 frame,
2360 &uid,
2361 &gid,
2362 &num_gids,
2363 &gids,
2364 &num_sids,
2365 &sids,
2366 &guest);
2367 if (!NT_STATUS_IS_OK(status)) {
2368 PyErr_SetNTSTATUS(status);
2369 goto fail;
2371 if (num_gids > PY_SSIZE_T_MAX) {
2372 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
2373 goto fail;
2375 if (num_sids > PY_SSIZE_T_MAX) {
2376 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
2377 goto fail;
2380 py_gids = PyList_New(num_gids);
2381 if (!py_gids) {
2382 goto fail;
2384 for (i = 0; i < num_gids; ++i) {
2385 int ret;
2386 PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
2387 if (!py_item) {
2388 goto fail2;
2391 ret = PyList_SetItem(py_gids, i, py_item);
2392 if (ret) {
2393 goto fail2;
2396 py_sids = PyList_New(num_sids);
2397 if (!py_sids) {
2398 goto fail2;
2400 for (i = 0; i < num_sids; ++i) {
2401 int ret;
2402 struct dom_sid *sid;
2403 PyObject *py_item;
2405 sid = dom_sid_dup(frame, &sids[i]);
2406 if (!sid) {
2407 PyErr_NoMemory();
2408 goto fail3;
2411 py_item = pytalloc_steal(dom_sid_Type, sid);
2412 if (!py_item) {
2413 PyErr_NoMemory();
2414 goto fail3;
2417 ret = PyList_SetItem(py_sids, i, py_item);
2418 if (ret) {
2419 goto fail3;
2423 py_guest = guest ? Py_True : Py_False;
2425 py_ret = Py_BuildValue("KKNNO",
2426 uid,
2427 gid,
2428 py_gids,
2429 py_sids,
2430 py_guest);
2431 if (!py_ret) {
2432 goto fail3;
2435 TALLOC_FREE(frame);
2436 return py_ret;
2438 fail3:
2439 Py_CLEAR(py_sids);
2441 fail2:
2442 Py_CLEAR(py_gids);
2444 fail:
2445 TALLOC_FREE(frame);
2446 return NULL;
2450 * Checks existence of a directory
2452 static bool check_dir_path(struct py_cli_state *self, const char *path)
2454 NTSTATUS status;
2455 struct tevent_req *req = NULL;
2457 req = cli_chkpath_send(NULL, self->ev, self->cli, path);
2458 if (!py_tevent_req_wait_exc(self, req)) {
2459 return false;
2461 status = cli_chkpath_recv(req);
2462 TALLOC_FREE(req);
2464 return NT_STATUS_IS_OK(status);
2467 static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
2469 const char *path = NULL;
2470 bool dir_exists;
2472 if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
2473 return NULL;
2476 dir_exists = check_dir_path(self, path);
2477 return PyBool_FromLong(dir_exists);
2480 static PyObject *py_smb_have_posix(struct py_cli_state *self,
2481 PyObject *Py_UNUSED(ignored))
2483 bool posix = smbXcli_conn_have_posix(self->cli->conn);
2485 if (posix) {
2486 Py_RETURN_TRUE;
2488 Py_RETURN_FALSE;
2491 static PyObject *py_smb_protocol(struct py_cli_state *self,
2492 PyObject *Py_UNUSED(ignored))
2494 enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2495 PyObject *result = PyLong_FromLong(proto);
2496 return result;
2499 static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
2501 int fnum;
2502 unsigned sinfo;
2503 struct tevent_req *req = NULL;
2504 struct security_descriptor *sd = NULL;
2505 NTSTATUS status;
2507 if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
2508 return NULL;
2511 req = cli_query_security_descriptor_send(
2512 NULL, self->ev, self->cli, fnum, sinfo);
2513 if (!py_tevent_req_wait_exc(self, req)) {
2514 return NULL;
2516 status = cli_query_security_descriptor_recv(req, NULL, &sd);
2517 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2519 return py_return_ndr_struct(
2520 "samba.dcerpc.security", "descriptor", sd, sd);
2523 static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
2525 PyObject *py_sd = NULL;
2526 struct tevent_req *req = NULL;
2527 struct security_descriptor *sd = NULL;
2528 uint16_t fnum;
2529 unsigned int sinfo;
2530 NTSTATUS status;
2532 if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
2533 return NULL;
2536 sd = pytalloc_get_type(py_sd, struct security_descriptor);
2537 if (!sd) {
2538 PyErr_Format(PyExc_TypeError,
2539 "Expected dcerpc.security.descriptor as argument, got %s",
2540 pytalloc_get_name(py_sd));
2541 return NULL;
2544 req = cli_set_security_descriptor_send(
2545 NULL, self->ev, self->cli, fnum, sinfo, sd);
2546 if (!py_tevent_req_wait_exc(self, req)) {
2547 return NULL;
2550 status = cli_set_security_descriptor_recv(req);
2551 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2553 Py_RETURN_NONE;
2556 static PyObject *py_smb_smb1_posix(
2557 struct py_cli_state *self, PyObject *Py_UNUSED(ignored))
2559 NTSTATUS status;
2560 struct tevent_req *req = NULL;
2561 uint16_t major, minor;
2562 uint32_t caplow, caphigh;
2563 PyObject *result = NULL;
2565 req = cli_unix_extensions_version_send(NULL, self->ev, self->cli);
2566 if (!py_tevent_req_wait_exc(self, req)) {
2567 return NULL;
2569 status = cli_unix_extensions_version_recv(
2570 req, &major, &minor, &caplow, &caphigh);
2571 TALLOC_FREE(req);
2572 if (!NT_STATUS_IS_OK(status)) {
2573 PyErr_SetNTSTATUS(status);
2574 return NULL;
2577 req = cli_set_unix_extensions_capabilities_send(
2578 NULL, self->ev, self->cli, major, minor, caplow, caphigh);
2579 if (!py_tevent_req_wait_exc(self, req)) {
2580 return NULL;
2582 status = cli_set_unix_extensions_capabilities_recv(req);
2583 TALLOC_FREE(req);
2584 if (!NT_STATUS_IS_OK(status)) {
2585 PyErr_SetNTSTATUS(status);
2586 return NULL;
2589 result = Py_BuildValue(
2590 "[IIII]",
2591 (unsigned)minor,
2592 (unsigned)major,
2593 (unsigned)caplow,
2594 (unsigned)caphigh);
2595 return result;
2598 static PyObject *py_smb_smb1_readlink(
2599 struct py_cli_state *self, PyObject *args)
2601 NTSTATUS status;
2602 const char *filename = NULL;
2603 struct tevent_req *req = NULL;
2604 char *target = NULL;
2605 PyObject *result = NULL;
2607 if (!PyArg_ParseTuple(args, "s:smb1_readlink", &filename)) {
2608 return NULL;
2611 req = cli_posix_readlink_send(NULL, self->ev, self->cli, filename);
2612 if (!py_tevent_req_wait_exc(self, req)) {
2613 return NULL;
2615 status = cli_posix_readlink_recv(req, NULL, &target);
2616 TALLOC_FREE(req);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 PyErr_SetNTSTATUS(status);
2619 return NULL;
2622 result = PyBytes_FromString(target);
2623 TALLOC_FREE(target);
2624 return result;
2627 static PyObject *py_smb_smb1_symlink(
2628 struct py_cli_state *self, PyObject *args)
2630 NTSTATUS status;
2631 const char *target = NULL, *newname = NULL;
2632 struct tevent_req *req = NULL;
2634 if (!PyArg_ParseTuple(args, "ss:smb1_symlink", &target, &newname)) {
2635 return NULL;
2638 req = cli_posix_symlink_send(
2639 NULL, self->ev, self->cli, target, newname);
2640 if (!py_tevent_req_wait_exc(self, req)) {
2641 return NULL;
2643 status = cli_posix_symlink_recv(req);
2644 TALLOC_FREE(req);
2645 if (!NT_STATUS_IS_OK(status)) {
2646 PyErr_SetNTSTATUS(status);
2647 return NULL;
2650 Py_RETURN_NONE;
2653 static PyObject *py_smb_smb1_stat(
2654 struct py_cli_state *self, PyObject *args)
2656 NTSTATUS status;
2657 const char *fname = NULL;
2658 struct tevent_req *req = NULL;
2659 struct stat_ex sbuf = { .st_ex_nlink = 0, };
2661 if (!PyArg_ParseTuple(args, "s:smb1_stat", &fname)) {
2662 return NULL;
2665 req = cli_posix_stat_send(NULL, self->ev, self->cli, fname);
2666 if (!py_tevent_req_wait_exc(self, req)) {
2667 return NULL;
2669 status = cli_posix_stat_recv(req, &sbuf);
2670 TALLOC_FREE(req);
2671 if (!NT_STATUS_IS_OK(status)) {
2672 PyErr_SetNTSTATUS(status);
2673 return NULL;
2676 return Py_BuildValue(
2677 "{sLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsL}",
2678 "dev",
2679 (unsigned long long)sbuf.st_ex_dev,
2680 "ino",
2681 (unsigned long long)sbuf.st_ex_ino,
2682 "mode",
2683 (unsigned long long)sbuf.st_ex_mode,
2684 "nlink",
2685 (unsigned long long)sbuf.st_ex_nlink,
2686 "uid",
2687 (unsigned long long)sbuf.st_ex_uid,
2688 "gid",
2689 (unsigned long long)sbuf.st_ex_gid,
2690 "rdev",
2691 (unsigned long long)sbuf.st_ex_size,
2692 "atime_sec",
2693 (unsigned long long)sbuf.st_ex_atime.tv_sec,
2694 "atime_nsec",
2695 (unsigned long long)sbuf.st_ex_atime.tv_nsec,
2696 "mtime_sec",
2697 (unsigned long long)sbuf.st_ex_mtime.tv_sec,
2698 "mtime_nsec",
2699 (unsigned long long)sbuf.st_ex_mtime.tv_nsec,
2700 "ctime_sec",
2701 (unsigned long long)sbuf.st_ex_ctime.tv_sec,
2702 "ctime_nsec",
2703 (unsigned long long)sbuf.st_ex_ctime.tv_nsec,
2704 "btime_sec",
2705 (unsigned long long)sbuf.st_ex_btime.tv_sec,
2706 "btime_nsec",
2707 (unsigned long long)sbuf.st_ex_btime.tv_nsec,
2708 "cached_dos_attributes",
2709 (unsigned long long)sbuf.cached_dos_attributes,
2710 "blksize",
2711 (unsigned long long)sbuf.st_ex_blksize,
2712 "blocks",
2713 (unsigned long long)sbuf.st_ex_blocks,
2714 "flags",
2715 (unsigned long long)sbuf.st_ex_flags,
2716 "iflags",
2717 (unsigned long long)sbuf.st_ex_iflags);
2720 static PyObject *py_cli_mknod(
2721 struct py_cli_state *self, PyObject *args, PyObject *kwds)
2723 char *fname = NULL;
2724 int mode = 0, major = 0, minor = 0, dev = 0;
2725 struct tevent_req *req = NULL;
2726 static const char *kwlist[] = {
2727 "fname", "mode", "major", "minor", NULL,
2729 NTSTATUS status;
2730 bool ok;
2732 ok = ParseTupleAndKeywords(
2733 args,
2734 kwds,
2735 "sI|II:mknod",
2736 kwlist,
2737 &fname,
2738 &mode,
2739 &major,
2740 &minor);
2741 if (!ok) {
2742 return NULL;
2745 #if defined(HAVE_MAKEDEV)
2746 dev = makedev(major, minor);
2747 #endif
2749 req = cli_mknod_send(
2750 NULL, self->ev, self->cli, fname, mode, dev);
2751 if (!py_tevent_req_wait_exc(self, req)) {
2752 return NULL;
2754 status = cli_mknod_recv(req);
2755 TALLOC_FREE(req);
2756 if (!NT_STATUS_IS_OK(status)) {
2757 PyErr_SetNTSTATUS(status);
2758 return NULL;
2760 Py_RETURN_NONE;
2763 static PyObject *py_cli_fsctl(
2764 struct py_cli_state *self, PyObject *args, PyObject *kwds)
2766 int fnum, ctl_code;
2767 int max_out = 0;
2768 char *buf = NULL;
2769 Py_ssize_t buflen;
2770 DATA_BLOB in = { .data = NULL, };
2771 DATA_BLOB out = { .data = NULL, };
2772 struct tevent_req *req = NULL;
2773 PyObject *result = NULL;
2774 static const char *kwlist[] = {
2775 "fnum", "ctl_code", "in", "max_out", NULL,
2777 NTSTATUS status;
2778 bool ok;
2780 ok = ParseTupleAndKeywords(
2781 args,
2782 kwds,
2783 "ii" PYARG_BYTES_LEN "i",
2784 kwlist,
2785 &fnum,
2786 &ctl_code,
2787 &buf,
2788 &buflen,
2789 &max_out);
2790 if (!ok) {
2791 return NULL;
2794 in = (DATA_BLOB) { .data = (uint8_t *)buf, .length = buflen, };
2796 req = cli_fsctl_send(
2797 NULL, self->ev, self->cli, fnum, ctl_code, &in, max_out);
2799 if (!py_tevent_req_wait_exc(self, req)) {
2800 return NULL;
2803 status = cli_fsctl_recv(req, NULL, &out);
2804 if (!NT_STATUS_IS_OK(status)) {
2805 PyErr_SetNTSTATUS(status);
2806 return NULL;
2809 result = PyBytes_FromStringAndSize((char *)out.data, out.length);
2810 data_blob_free(&out);
2811 return result;
2814 static PyMethodDef py_cli_state_methods[] = {
2815 { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
2816 "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
2817 { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
2818 "Ping the server connection" },
2819 { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
2820 METH_VARARGS|METH_KEYWORDS,
2821 "Open a file" },
2822 { "get_posix_fs_info",
2823 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_get_posix_fs_info),
2824 METH_NOARGS,
2825 "Get posix filesystem attribute information" },
2826 { "create_ex",
2827 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create_ex),
2828 METH_VARARGS|METH_KEYWORDS,
2829 "Open a file, SMB2 version returning create contexts" },
2830 { "close", (PyCFunction)py_cli_close, METH_VARARGS,
2831 "Close a file handle" },
2832 { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
2833 METH_VARARGS|METH_KEYWORDS,
2834 "Write to a file handle" },
2835 { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
2836 METH_VARARGS|METH_KEYWORDS,
2837 "Read from a file handle" },
2838 { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
2839 py_cli_ftruncate),
2840 METH_VARARGS|METH_KEYWORDS,
2841 "Truncate a file" },
2842 { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
2843 py_cli_delete_on_close),
2844 METH_VARARGS|METH_KEYWORDS,
2845 "Set/Reset the delete on close flag" },
2846 { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
2847 METH_VARARGS|METH_KEYWORDS,
2848 "Wait for change notifications: \n"
2849 "notify(fnum, buffer_size, completion_filter...) -> "
2850 "libsmb_samba_internal.Notify request handle\n" },
2851 { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
2852 METH_VARARGS|METH_KEYWORDS,
2853 "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
2854 "directory contents as a dictionary\n"
2855 "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
2856 "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
2857 "\t\tList contents of a directory. The keys are, \n"
2858 "\t\t\tname: Long name of the directory item\n"
2859 "\t\t\tshort_name: Short name of the directory item\n"
2860 "\t\t\tsize: File size in bytes\n"
2861 "\t\t\tattrib: Attributes\n"
2862 "\t\t\tmtime: Modification time\n" },
2863 { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
2864 METH_VARARGS, "Wait for an oplock break" },
2865 { "unlink", (PyCFunction)py_smb_unlink,
2866 METH_VARARGS,
2867 "unlink(path) -> None\n\n \t\tDelete a file." },
2868 { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
2869 "mkdir(path) -> None\n\n \t\tCreate a directory." },
2870 { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
2871 "posix_whoami() -> (uid, gid, gids, sids, guest)" },
2872 { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
2873 "rmdir(path) -> None\n\n \t\tDelete a directory." },
2874 { "rename",
2875 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
2876 METH_VARARGS|METH_KEYWORDS,
2877 "rename(src,dst) -> None\n\n \t\tRename a file." },
2878 { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
2879 "chkpath(dir_path) -> True or False\n\n"
2880 "\t\tReturn true if directory exists, false otherwise." },
2881 { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
2882 "savefile(path, bytes) -> None\n\n"
2883 "\t\tWrite bytes to file." },
2884 { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
2885 "loadfile(path) -> file contents as a bytes object"
2886 "\n\n\t\tRead contents of a file." },
2887 { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
2888 "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
2889 "\t\tGet security descriptor for opened file." },
2890 { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
2891 "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
2892 "\t\tSet security descriptor for opened file." },
2893 { "protocol",
2894 (PyCFunction)py_smb_protocol,
2895 METH_NOARGS,
2896 "protocol() -> Number"
2898 { "have_posix",
2899 (PyCFunction)py_smb_have_posix,
2900 METH_NOARGS,
2901 "have_posix() -> True/False\n\n"
2902 "\t\tReturn if the server has posix extensions"
2904 { "smb1_posix",
2905 (PyCFunction)py_smb_smb1_posix,
2906 METH_NOARGS,
2907 "Negotiate SMB1 posix extensions",
2909 { "smb1_readlink",
2910 (PyCFunction)py_smb_smb1_readlink,
2911 METH_VARARGS,
2912 "smb1_readlink(path) -> link target",
2914 { "smb1_symlink",
2915 (PyCFunction)py_smb_smb1_symlink,
2916 METH_VARARGS,
2917 "smb1_symlink(target, newname) -> None",
2919 { "smb1_stat",
2920 (PyCFunction)py_smb_smb1_stat,
2921 METH_VARARGS,
2922 "smb1_stat(path) -> stat info",
2924 { "fsctl",
2925 (PyCFunction)py_cli_fsctl,
2926 METH_VARARGS|METH_KEYWORDS,
2927 "fsctl(fnum, ctl_code, in_bytes, max_out) -> out_bytes",
2930 "qfileinfo",
2931 (PyCFunction)py_cli_qfileinfo,
2932 METH_VARARGS | METH_KEYWORDS,
2933 "qfileinfo(fnum, level) -> blob",
2935 { "mknod",
2936 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_mknod),
2937 METH_VARARGS|METH_KEYWORDS,
2938 "mknod(path, mode | major, minor)",
2940 { NULL, NULL, 0, NULL }
2943 static PyTypeObject py_cli_state_type = {
2944 PyVarObject_HEAD_INIT(NULL, 0)
2945 .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
2946 .tp_basicsize = sizeof(struct py_cli_state),
2947 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2948 .tp_doc = "libsmb cwrapper connection",
2949 .tp_new = py_cli_state_new,
2950 .tp_init = (initproc)py_cli_state_init,
2951 .tp_dealloc = (destructor)py_cli_state_dealloc,
2952 .tp_methods = py_cli_state_methods,
2955 static PyMethodDef py_libsmb_methods[] = {
2957 "unix_mode_to_wire",
2958 (PyCFunction)py_unix_mode_to_wire,
2959 METH_VARARGS,
2960 "Convert mode_t to posix extensions wire format",
2963 "wire_mode_to_unix",
2964 (PyCFunction)py_wire_mode_to_unix,
2965 METH_VARARGS,
2966 "Convert posix wire format mode to mode_t",
2968 {0},
2971 void initlibsmb_samba_cwrapper(void);
2973 static struct PyModuleDef moduledef = {
2974 PyModuleDef_HEAD_INIT,
2975 .m_name = "libsmb_samba_cwrapper",
2976 .m_doc = "libsmb wrapper",
2977 .m_size = -1,
2978 .m_methods = py_libsmb_methods,
2981 MODULE_INIT_FUNC(libsmb_samba_cwrapper)
2983 PyObject *m = NULL;
2984 PyObject *mod = NULL;
2986 talloc_stackframe();
2988 if (PyType_Ready(&py_cli_state_type) < 0) {
2989 return NULL;
2991 if (PyType_Ready(&py_cli_notify_state_type) < 0) {
2992 return NULL;
2995 m = PyModule_Create(&moduledef);
2996 if (m == NULL) {
2997 return m;
3000 /* Import dom_sid type from dcerpc.security */
3001 mod = PyImport_ImportModule("samba.dcerpc.security");
3002 if (mod == NULL) {
3003 return NULL;
3006 dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
3007 if (dom_sid_Type == NULL) {
3008 Py_DECREF(mod);
3009 return NULL;
3012 Py_INCREF(&py_cli_state_type);
3013 PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
3015 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
3017 ADD_FLAGS(PROTOCOL_NONE);
3018 ADD_FLAGS(PROTOCOL_CORE);
3019 ADD_FLAGS(PROTOCOL_COREPLUS);
3020 ADD_FLAGS(PROTOCOL_LANMAN1);
3021 ADD_FLAGS(PROTOCOL_LANMAN2);
3022 ADD_FLAGS(PROTOCOL_NT1);
3023 ADD_FLAGS(PROTOCOL_SMB2_02);
3024 ADD_FLAGS(PROTOCOL_SMB2_10);
3025 ADD_FLAGS(PROTOCOL_SMB3_00);
3026 ADD_FLAGS(PROTOCOL_SMB3_02);
3027 ADD_FLAGS(PROTOCOL_SMB3_11);
3029 ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
3030 ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
3031 ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
3032 ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
3033 ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
3034 ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
3035 ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
3036 ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
3037 ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
3038 ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
3039 ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
3040 ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
3041 ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
3042 ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
3043 ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
3044 ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
3046 ADD_FLAGS(FILE_DIRECTORY_FILE);
3047 ADD_FLAGS(FILE_WRITE_THROUGH);
3048 ADD_FLAGS(FILE_SEQUENTIAL_ONLY);
3049 ADD_FLAGS(FILE_NO_INTERMEDIATE_BUFFERING);
3050 ADD_FLAGS(FILE_SYNCHRONOUS_IO_ALERT);
3051 ADD_FLAGS(FILE_SYNCHRONOUS_IO_NONALERT);
3052 ADD_FLAGS(FILE_NON_DIRECTORY_FILE);
3053 ADD_FLAGS(FILE_CREATE_TREE_CONNECTION);
3054 ADD_FLAGS(FILE_COMPLETE_IF_OPLOCKED);
3055 ADD_FLAGS(FILE_NO_EA_KNOWLEDGE);
3056 ADD_FLAGS(FILE_EIGHT_DOT_THREE_ONLY);
3057 ADD_FLAGS(FILE_RANDOM_ACCESS);
3058 ADD_FLAGS(FILE_DELETE_ON_CLOSE);
3059 ADD_FLAGS(FILE_OPEN_BY_FILE_ID);
3060 ADD_FLAGS(FILE_OPEN_FOR_BACKUP_INTENT);
3061 ADD_FLAGS(FILE_NO_COMPRESSION);
3062 ADD_FLAGS(FILE_RESERVER_OPFILTER);
3063 ADD_FLAGS(FILE_OPEN_REPARSE_POINT);
3064 ADD_FLAGS(FILE_OPEN_NO_RECALL);
3065 ADD_FLAGS(FILE_OPEN_FOR_FREE_SPACE_QUERY);
3067 ADD_FLAGS(FILE_SHARE_READ);
3068 ADD_FLAGS(FILE_SHARE_WRITE);
3069 ADD_FLAGS(FILE_SHARE_DELETE);
3071 /* change notify completion filter flags */
3072 ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
3073 ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
3074 ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
3075 ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
3076 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
3077 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
3078 ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
3079 ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
3080 ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
3081 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
3082 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
3083 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
3084 ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
3085 ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
3087 /* change notify action results */
3088 ADD_FLAGS(NOTIFY_ACTION_ADDED);
3089 ADD_FLAGS(NOTIFY_ACTION_REMOVED);
3090 ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
3091 ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
3092 ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
3093 ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
3094 ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
3095 ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
3097 /* CreateDisposition values */
3098 ADD_FLAGS(FILE_SUPERSEDE);
3099 ADD_FLAGS(FILE_OPEN);
3100 ADD_FLAGS(FILE_CREATE);
3101 ADD_FLAGS(FILE_OPEN_IF);
3102 ADD_FLAGS(FILE_OVERWRITE);
3103 ADD_FLAGS(FILE_OVERWRITE_IF);
3105 ADD_FLAGS(FSCTL_DFS_GET_REFERRALS);
3106 ADD_FLAGS(FSCTL_DFS_GET_REFERRALS_EX);
3107 ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_1);
3108 ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_2);
3109 ADD_FLAGS(FSCTL_REQUEST_BATCH_OPLOCK);
3110 ADD_FLAGS(FSCTL_OPLOCK_BREAK_ACKNOWLEDGE);
3111 ADD_FLAGS(FSCTL_OPBATCH_ACK_CLOSE_PENDING);
3112 ADD_FLAGS(FSCTL_OPLOCK_BREAK_NOTIFY);
3113 ADD_FLAGS(FSCTL_GET_COMPRESSION);
3114 ADD_FLAGS(FSCTL_FILESYS_GET_STATISTICS);
3115 ADD_FLAGS(FSCTL_GET_NTFS_VOLUME_DATA);
3116 ADD_FLAGS(FSCTL_IS_VOLUME_DIRTY);
3117 ADD_FLAGS(FSCTL_FIND_FILES_BY_SID);
3118 ADD_FLAGS(FSCTL_SET_OBJECT_ID);
3119 ADD_FLAGS(FSCTL_GET_OBJECT_ID);
3120 ADD_FLAGS(FSCTL_DELETE_OBJECT_ID);
3121 ADD_FLAGS(FSCTL_SET_REPARSE_POINT);
3122 ADD_FLAGS(FSCTL_GET_REPARSE_POINT);
3123 ADD_FLAGS(FSCTL_DELETE_REPARSE_POINT);
3124 ADD_FLAGS(FSCTL_SET_OBJECT_ID_EXTENDED);
3125 ADD_FLAGS(FSCTL_CREATE_OR_GET_OBJECT_ID);
3126 ADD_FLAGS(FSCTL_SET_SPARSE);
3127 ADD_FLAGS(FSCTL_SET_ZERO_DATA);
3128 ADD_FLAGS(FSCTL_SET_ZERO_ON_DEALLOCATION);
3129 ADD_FLAGS(FSCTL_READ_FILE_USN_DATA);
3130 ADD_FLAGS(FSCTL_WRITE_USN_CLOSE_RECORD);
3131 ADD_FLAGS(FSCTL_QUERY_ALLOCATED_RANGES);
3132 ADD_FLAGS(FSCTL_QUERY_ON_DISK_VOLUME_INFO);
3133 ADD_FLAGS(FSCTL_QUERY_SPARING_INFO);
3134 ADD_FLAGS(FSCTL_FILE_LEVEL_TRIM);
3135 ADD_FLAGS(FSCTL_OFFLOAD_READ);
3136 ADD_FLAGS(FSCTL_OFFLOAD_WRITE);
3137 ADD_FLAGS(FSCTL_SET_INTEGRITY_INFORMATION);
3138 ADD_FLAGS(FSCTL_DUP_EXTENTS_TO_FILE);
3139 ADD_FLAGS(FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX);
3140 ADD_FLAGS(FSCTL_STORAGE_QOS_CONTROL);
3141 ADD_FLAGS(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST);
3142 ADD_FLAGS(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT);
3143 ADD_FLAGS(FSCTL_PIPE_PEEK);
3144 ADD_FLAGS(FSCTL_NAMED_PIPE_READ_WRITE);
3145 ADD_FLAGS(FSCTL_PIPE_TRANSCEIVE);
3146 ADD_FLAGS(FSCTL_PIPE_WAIT);
3147 ADD_FLAGS(FSCTL_GET_SHADOW_COPY_DATA);
3148 ADD_FLAGS(FSCTL_SRV_ENUM_SNAPS);
3149 ADD_FLAGS(FSCTL_SRV_REQUEST_RESUME_KEY);
3150 ADD_FLAGS(FSCTL_SRV_COPYCHUNK);
3151 ADD_FLAGS(FSCTL_SRV_COPYCHUNK_WRITE);
3152 ADD_FLAGS(FSCTL_SRV_READ_HASH);
3153 ADD_FLAGS(FSCTL_LMR_REQ_RESILIENCY);
3154 ADD_FLAGS(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION);
3155 ADD_FLAGS(FSCTL_QUERY_NETWORK_INTERFACE_INFO);
3157 ADD_FLAGS(SYMLINK_ERROR_TAG);
3158 ADD_FLAGS(SYMLINK_FLAG_RELATIVE);
3159 ADD_FLAGS(SYMLINK_ADMIN);
3160 ADD_FLAGS(SYMLINK_UNTRUSTED);
3161 ADD_FLAGS(SYMLINK_TRUST_UNKNOWN);
3162 ADD_FLAGS(SYMLINK_TRUST_MASK);
3164 ADD_FLAGS(IO_REPARSE_TAG_RESERVED_ZERO);
3165 ADD_FLAGS(IO_REPARSE_TAG_SYMLINK);
3166 ADD_FLAGS(IO_REPARSE_TAG_MOUNT_POINT);
3167 ADD_FLAGS(IO_REPARSE_TAG_HSM);
3168 ADD_FLAGS(IO_REPARSE_TAG_SIS);
3169 ADD_FLAGS(IO_REPARSE_TAG_DFS);
3170 ADD_FLAGS(IO_REPARSE_TAG_NFS);
3172 ADD_FLAGS(FSCC_FILE_DIRECTORY_INFORMATION);
3173 ADD_FLAGS(FSCC_FILE_FULL_DIRECTORY_INFORMATION);
3174 ADD_FLAGS(FSCC_FILE_BOTH_DIRECTORY_INFORMATION);
3175 ADD_FLAGS(FSCC_FILE_BASIC_INFORMATION);
3176 ADD_FLAGS(FSCC_FILE_STANDARD_INFORMATION);
3177 ADD_FLAGS(FSCC_FILE_INTERNAL_INFORMATION);
3178 ADD_FLAGS(FSCC_FILE_EA_INFORMATION);
3179 ADD_FLAGS(FSCC_FILE_ACCESS_INFORMATION);
3180 ADD_FLAGS(FSCC_FILE_NAME_INFORMATION);
3181 ADD_FLAGS(FSCC_FILE_RENAME_INFORMATION);
3182 ADD_FLAGS(FSCC_FILE_LINK_INFORMATION);
3183 ADD_FLAGS(FSCC_FILE_NAMES_INFORMATION);
3184 ADD_FLAGS(FSCC_FILE_DISPOSITION_INFORMATION);
3185 ADD_FLAGS(FSCC_FILE_POSITION_INFORMATION);
3186 ADD_FLAGS(FSCC_FILE_FULL_EA_INFORMATION);
3187 ADD_FLAGS(FSCC_FILE_MODE_INFORMATION);
3188 ADD_FLAGS(FSCC_FILE_ALIGNMENT_INFORMATION);
3189 ADD_FLAGS(FSCC_FILE_ALL_INFORMATION);
3190 ADD_FLAGS(FSCC_FILE_ALLOCATION_INFORMATION);
3191 ADD_FLAGS(FSCC_FILE_END_OF_FILE_INFORMATION);
3192 ADD_FLAGS(FSCC_FILE_ALTERNATE_NAME_INFORMATION);
3193 ADD_FLAGS(FSCC_FILE_STREAM_INFORMATION);
3194 ADD_FLAGS(FSCC_FILE_PIPE_INFORMATION);
3195 ADD_FLAGS(FSCC_FILE_PIPE_LOCAL_INFORMATION);
3196 ADD_FLAGS(FSCC_FILE_PIPE_REMOTE_INFORMATION);
3197 ADD_FLAGS(FSCC_FILE_MAILSLOT_QUERY_INFORMATION);
3198 ADD_FLAGS(FSCC_FILE_MAILSLOT_SET_INFORMATION);
3199 ADD_FLAGS(FSCC_FILE_COMPRESSION_INFORMATION);
3200 ADD_FLAGS(FSCC_FILE_OBJECTID_INFORMATION);
3201 ADD_FLAGS(FSCC_FILE_COMPLETION_INFORMATION);
3202 ADD_FLAGS(FSCC_FILE_MOVE_CLUSTER_INFORMATION);
3203 ADD_FLAGS(FSCC_FILE_QUOTA_INFORMATION);
3204 ADD_FLAGS(FSCC_FILE_REPARSEPOINT_INFORMATION);
3205 ADD_FLAGS(FSCC_FILE_NETWORK_OPEN_INFORMATION);
3206 ADD_FLAGS(FSCC_FILE_ATTRIBUTE_TAG_INFORMATION);
3207 ADD_FLAGS(FSCC_FILE_TRACKING_INFORMATION);
3208 ADD_FLAGS(FSCC_FILE_ID_BOTH_DIRECTORY_INFORMATION);
3209 ADD_FLAGS(FSCC_FILE_ID_FULL_DIRECTORY_INFORMATION);
3210 ADD_FLAGS(FSCC_FILE_VALID_DATA_LENGTH_INFORMATION);
3211 ADD_FLAGS(FSCC_FILE_SHORT_NAME_INFORMATION);
3212 ADD_FLAGS(FSCC_FILE_SFIO_RESERVE_INFORMATION);
3213 ADD_FLAGS(FSCC_FILE_SFIO_VOLUME_INFORMATION);
3214 ADD_FLAGS(FSCC_FILE_HARD_LINK_INFORMATION);
3215 ADD_FLAGS(FSCC_FILE_NORMALIZED_NAME_INFORMATION);
3216 ADD_FLAGS(FSCC_FILE_ID_GLOBAL_TX_DIRECTORY_INFORMATION);
3217 ADD_FLAGS(FSCC_FILE_STANDARD_LINK_INFORMATION);
3218 ADD_FLAGS(FSCC_FILE_MAXIMUM_INFORMATION);
3220 #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
3222 ADD_STRING(SMB2_CREATE_TAG_EXTA);
3223 ADD_STRING(SMB2_CREATE_TAG_MXAC);
3224 ADD_STRING(SMB2_CREATE_TAG_SECD);
3225 ADD_STRING(SMB2_CREATE_TAG_DHNQ);
3226 ADD_STRING(SMB2_CREATE_TAG_DHNC);
3227 ADD_STRING(SMB2_CREATE_TAG_ALSI);
3228 ADD_STRING(SMB2_CREATE_TAG_TWRP);
3229 ADD_STRING(SMB2_CREATE_TAG_QFID);
3230 ADD_STRING(SMB2_CREATE_TAG_RQLS);
3231 ADD_STRING(SMB2_CREATE_TAG_DH2Q);
3232 ADD_STRING(SMB2_CREATE_TAG_DH2C);
3233 ADD_STRING(SMB2_CREATE_TAG_AAPL);
3234 ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
3235 ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
3236 ADD_STRING(SMB2_CREATE_TAG_POSIX);
3237 ADD_FLAGS(SMB2_FIND_POSIX_INFORMATION);
3238 ADD_FLAGS(FILE_SUPERSEDE);
3239 ADD_FLAGS(FILE_OPEN);
3240 ADD_FLAGS(FILE_CREATE);
3241 ADD_FLAGS(FILE_OPEN_IF);
3242 ADD_FLAGS(FILE_OVERWRITE);
3243 ADD_FLAGS(FILE_OVERWRITE_IF);
3244 ADD_FLAGS(FILE_DIRECTORY_FILE);
3246 ADD_FLAGS(SMB2_CLOSE_FLAGS_FULL_INFORMATION);
3248 return m;