drsuapi.idl: fix source_dsa spelling
[samba4-gss.git] / source3 / libsmb / pylibsmb.c
blob97ae69ef50e779989c26b588de6746adafa20792
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"
63 #include "librpc/gen_ndr/ndr_security.h"
65 #define LIST_ATTRIBUTE_MASK \
66 (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
68 static PyTypeObject *dom_sid_Type = NULL;
70 static PyTypeObject *get_pytype(const char *module, const char *type)
72 PyObject *mod;
73 PyTypeObject *result;
75 mod = PyImport_ImportModule(module);
76 if (mod == NULL) {
77 PyErr_Format(PyExc_RuntimeError,
78 "Unable to import %s to check type %s",
79 module, type);
80 return NULL;
82 result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
83 Py_DECREF(mod);
84 if (result == NULL) {
85 PyErr_Format(PyExc_RuntimeError,
86 "Unable to find type %s in module %s",
87 module, type);
88 return NULL;
90 return result;
94 * We're using "const char * const *" for keywords,
95 * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
96 * inevitable warnings to just one place.
98 static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
99 const char *format, const char * const *keywords,
100 ...)
102 char **_keywords = discard_const_p(char *, keywords);
103 va_list a;
104 int ret;
105 va_start(a, keywords);
106 ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
107 _keywords, a);
108 va_end(a);
109 return ret;
112 struct py_cli_thread;
114 struct py_cli_oplock_break {
115 uint16_t fnum;
116 uint8_t level;
119 struct py_cli_state {
120 PyObject_HEAD
121 struct cli_state *cli;
122 struct tevent_context *ev;
123 int (*req_wait_fn)(struct tevent_context *ev,
124 struct tevent_req *req);
125 struct py_cli_thread *thread_state;
127 struct tevent_req *oplock_waiter;
128 struct py_cli_oplock_break *oplock_breaks;
129 struct py_tevent_cond *oplock_cond;
132 #ifdef HAVE_PTHREAD
134 #include <pthread.h>
136 struct py_cli_thread {
139 * Pipe to make the poll thread wake up in our destructor, so
140 * that we can exit and join the thread.
142 int shutdown_pipe[2];
143 struct tevent_fd *shutdown_fde;
144 bool do_shutdown;
145 pthread_t id;
148 * Thread state to release the GIL during the poll(2) syscall
150 PyThreadState *py_threadstate;
153 static void *py_cli_state_poll_thread(void *private_data)
155 struct py_cli_state *self = (struct py_cli_state *)private_data;
156 struct py_cli_thread *t = self->thread_state;
157 PyGILState_STATE gstate;
159 gstate = PyGILState_Ensure();
161 while (!t->do_shutdown) {
162 int ret;
163 ret = tevent_loop_once(self->ev);
164 assert(ret == 0);
166 PyGILState_Release(gstate);
167 return NULL;
170 static void py_cli_state_trace_callback(enum tevent_trace_point point,
171 void *private_data)
173 struct py_cli_state *self = (struct py_cli_state *)private_data;
174 struct py_cli_thread *t = self->thread_state;
176 switch(point) {
177 case TEVENT_TRACE_BEFORE_WAIT:
178 assert(t->py_threadstate == NULL);
179 t->py_threadstate = PyEval_SaveThread();
180 break;
181 case TEVENT_TRACE_AFTER_WAIT:
182 assert(t->py_threadstate != NULL);
183 PyEval_RestoreThread(t->py_threadstate);
184 t->py_threadstate = NULL;
185 break;
186 default:
187 break;
191 static void py_cli_state_shutdown_handler(struct tevent_context *ev,
192 struct tevent_fd *fde,
193 uint16_t flags,
194 void *private_data)
196 struct py_cli_state *self = (struct py_cli_state *)private_data;
197 struct py_cli_thread *t = self->thread_state;
199 if ((flags & TEVENT_FD_READ) == 0) {
200 return;
202 TALLOC_FREE(t->shutdown_fde);
203 t->do_shutdown = true;
206 static int py_cli_thread_destructor(struct py_cli_thread *t)
208 char c = 0;
209 ssize_t written;
210 int ret;
212 if (t->shutdown_pipe[1] != -1) {
213 do {
215 * This will wake the poll thread from the poll(2)
217 written = write(t->shutdown_pipe[1], &c, 1);
218 } while ((written == -1) && (errno == EINTR));
222 * Allow the poll thread to do its own cleanup under the GIL
224 Py_BEGIN_ALLOW_THREADS
225 ret = pthread_join(t->id, NULL);
226 Py_END_ALLOW_THREADS
227 assert(ret == 0);
229 if (t->shutdown_pipe[0] != -1) {
230 close(t->shutdown_pipe[0]);
231 t->shutdown_pipe[0] = -1;
233 if (t->shutdown_pipe[1] != -1) {
234 close(t->shutdown_pipe[1]);
235 t->shutdown_pipe[1] = -1;
237 return 0;
240 static int py_tevent_cond_req_wait(struct tevent_context *ev,
241 struct tevent_req *req);
243 static bool py_cli_state_setup_mt_ev(struct py_cli_state *self)
245 struct py_cli_thread *t = NULL;
246 int ret;
248 self->ev = tevent_context_init_byname(NULL, "poll_mt");
249 if (self->ev == NULL) {
250 goto fail;
252 samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
253 tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
255 self->req_wait_fn = py_tevent_cond_req_wait;
257 self->thread_state = talloc_zero(NULL, struct py_cli_thread);
258 if (self->thread_state == NULL) {
259 goto fail;
261 t = self->thread_state;
263 ret = pipe(t->shutdown_pipe);
264 if (ret == -1) {
265 goto fail;
267 t->shutdown_fde = tevent_add_fd(
268 self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ,
269 py_cli_state_shutdown_handler, self);
270 if (t->shutdown_fde == NULL) {
271 goto fail;
274 PyEval_InitThreads();
276 ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
277 if (ret != 0) {
278 goto fail;
280 talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
281 return true;
283 fail:
284 if (t != NULL) {
285 TALLOC_FREE(t->shutdown_fde);
287 if (t->shutdown_pipe[0] != -1) {
288 close(t->shutdown_pipe[0]);
289 t->shutdown_pipe[0] = -1;
291 if (t->shutdown_pipe[1] != -1) {
292 close(t->shutdown_pipe[1]);
293 t->shutdown_pipe[1] = -1;
297 TALLOC_FREE(self->thread_state);
298 TALLOC_FREE(self->ev);
299 return false;
302 struct py_tevent_cond {
303 pthread_mutex_t mutex;
304 pthread_cond_t cond;
305 bool is_done;
308 static void py_tevent_signalme(struct tevent_req *req);
310 static int py_tevent_cond_wait(struct py_tevent_cond *cond)
312 int ret, result;
314 result = pthread_mutex_init(&cond->mutex, NULL);
315 if (result != 0) {
316 goto fail;
318 result = pthread_cond_init(&cond->cond, NULL);
319 if (result != 0) {
320 goto fail_mutex;
323 result = pthread_mutex_lock(&cond->mutex);
324 if (result != 0) {
325 goto fail_cond;
328 cond->is_done = false;
330 while (!cond->is_done) {
332 Py_BEGIN_ALLOW_THREADS
333 result = pthread_cond_wait(&cond->cond, &cond->mutex);
334 Py_END_ALLOW_THREADS
336 if (result != 0) {
337 goto fail_unlock;
341 fail_unlock:
342 ret = pthread_mutex_unlock(&cond->mutex);
343 assert(ret == 0);
344 fail_cond:
345 ret = pthread_cond_destroy(&cond->cond);
346 assert(ret == 0);
347 fail_mutex:
348 ret = pthread_mutex_destroy(&cond->mutex);
349 assert(ret == 0);
350 fail:
351 return result;
354 static int py_tevent_cond_req_wait(struct tevent_context *ev,
355 struct tevent_req *req)
357 struct py_tevent_cond cond;
358 tevent_req_set_callback(req, py_tevent_signalme, &cond);
359 return py_tevent_cond_wait(&cond);
362 static void py_tevent_cond_signal(struct py_tevent_cond *cond)
364 int ret;
366 ret = pthread_mutex_lock(&cond->mutex);
367 assert(ret == 0);
369 cond->is_done = true;
371 ret = pthread_cond_signal(&cond->cond);
372 assert(ret == 0);
373 ret = pthread_mutex_unlock(&cond->mutex);
374 assert(ret == 0);
377 static void py_tevent_signalme(struct tevent_req *req)
379 struct py_tevent_cond *cond = (struct py_tevent_cond *)
380 tevent_req_callback_data_void(req);
382 py_tevent_cond_signal(cond);
385 #endif
387 static int py_tevent_req_wait(struct tevent_context *ev,
388 struct tevent_req *req);
390 static bool py_cli_state_setup_ev(struct py_cli_state *self)
392 self->ev = tevent_context_init(NULL);
393 if (self->ev == NULL) {
394 return false;
397 samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
399 self->req_wait_fn = py_tevent_req_wait;
401 return true;
404 static int py_tevent_req_wait(struct tevent_context *ev,
405 struct tevent_req *req)
407 while (tevent_req_is_in_progress(req)) {
408 int ret;
410 ret = tevent_loop_once(ev);
411 if (ret != 0) {
412 return ret;
415 return 0;
418 static bool py_tevent_req_wait_exc(struct py_cli_state *self,
419 struct tevent_req *req)
421 int ret;
423 if (req == NULL) {
424 PyErr_NoMemory();
425 return false;
427 ret = self->req_wait_fn(self->ev, req);
428 if (ret != 0) {
429 TALLOC_FREE(req);
430 errno = ret;
431 PyErr_SetFromErrno(PyExc_RuntimeError);
432 return false;
434 return true;
437 static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
438 PyObject *kwds)
440 struct py_cli_state *self;
442 self = (struct py_cli_state *)type->tp_alloc(type, 0);
443 if (self == NULL) {
444 return NULL;
446 self->cli = NULL;
447 self->ev = NULL;
448 self->thread_state = NULL;
449 self->oplock_waiter = NULL;
450 self->oplock_cond = NULL;
451 self->oplock_breaks = NULL;
452 return (PyObject *)self;
455 static struct smb2_negotiate_contexts *py_cli_get_negotiate_contexts(
456 TALLOC_CTX *mem_ctx, PyObject *list)
458 struct smb2_negotiate_contexts *ctxs = NULL;
459 Py_ssize_t i, len;
460 int ret;
462 ret = PyList_Check(list);
463 if (!ret) {
464 goto fail;
467 len = PyList_Size(list);
468 if (len == 0) {
469 goto fail;
472 ctxs = talloc_zero(mem_ctx, struct smb2_negotiate_contexts);
473 if (ctxs == NULL) {
474 goto fail;
477 for (i=0; i<len; i++) {
478 NTSTATUS status;
480 PyObject *t = PyList_GetItem(list, i);
481 Py_ssize_t tlen;
483 PyObject *ptype = NULL;
484 long type;
486 PyObject *pdata = NULL;
487 DATA_BLOB data = { .data = NULL, };
489 if (t == NULL) {
490 goto fail;
493 ret = PyTuple_Check(t);
494 if (!ret) {
495 goto fail;
498 tlen = PyTuple_Size(t);
499 if (tlen != 2) {
500 goto fail;
503 ptype = PyTuple_GetItem(t, 0);
504 if (ptype == NULL) {
505 goto fail;
507 type = PyLong_AsLong(ptype);
508 if ((type < 0) || (type > UINT16_MAX)) {
509 goto fail;
512 pdata = PyTuple_GetItem(t, 1);
514 ret = PyBytes_Check(pdata);
515 if (!ret) {
516 goto fail;
519 data.data = (uint8_t *)PyBytes_AsString(pdata);
520 data.length = PyBytes_Size(pdata);
522 status = smb2_negotiate_context_add(
523 ctxs, ctxs, type, data.data, data.length);
524 if (!NT_STATUS_IS_OK(status)) {
525 goto fail;
528 return ctxs;
530 fail:
531 TALLOC_FREE(ctxs);
532 return NULL;
535 static void py_cli_got_oplock_break(struct tevent_req *req);
537 static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
538 PyObject *kwds)
540 NTSTATUS status;
541 char *host, *share;
542 PyObject *creds = NULL;
543 struct cli_credentials *cli_creds;
544 PyObject *py_lp = Py_None;
545 PyObject *py_multi_threaded = Py_False;
546 bool multi_threaded = false;
547 PyObject *py_force_smb1 = Py_False;
548 bool force_smb1 = false;
549 PyObject *py_ipc = Py_False;
550 PyObject *py_posix = Py_False;
551 PyObject *py_negotiate_contexts = NULL;
552 struct smb2_negotiate_contexts *negotiate_contexts = NULL;
553 bool use_ipc = false;
554 bool request_posix = false;
555 struct tevent_req *req;
556 bool ret;
557 int flags = 0;
559 static const char *kwlist[] = {
560 "host", "share", "lp", "creds",
561 "multi_threaded", "force_smb1",
562 "ipc",
563 "posix",
564 "negotiate_contexts",
565 NULL
568 PyTypeObject *py_type_Credentials = get_pytype(
569 "samba.credentials", "Credentials");
570 if (py_type_Credentials == NULL) {
571 return -1;
574 ret = ParseTupleAndKeywords(
575 args, kwds, "ssO|O!OOOOO", kwlist,
576 &host, &share, &py_lp,
577 py_type_Credentials, &creds,
578 &py_multi_threaded,
579 &py_force_smb1,
580 &py_ipc,
581 &py_posix,
582 &py_negotiate_contexts);
584 Py_DECREF(py_type_Credentials);
586 if (!ret) {
587 return -1;
590 multi_threaded = PyObject_IsTrue(py_multi_threaded);
591 force_smb1 = PyObject_IsTrue(py_force_smb1);
593 if (force_smb1) {
595 * As most of the cli_*_send() function
596 * don't support SMB2 (it's only plugged
597 * into the sync wrapper functions currently)
598 * we have a way to force SMB1.
600 flags = CLI_FULL_CONNECTION_FORCE_SMB1;
603 use_ipc = PyObject_IsTrue(py_ipc);
604 if (use_ipc) {
605 flags |= CLI_FULL_CONNECTION_IPC;
608 request_posix = PyObject_IsTrue(py_posix);
609 if (request_posix) {
610 flags |= CLI_FULL_CONNECTION_REQUEST_POSIX;
613 if (py_negotiate_contexts != NULL) {
614 negotiate_contexts = py_cli_get_negotiate_contexts(
615 talloc_tos(), py_negotiate_contexts);
616 if (negotiate_contexts == NULL) {
617 return -1;
621 if (multi_threaded) {
622 #ifdef HAVE_PTHREAD
623 ret = py_cli_state_setup_mt_ev(self);
624 if (!ret) {
625 return -1;
627 #else
628 PyErr_SetString(PyExc_RuntimeError,
629 "No PTHREAD support available");
630 return -1;
631 #endif
632 } else {
633 ret = py_cli_state_setup_ev(self);
634 if (!ret) {
635 return -1;
639 if (creds == NULL) {
640 cli_creds = cli_credentials_init_anon(NULL);
641 } else {
642 cli_creds = PyCredentials_AsCliCredentials(creds);
645 req = cli_full_connection_creds_send(
646 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
647 cli_creds, flags,
648 negotiate_contexts);
649 if (!py_tevent_req_wait_exc(self, req)) {
650 return -1;
652 status = cli_full_connection_creds_recv(req, NULL, &self->cli);
653 TALLOC_FREE(req);
655 if (!NT_STATUS_IS_OK(status)) {
656 PyErr_SetNTSTATUS(status);
657 return -1;
661 * Oplocks require a multi threaded connection
663 if (self->thread_state == NULL) {
664 return 0;
667 self->oplock_waiter = cli_smb_oplock_break_waiter_send(
668 self->ev, self->ev, self->cli);
669 if (self->oplock_waiter == NULL) {
670 PyErr_NoMemory();
671 return -1;
673 tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
674 self);
675 return 0;
678 static void py_cli_got_oplock_break(struct tevent_req *req)
680 struct py_cli_state *self = (struct py_cli_state *)
681 tevent_req_callback_data_void(req);
682 struct py_cli_oplock_break b;
683 struct py_cli_oplock_break *tmp;
684 size_t num_breaks;
685 NTSTATUS status;
687 status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
688 TALLOC_FREE(req);
689 self->oplock_waiter = NULL;
691 if (!NT_STATUS_IS_OK(status)) {
692 return;
695 num_breaks = talloc_array_length(self->oplock_breaks);
696 tmp = talloc_realloc(self->ev, self->oplock_breaks,
697 struct py_cli_oplock_break, num_breaks+1);
698 if (tmp == NULL) {
699 return;
701 self->oplock_breaks = tmp;
702 self->oplock_breaks[num_breaks] = b;
704 if (self->oplock_cond != NULL) {
705 py_tevent_cond_signal(self->oplock_cond);
708 self->oplock_waiter = cli_smb_oplock_break_waiter_send(
709 self->ev, self->ev, self->cli);
710 if (self->oplock_waiter == NULL) {
711 return;
713 tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
714 self);
717 static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
718 PyObject *args)
720 size_t num_oplock_breaks;
722 if (!PyArg_ParseTuple(args, "")) {
723 return NULL;
726 if (self->thread_state == NULL) {
727 PyErr_SetString(PyExc_RuntimeError,
728 "get_oplock_break() only possible on "
729 "a multi_threaded connection");
730 return NULL;
733 if (self->oplock_cond != NULL) {
734 errno = EBUSY;
735 PyErr_SetFromErrno(PyExc_RuntimeError);
736 return NULL;
739 num_oplock_breaks = talloc_array_length(self->oplock_breaks);
741 if (num_oplock_breaks == 0) {
742 struct py_tevent_cond cond;
743 int ret;
745 self->oplock_cond = &cond;
746 ret = py_tevent_cond_wait(&cond);
747 self->oplock_cond = NULL;
749 if (ret != 0) {
750 errno = ret;
751 PyErr_SetFromErrno(PyExc_RuntimeError);
752 return NULL;
756 num_oplock_breaks = talloc_array_length(self->oplock_breaks);
757 if (num_oplock_breaks > 0) {
758 PyObject *result;
760 result = Py_BuildValue(
761 "{s:i,s:i}",
762 "fnum", self->oplock_breaks[0].fnum,
763 "level", self->oplock_breaks[0].level);
765 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
766 sizeof(self->oplock_breaks[0]) *
767 (num_oplock_breaks - 1));
768 self->oplock_breaks = talloc_realloc(
769 NULL, self->oplock_breaks, struct py_cli_oplock_break,
770 num_oplock_breaks - 1);
772 return result;
774 Py_RETURN_NONE;
777 static void py_cli_state_dealloc(struct py_cli_state *self)
779 TALLOC_FREE(self->thread_state);
780 TALLOC_FREE(self->oplock_waiter);
781 TALLOC_FREE(self->ev);
783 if (self->cli != NULL) {
784 cli_shutdown(self->cli);
785 self->cli = NULL;
787 Py_TYPE(self)->tp_free((PyObject *)self);
790 static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
792 unsigned int nmsecs = 0;
793 unsigned int omsecs = 0;
795 if (!PyArg_ParseTuple(args, "I", &nmsecs)) {
796 return NULL;
799 omsecs = cli_set_timeout(self->cli, nmsecs);
801 return PyLong_FromLong(omsecs);
804 static PyObject *py_cli_echo(struct py_cli_state *self,
805 PyObject *Py_UNUSED(ignored))
807 DATA_BLOB data = data_blob_string_const("keepalive");
808 struct tevent_req *req = NULL;
809 NTSTATUS status;
811 req = cli_echo_send(NULL, self->ev, self->cli, 1, data);
812 if (!py_tevent_req_wait_exc(self, req)) {
813 return NULL;
815 status = cli_echo_recv(req);
816 TALLOC_FREE(req);
817 PyErr_NTSTATUS_NOT_OK_RAISE(status);
819 Py_RETURN_NONE;
822 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
823 PyObject *kwds)
825 char *fname;
826 unsigned CreateFlags = 0;
827 unsigned DesiredAccess = FILE_GENERIC_READ;
828 unsigned FileAttributes = 0;
829 unsigned ShareAccess = 0;
830 unsigned CreateDisposition = FILE_OPEN;
831 unsigned CreateOptions = 0;
832 unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
833 unsigned SecurityFlags = 0;
834 uint16_t fnum;
835 struct tevent_req *req;
836 NTSTATUS status;
838 static const char *kwlist[] = {
839 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
840 "ShareAccess", "CreateDisposition", "CreateOptions",
841 "ImpersonationLevel", "SecurityFlags", NULL };
843 if (!ParseTupleAndKeywords(
844 args, kwds, "s|IIIIIIII", kwlist,
845 &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
846 &ShareAccess, &CreateDisposition, &CreateOptions,
847 &ImpersonationLevel, &SecurityFlags)) {
848 return NULL;
851 req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
852 DesiredAccess, FileAttributes, ShareAccess,
853 CreateDisposition, CreateOptions,
854 ImpersonationLevel, SecurityFlags);
855 if (!py_tevent_req_wait_exc(self, req)) {
856 return NULL;
858 status = cli_ntcreate_recv(req, &fnum, NULL);
859 TALLOC_FREE(req);
861 if (!NT_STATUS_IS_OK(status)) {
862 PyErr_SetNTSTATUS(status);
863 return NULL;
865 return Py_BuildValue("I", (unsigned)fnum);
868 static struct smb2_create_blobs *py_cli_get_create_contexts(
869 TALLOC_CTX *mem_ctx, PyObject *list)
871 struct smb2_create_blobs *ctxs = NULL;
872 Py_ssize_t i, len;
873 int ret;
875 ret = PyList_Check(list);
876 if (!ret) {
877 goto fail;
880 len = PyList_Size(list);
881 if (len == 0) {
882 goto fail;
885 ctxs = talloc_zero(mem_ctx, struct smb2_create_blobs);
886 if (ctxs == NULL) {
887 goto fail;
890 for (i=0; i<len; i++) {
891 NTSTATUS status;
893 PyObject *t = NULL;
894 Py_ssize_t tlen;
896 PyObject *pname = NULL;
897 char *name = NULL;
899 PyObject *pdata = NULL;
900 DATA_BLOB data = { .data = NULL, };
902 t = PyList_GetItem(list, i);
903 if (t == NULL) {
904 goto fail;
907 ret = PyTuple_Check(t);
908 if (!ret) {
909 goto fail;
912 tlen = PyTuple_Size(t);
913 if (tlen != 2) {
914 goto fail;
917 pname = PyTuple_GetItem(t, 0);
918 if (pname == NULL) {
919 goto fail;
921 ret = PyBytes_Check(pname);
922 if (!ret) {
923 goto fail;
925 name = PyBytes_AsString(pname);
927 pdata = PyTuple_GetItem(t, 1);
928 if (pdata == NULL) {
929 goto fail;
931 ret = PyBytes_Check(pdata);
932 if (!ret) {
933 goto fail;
935 data = (DATA_BLOB) {
936 .data = (uint8_t *)PyBytes_AsString(pdata),
937 .length = PyBytes_Size(pdata),
939 status = smb2_create_blob_add(ctxs, ctxs, name, data);
940 if (!NT_STATUS_IS_OK(status)) {
941 goto fail;
944 return ctxs;
946 fail:
947 TALLOC_FREE(ctxs);
948 return NULL;
951 static PyObject *py_cli_create_contexts(const struct smb2_create_blobs *blobs)
953 PyObject *py_blobs = NULL;
954 uint32_t i;
956 if (blobs == NULL) {
957 Py_RETURN_NONE;
960 py_blobs = PyList_New(blobs->num_blobs);
961 if (py_blobs == NULL) {
962 return NULL;
965 for (i=0; i<blobs->num_blobs; i++) {
966 struct smb2_create_blob *blob = &blobs->blobs[i];
967 PyObject *py_blob = NULL;
968 int ret;
970 py_blob = Py_BuildValue(
971 "(yy#)",
972 blob->tag,
973 blob->data.data,
974 (int)blob->data.length);
975 if (py_blob == NULL) {
976 goto fail;
979 ret = PyList_SetItem(py_blobs, i, py_blob);
980 if (ret == -1) {
981 Py_XDECREF(py_blob);
982 goto fail;
985 return py_blobs;
987 fail:
988 Py_XDECREF(py_blobs);
989 return NULL;
992 static PyObject *py_cli_create_returns(const struct smb_create_returns *r)
994 PyObject *v = NULL;
996 v = Py_BuildValue(
997 "{sLsLsLsLsLsLsLsLsLsL}",
998 "oplock_level",
999 (unsigned long long)r->oplock_level,
1000 "flags",
1001 (unsigned long long)r->flags,
1002 "create_action",
1003 (unsigned long long)r->create_action,
1004 "creation_time",
1005 (unsigned long long)r->creation_time,
1006 "last_access_time",
1007 (unsigned long long)r->last_access_time,
1008 "last_write_time",
1009 (unsigned long long)r->last_write_time,
1010 "change_time",
1011 (unsigned long long)r->change_time,
1012 "allocation_size",
1013 (unsigned long long)r->allocation_size,
1014 "end_of_file",
1015 (unsigned long long)r->end_of_file,
1016 "file_attributes",
1017 (unsigned long long)r->file_attributes);
1018 return v;
1021 static PyObject *py_cli_symlink_error(const struct symlink_reparse_struct *s)
1023 char *subst_utf8 = NULL, *print_utf8 = NULL;
1024 size_t subst_utf8_len, print_utf8_len;
1025 PyObject *v = NULL;
1026 bool ok = true;
1029 * Python wants utf-8, regardless of our unix charset (which
1030 * most likely is utf-8 these days, but you never know).
1033 ok = convert_string_talloc(
1034 talloc_tos(),
1035 CH_UNIX,
1036 CH_UTF8,
1037 s->substitute_name,
1038 strlen(s->substitute_name),
1039 &subst_utf8,
1040 &subst_utf8_len);
1041 if (!ok) {
1042 goto fail;
1045 ok = convert_string_talloc(
1046 talloc_tos(),
1047 CH_UNIX,
1048 CH_UTF8,
1049 s->print_name,
1050 strlen(s->print_name),
1051 &print_utf8,
1052 &print_utf8_len);
1053 if (!ok) {
1054 goto fail;
1057 v = Py_BuildValue(
1058 "{sLsssssL}",
1059 "unparsed_path_length",
1060 (unsigned long long)s->unparsed_path_length,
1061 "substitute_name",
1062 subst_utf8,
1063 "print_name",
1064 print_utf8,
1065 "flags",
1066 (unsigned long long)s->flags);
1068 fail:
1069 TALLOC_FREE(subst_utf8);
1070 TALLOC_FREE(print_utf8);
1071 return v;
1074 static PyObject *py_cli_get_posix_fs_info(
1075 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1077 NTSTATUS status;
1078 struct tevent_req *req = NULL;
1079 uint32_t optimal_transfer_size = 0;
1080 uint32_t block_size = 0;
1081 uint64_t total_blocks = 0;
1082 uint64_t blocks_available = 0;
1083 uint64_t user_blocks_available = 0;
1084 uint64_t total_file_nodes = 0;
1085 uint64_t free_file_nodes = 0;
1086 uint64_t fs_identifier = 0;
1088 req = cli_get_posix_fs_info_send(NULL, self->ev, self->cli);
1089 if (!py_tevent_req_wait_exc(self, req)) {
1090 return NULL;
1093 status = cli_get_posix_fs_info_recv(req,
1094 &optimal_transfer_size,
1095 &block_size,
1096 &total_blocks,
1097 &blocks_available,
1098 &user_blocks_available,
1099 &total_file_nodes,
1100 &free_file_nodes,
1101 &fs_identifier);
1102 TALLOC_FREE(req);
1103 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1105 return Py_BuildValue("{s:I,s:I,s:I,s:I,s:I,s:I,s:I,s:I}",
1106 "optimal_transfer_size", optimal_transfer_size,
1107 "block_size", block_size,
1108 "total_blocks", total_blocks,
1109 "blocks_available", blocks_available,
1110 "user_blocks_available", user_blocks_available,
1111 "total_file_nodes", total_file_nodes,
1112 "free_file_nodes", free_file_nodes,
1113 "fs_identifier", fs_identifier);
1116 static PyObject *py_cli_create_ex(
1117 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1119 char *fname = NULL;
1120 unsigned CreateFlags = 0;
1121 unsigned DesiredAccess = FILE_GENERIC_READ;
1122 unsigned FileAttributes = 0;
1123 unsigned ShareAccess = 0;
1124 unsigned CreateDisposition = FILE_OPEN;
1125 unsigned CreateOptions = 0;
1126 unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
1127 unsigned SecurityFlags = 0;
1128 PyObject *py_create_contexts_in = NULL;
1129 PyObject *py_create_contexts_out = NULL;
1130 struct smb2_create_blobs *create_contexts_in = NULL;
1131 struct smb2_create_blobs create_contexts_out = { .num_blobs = 0 };
1132 struct smb_create_returns cr = { .create_action = 0, };
1133 struct symlink_reparse_struct *symlink = NULL;
1134 PyObject *py_cr = NULL;
1135 uint16_t fnum;
1136 struct tevent_req *req;
1137 NTSTATUS status;
1138 int ret;
1139 bool ok;
1140 PyObject *v = NULL;
1142 static const char *kwlist[] = {
1143 "Name",
1144 "CreateFlags",
1145 "DesiredAccess",
1146 "FileAttributes",
1147 "ShareAccess",
1148 "CreateDisposition",
1149 "CreateOptions",
1150 "ImpersonationLevel",
1151 "SecurityFlags",
1152 "CreateContexts",
1153 NULL };
1155 ret = ParseTupleAndKeywords(
1156 args,
1157 kwds,
1158 "s|IIIIIIIIO",
1159 kwlist,
1160 &fname,
1161 &CreateFlags,
1162 &DesiredAccess,
1163 &FileAttributes,
1164 &ShareAccess,
1165 &CreateDisposition,
1166 &CreateOptions,
1167 &ImpersonationLevel,
1168 &SecurityFlags,
1169 &py_create_contexts_in);
1170 if (!ret) {
1171 return NULL;
1174 if (py_create_contexts_in != NULL) {
1175 create_contexts_in = py_cli_get_create_contexts(
1176 NULL, py_create_contexts_in);
1177 if (create_contexts_in == NULL) {
1178 errno = EINVAL;
1179 PyErr_SetFromErrno(PyExc_RuntimeError);
1180 return NULL;
1184 if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1185 struct cli_smb2_create_flags cflags = {
1186 .batch_oplock = (CreateFlags & REQUEST_BATCH_OPLOCK),
1187 .exclusive_oplock = (CreateFlags & REQUEST_OPLOCK),
1190 req = cli_smb2_create_fnum_send(
1191 NULL,
1192 self->ev,
1193 self->cli,
1194 fname,
1195 cflags,
1196 ImpersonationLevel,
1197 DesiredAccess,
1198 FileAttributes,
1199 ShareAccess,
1200 CreateDisposition,
1201 CreateOptions,
1202 create_contexts_in);
1203 } else {
1204 req = cli_ntcreate_send(
1205 NULL,
1206 self->ev,
1207 self->cli,
1208 fname,
1209 CreateFlags,
1210 DesiredAccess,
1211 FileAttributes,
1212 ShareAccess,
1213 CreateDisposition,
1214 CreateOptions,
1215 ImpersonationLevel,
1216 SecurityFlags);
1219 TALLOC_FREE(create_contexts_in);
1221 ok = py_tevent_req_wait_exc(self, req);
1222 if (!ok) {
1223 return NULL;
1226 if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1227 status = cli_smb2_create_fnum_recv(
1228 req,
1229 &fnum,
1230 &cr,
1231 NULL,
1232 &create_contexts_out,
1233 &symlink);
1234 } else {
1235 status = cli_ntcreate_recv(req, &fnum, &cr);
1238 TALLOC_FREE(req);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 goto fail;
1244 SMB_ASSERT(symlink == NULL);
1246 py_create_contexts_out = py_cli_create_contexts(&create_contexts_out);
1247 TALLOC_FREE(create_contexts_out.blobs);
1248 if (py_create_contexts_out == NULL) {
1249 goto nomem;
1252 py_cr = py_cli_create_returns(&cr);
1253 if (py_cr == NULL) {
1254 goto nomem;
1257 v = Py_BuildValue("(IOO)",
1258 (unsigned)fnum,
1259 py_cr,
1260 py_create_contexts_out);
1261 return v;
1262 nomem:
1263 status = NT_STATUS_NO_MEMORY;
1264 fail:
1265 Py_XDECREF(py_create_contexts_out);
1266 Py_XDECREF(py_cr);
1267 Py_XDECREF(v);
1269 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
1270 (symlink != NULL)) {
1271 PyErr_SetObject(
1272 PyObject_GetAttrString(
1273 PyImport_ImportModule("samba"),
1274 "NTSTATUSError"),
1275 Py_BuildValue(
1276 "I,s,O",
1277 NT_STATUS_V(status),
1278 get_friendly_nt_error_msg(status),
1279 py_cli_symlink_error(symlink)));
1280 } else {
1281 PyErr_SetNTSTATUS(status);
1283 return NULL;
1286 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
1288 struct tevent_req *req;
1289 int fnum;
1290 int flags = 0;
1291 NTSTATUS status;
1293 if (!PyArg_ParseTuple(args, "i|i", &fnum, &flags)) {
1294 return NULL;
1297 req = cli_close_send(NULL, self->ev, self->cli, fnum, flags);
1298 if (!py_tevent_req_wait_exc(self, req)) {
1299 return NULL;
1301 status = cli_close_recv(req);
1302 TALLOC_FREE(req);
1304 if (!NT_STATUS_IS_OK(status)) {
1305 PyErr_SetNTSTATUS(status);
1306 return NULL;
1308 Py_RETURN_NONE;
1311 static PyObject *py_wire_mode_to_unix(struct py_cli_state *self,
1312 PyObject *args)
1314 unsigned long long wire = 0;
1315 mode_t mode;
1316 bool ok;
1317 PyObject *v = NULL;
1319 ok = PyArg_ParseTuple(args, "K", &wire);
1320 if (!ok) {
1321 return NULL;
1323 mode = wire_mode_to_unix(wire);
1325 v = Py_BuildValue("I", (unsigned)mode);
1326 return v;
1329 static PyObject *py_unix_mode_to_wire(struct py_cli_state *self,
1330 PyObject *args)
1332 unsigned long long mode = 0;
1333 uint32_t wire;
1334 bool ok;
1335 PyObject *v = NULL;
1337 ok = PyArg_ParseTuple(args, "K", &mode);
1338 if (!ok) {
1339 return NULL;
1341 wire = unix_mode_to_wire(mode);
1343 v = Py_BuildValue("I", (unsigned)wire);
1344 return v;
1347 static PyObject *py_cli_qfileinfo(struct py_cli_state *self, PyObject *args)
1349 struct tevent_req *req = NULL;
1350 int fnum, level;
1351 uint16_t recv_flags2;
1352 uint8_t *rdata = NULL;
1353 uint32_t num_rdata;
1354 PyObject *result = NULL;
1355 NTSTATUS status;
1357 if (!PyArg_ParseTuple(args, "ii", &fnum, &level)) {
1358 return NULL;
1361 req = cli_qfileinfo_send(
1362 NULL, self->ev, self->cli, fnum, level, 0, UINT32_MAX);
1363 if (!py_tevent_req_wait_exc(self, req)) {
1364 return NULL;
1366 status = cli_qfileinfo_recv(
1367 req, NULL, &recv_flags2, &rdata, &num_rdata);
1368 TALLOC_FREE(req);
1370 if (!NT_STATUS_IS_OK(status)) {
1371 PyErr_SetNTSTATUS(status);
1372 return NULL;
1375 switch (level) {
1376 case FSCC_FILE_ATTRIBUTE_TAG_INFORMATION: {
1377 uint32_t mode = PULL_LE_U32(rdata, 0);
1378 uint32_t tag = PULL_LE_U32(rdata, 4);
1380 if (num_rdata != 8) {
1381 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1382 return NULL;
1385 result = Py_BuildValue("{s:K,s:K}",
1386 "mode",
1387 (unsigned long long)mode,
1388 "tag",
1389 (unsigned long long)tag);
1390 break;
1392 case FSCC_FILE_POSIX_INFORMATION: {
1393 size_t data_off = 0;
1394 time_t btime;
1395 time_t atime;
1396 time_t mtime;
1397 time_t ctime;
1398 uint64_t size;
1399 uint64_t alloc_size;
1400 uint32_t attr;
1401 uint64_t ino;
1402 uint32_t dev;
1403 uint32_t nlinks;
1404 uint32_t reparse_tag;
1405 uint32_t mode;
1406 size_t sid_size;
1407 enum ndr_err_code ndr_err;
1408 struct dom_sid owner, group;
1409 struct dom_sid_buf owner_buf, group_buf;
1411 if (num_rdata < 80) {
1412 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1413 return NULL;
1416 btime = nt_time_to_unix(PULL_LE_U64(rdata, data_off));
1417 data_off += 8;
1418 atime = nt_time_to_unix(PULL_LE_U64(rdata, data_off));
1419 data_off += 8;
1420 mtime = nt_time_to_unix(PULL_LE_U64(rdata, data_off));
1421 data_off += 8;
1422 ctime = nt_time_to_unix(PULL_LE_U64(rdata, data_off));
1423 data_off += 8;
1424 size = PULL_LE_U64(rdata, data_off);
1425 data_off += 8;
1426 alloc_size = PULL_LE_U64(rdata, data_off);
1427 data_off += 8;
1428 attr = PULL_LE_U32(rdata, data_off);
1429 data_off += 4;
1430 ino = PULL_LE_U64(rdata, data_off);
1431 data_off += 8;
1432 dev = PULL_LE_U32(rdata, data_off);
1433 data_off += 4;
1434 /* 4 bytes reserved */
1435 data_off += 4;
1436 nlinks = PULL_LE_U32(rdata, data_off);
1437 data_off += 4;
1438 reparse_tag = PULL_LE_U32(rdata, data_off);
1439 data_off += 4;
1440 mode = PULL_LE_U32(rdata, data_off);
1441 data_off += 4;
1443 ndr_err = ndr_pull_struct_blob_noalloc(
1444 rdata + data_off,
1445 num_rdata - data_off,
1446 &owner,
1447 (ndr_pull_flags_fn_t)ndr_pull_dom_sid,
1448 &sid_size);
1449 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1450 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1451 return NULL;
1453 if (data_off + sid_size < data_off ||
1454 data_off + sid_size > num_rdata)
1456 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1457 return NULL;
1459 data_off += sid_size;
1461 ndr_err = ndr_pull_struct_blob_noalloc(
1462 rdata + data_off,
1463 num_rdata - data_off,
1464 &group,
1465 (ndr_pull_flags_fn_t)ndr_pull_dom_sid,
1466 &sid_size);
1467 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1468 PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
1469 return NULL;
1472 result = Py_BuildValue(
1473 "{s:i," /* attr */
1474 "s:K,s:K,s:K,s:K," /* dates */
1475 "s:K,s:K," /* sizes */
1476 "s:K,s:K,s:K," /* ino, dev, nlinks */
1477 "s:K,s:K," /* tag, mode */
1478 "s:s,s:s}", /* owner, group */
1480 "attrib",
1481 attr,
1483 "btime",
1484 (unsigned long long)btime,
1485 "atime",
1486 (unsigned long long)atime,
1487 "mtime",
1488 (unsigned long long)mtime,
1489 "ctime",
1490 (unsigned long long)ctime,
1492 "allocation_size",
1493 (unsigned long long)alloc_size,
1494 "size",
1495 (unsigned long long)size,
1497 "ino",
1498 (unsigned long long)ino,
1499 "dev",
1500 (unsigned long long)dev,
1501 "nlink",
1502 (unsigned long long)nlinks,
1504 "reparse_tag",
1505 (unsigned long long)reparse_tag,
1506 "perms",
1507 (unsigned long long)mode,
1509 "owner_sid",
1510 dom_sid_str_buf(&owner, &owner_buf),
1511 "group_sid",
1512 dom_sid_str_buf(&group, &group_buf));
1513 break;
1515 default:
1516 result = PyBytes_FromStringAndSize((char *)rdata, num_rdata);
1517 break;
1520 TALLOC_FREE(rdata);
1522 return result;
1525 static PyObject *py_cli_rename(
1526 struct py_cli_state *self, PyObject *args, PyObject *kwds)
1528 char *fname_src = NULL, *fname_dst = NULL;
1529 int replace = false;
1530 struct tevent_req *req = NULL;
1531 NTSTATUS status;
1532 bool ok;
1534 static const char *kwlist[] = { "src", "dst", "replace", NULL };
1536 ok = ParseTupleAndKeywords(
1537 args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
1538 if (!ok) {
1539 return NULL;
1542 req = cli_rename_send(
1543 NULL, self->ev, self->cli, fname_src, fname_dst, replace);
1544 if (!py_tevent_req_wait_exc(self, req)) {
1545 return NULL;
1547 status = cli_rename_recv(req);
1548 TALLOC_FREE(req);
1550 if (!NT_STATUS_IS_OK(status)) {
1551 PyErr_SetNTSTATUS(status);
1552 return NULL;
1554 Py_RETURN_NONE;
1558 struct push_state {
1559 char *data;
1560 off_t nread;
1561 off_t total_data;
1565 * cli_push() helper to write a chunk of data to a remote file
1567 static size_t push_data(uint8_t *buf, size_t n, void *priv)
1569 struct push_state *state = (struct push_state *)priv;
1570 char *curr_ptr = NULL;
1571 off_t remaining;
1572 size_t copied_bytes;
1574 if (state->nread >= state->total_data) {
1575 return 0;
1578 curr_ptr = state->data + state->nread;
1579 remaining = state->total_data - state->nread;
1580 copied_bytes = MIN(remaining, n);
1582 memcpy(buf, curr_ptr, copied_bytes);
1583 state->nread += copied_bytes;
1584 return copied_bytes;
1588 * Writes a file with the contents specified
1590 static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
1592 uint16_t fnum;
1593 const char *filename = NULL;
1594 char *data = NULL;
1595 Py_ssize_t size = 0;
1596 NTSTATUS status;
1597 struct tevent_req *req = NULL;
1598 struct push_state state;
1600 if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
1601 &data, &size)) {
1602 return NULL;
1605 /* create a new file handle for writing to */
1606 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1607 FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
1608 FILE_SHARE_READ|FILE_SHARE_WRITE,
1609 FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
1610 SMB2_IMPERSONATION_IMPERSONATION, 0);
1611 if (!py_tevent_req_wait_exc(self, req)) {
1612 return NULL;
1614 status = cli_ntcreate_recv(req, &fnum, NULL);
1615 TALLOC_FREE(req);
1616 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1618 /* write the new file contents */
1619 state.data = data;
1620 state.nread = 0;
1621 state.total_data = size;
1623 req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
1624 push_data, &state);
1625 if (!py_tevent_req_wait_exc(self, req)) {
1626 return NULL;
1628 status = cli_push_recv(req);
1629 TALLOC_FREE(req);
1630 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1632 /* close the file handle */
1633 req = cli_close_send(NULL, self->ev, self->cli, fnum, 0);
1634 if (!py_tevent_req_wait_exc(self, req)) {
1635 return NULL;
1637 status = cli_close_recv(req);
1638 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1640 Py_RETURN_NONE;
1643 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
1644 PyObject *kwds)
1646 int fnum;
1647 unsigned mode = 0;
1648 char *buf;
1649 Py_ssize_t buflen;
1650 unsigned long long offset;
1651 struct tevent_req *req;
1652 NTSTATUS status;
1653 size_t written;
1655 static const char *kwlist[] = {
1656 "fnum", "buffer", "offset", "mode", NULL };
1658 if (!ParseTupleAndKeywords(
1659 args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
1660 &fnum, &buf, &buflen, &offset, &mode)) {
1661 return NULL;
1664 req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
1665 (uint8_t *)buf, offset, buflen);
1666 if (!py_tevent_req_wait_exc(self, req)) {
1667 return NULL;
1669 status = cli_write_recv(req, &written);
1670 TALLOC_FREE(req);
1672 if (!NT_STATUS_IS_OK(status)) {
1673 PyErr_SetNTSTATUS(status);
1674 return NULL;
1676 return Py_BuildValue("K", (unsigned long long)written);
1680 * Returns the size of the given file
1682 static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
1683 off_t *size)
1685 NTSTATUS status;
1686 struct tevent_req *req = NULL;
1688 req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
1689 if (!py_tevent_req_wait_exc(self, req)) {
1690 return NT_STATUS_INTERNAL_ERROR;
1692 status = cli_qfileinfo_basic_recv(
1693 req, NULL, size, NULL, NULL, NULL, NULL, NULL);
1694 TALLOC_FREE(req);
1695 return status;
1699 * Loads the specified file's contents and returns it
1701 static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
1703 NTSTATUS status;
1704 const char *filename = NULL;
1705 struct tevent_req *req = NULL;
1706 uint16_t fnum;
1707 off_t size;
1708 char *buf = NULL;
1709 off_t nread = 0;
1710 PyObject *result = NULL;
1712 if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
1713 return NULL;
1716 /* get a read file handle */
1717 req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1718 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
1719 FILE_ATTRIBUTE_NORMAL,
1720 FILE_SHARE_READ, FILE_OPEN, 0,
1721 SMB2_IMPERSONATION_IMPERSONATION, 0);
1722 if (!py_tevent_req_wait_exc(self, req)) {
1723 return NULL;
1725 status = cli_ntcreate_recv(req, &fnum, NULL);
1726 TALLOC_FREE(req);
1727 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1729 /* get a buffer to hold the file contents */
1730 status = py_smb_filesize(self, fnum, &size);
1731 PyErr_NTSTATUS_NOT_OK_RAISE(status);
1733 result = PyBytes_FromStringAndSize(NULL, size);
1734 if (result == NULL) {
1735 return NULL;
1738 /* read the file contents */
1739 buf = PyBytes_AS_STRING(result);
1740 req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
1741 size, cli_read_sink, &buf);
1742 if (!py_tevent_req_wait_exc(self, req)) {
1743 Py_XDECREF(result);
1744 return NULL;
1746 status = cli_pull_recv(req, &nread);
1747 TALLOC_FREE(req);
1748 if (!NT_STATUS_IS_OK(status)) {
1749 Py_XDECREF(result);
1750 PyErr_SetNTSTATUS(status);
1751 return NULL;
1754 /* close the file handle */
1755 req = cli_close_send(NULL, self->ev, self->cli, fnum, 0);
1756 if (!py_tevent_req_wait_exc(self, req)) {
1757 Py_XDECREF(result);
1758 return NULL;
1760 status = cli_close_recv(req);
1761 TALLOC_FREE(req);
1762 if (!NT_STATUS_IS_OK(status)) {
1763 Py_XDECREF(result);
1764 PyErr_SetNTSTATUS(status);
1765 return NULL;
1768 /* sanity-check we read the expected number of bytes */
1769 if (nread > size) {
1770 Py_XDECREF(result);
1771 PyErr_Format(PyExc_IOError,
1772 "read invalid - got %zu requested %zu",
1773 nread, size);
1774 return NULL;
1777 if (nread < size) {
1778 if (_PyBytes_Resize(&result, nread) < 0) {
1779 return NULL;
1783 return result;
1786 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
1787 PyObject *kwds)
1789 int fnum;
1790 unsigned long long offset;
1791 unsigned size;
1792 struct tevent_req *req;
1793 NTSTATUS status;
1794 char *buf;
1795 size_t received;
1796 PyObject *result;
1798 static const char *kwlist[] = {
1799 "fnum", "offset", "size", NULL };
1801 if (!ParseTupleAndKeywords(
1802 args, kwds, "iKI", kwlist, &fnum, &offset,
1803 &size)) {
1804 return NULL;
1807 result = PyBytes_FromStringAndSize(NULL, size);
1808 if (result == NULL) {
1809 return NULL;
1811 buf = PyBytes_AS_STRING(result);
1813 req = cli_read_send(NULL, self->ev, self->cli, fnum,
1814 buf, offset, size);
1815 if (!py_tevent_req_wait_exc(self, req)) {
1816 Py_XDECREF(result);
1817 return NULL;
1819 status = cli_read_recv(req, &received);
1820 TALLOC_FREE(req);
1822 if (!NT_STATUS_IS_OK(status)) {
1823 Py_XDECREF(result);
1824 PyErr_SetNTSTATUS(status);
1825 return NULL;
1828 if (received > size) {
1829 Py_XDECREF(result);
1830 PyErr_Format(PyExc_IOError,
1831 "read invalid - got %zu requested %u",
1832 received, size);
1833 return NULL;
1836 if (received < size) {
1837 if (_PyBytes_Resize(&result, received) < 0) {
1838 return NULL;
1842 return result;
1845 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
1846 PyObject *kwds)
1848 int fnum;
1849 unsigned long long size;
1850 struct tevent_req *req;
1851 NTSTATUS status;
1853 static const char *kwlist[] = {
1854 "fnum", "size", NULL };
1856 if (!ParseTupleAndKeywords(
1857 args, kwds, "IK", kwlist, &fnum, &size)) {
1858 return NULL;
1861 req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
1862 if (!py_tevent_req_wait_exc(self, req)) {
1863 return NULL;
1865 status = cli_ftruncate_recv(req);
1866 TALLOC_FREE(req);
1868 if (!NT_STATUS_IS_OK(status)) {
1869 PyErr_SetNTSTATUS(status);
1870 return NULL;
1872 Py_RETURN_NONE;
1875 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
1876 PyObject *args,
1877 PyObject *kwds)
1879 unsigned fnum, flag;
1880 struct tevent_req *req;
1881 NTSTATUS status;
1883 static const char *kwlist[] = {
1884 "fnum", "flag", NULL };
1886 if (!ParseTupleAndKeywords(
1887 args, kwds, "II", kwlist, &fnum, &flag)) {
1888 return NULL;
1891 req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
1892 flag);
1893 if (!py_tevent_req_wait_exc(self, req)) {
1894 return NULL;
1896 status = cli_nt_delete_on_close_recv(req);
1897 TALLOC_FREE(req);
1899 if (!NT_STATUS_IS_OK(status)) {
1900 PyErr_SetNTSTATUS(status);
1901 return NULL;
1903 Py_RETURN_NONE;
1906 struct py_cli_notify_state {
1907 PyObject_HEAD
1908 struct py_cli_state *py_cli_state;
1909 struct tevent_req *req;
1912 static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
1914 TALLOC_FREE(self->req);
1915 Py_CLEAR(self->py_cli_state);
1916 Py_TYPE(self)->tp_free(self);
1919 static PyTypeObject py_cli_notify_state_type;
1921 static PyObject *py_cli_notify(struct py_cli_state *self,
1922 PyObject *args,
1923 PyObject *kwds)
1925 static const char *kwlist[] = {
1926 "fnum",
1927 "buffer_size",
1928 "completion_filter",
1929 "recursive",
1930 NULL
1932 unsigned fnum = 0;
1933 unsigned buffer_size = 0;
1934 unsigned completion_filter = 0;
1935 PyObject *py_recursive = Py_False;
1936 bool recursive = false;
1937 struct tevent_req *req = NULL;
1938 struct tevent_queue *send_queue = NULL;
1939 struct tevent_req *flush_req = NULL;
1940 bool ok;
1941 struct py_cli_notify_state *py_notify_state = NULL;
1942 struct timeval endtime;
1944 ok = ParseTupleAndKeywords(args,
1945 kwds,
1946 "IIIO",
1947 kwlist,
1948 &fnum,
1949 &buffer_size,
1950 &completion_filter,
1951 &py_recursive);
1952 if (!ok) {
1953 return NULL;
1956 recursive = PyObject_IsTrue(py_recursive);
1958 req = cli_notify_send(NULL,
1959 self->ev,
1960 self->cli,
1961 fnum,
1962 buffer_size,
1963 completion_filter,
1964 recursive);
1965 if (req == NULL) {
1966 PyErr_NoMemory();
1967 return NULL;
1971 * Just wait for the request being submitted to
1972 * the kernel/socket/wire.
1974 send_queue = smbXcli_conn_send_queue(self->cli->conn);
1975 flush_req = tevent_queue_wait_send(req,
1976 self->ev,
1977 send_queue);
1978 endtime = timeval_current_ofs_msec(self->cli->timeout);
1979 ok = tevent_req_set_endtime(flush_req,
1980 self->ev,
1981 endtime);
1982 if (!ok) {
1983 TALLOC_FREE(req);
1984 PyErr_NoMemory();
1985 return NULL;
1987 ok = py_tevent_req_wait_exc(self, flush_req);
1988 if (!ok) {
1989 TALLOC_FREE(req);
1990 return NULL;
1992 TALLOC_FREE(flush_req);
1994 py_notify_state = (struct py_cli_notify_state *)
1995 py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
1996 if (py_notify_state == NULL) {
1997 TALLOC_FREE(req);
1998 PyErr_NoMemory();
1999 return NULL;
2001 Py_INCREF(self);
2002 py_notify_state->py_cli_state = self;
2003 py_notify_state->req = req;
2005 return (PyObject *)py_notify_state;
2008 static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
2009 PyObject *args,
2010 PyObject *kwds)
2012 struct py_cli_state *py_cli_state = self->py_cli_state;
2013 struct tevent_req *req = self->req;
2014 uint32_t i;
2015 uint32_t num_changes = 0;
2016 struct notify_change *changes = NULL;
2017 PyObject *result = NULL;
2018 NTSTATUS status;
2019 bool ok;
2020 static const char *kwlist[] = {
2021 "wait",
2022 NULL
2024 PyObject *py_wait = Py_False;
2025 bool wait = false;
2026 bool pending;
2028 ok = ParseTupleAndKeywords(args,
2029 kwds,
2030 "O",
2031 kwlist,
2032 &py_wait);
2033 if (!ok) {
2034 return NULL;
2037 wait = PyObject_IsTrue(py_wait);
2039 if (req == NULL) {
2040 PyErr_SetString(PyExc_RuntimeError,
2041 "TODO req == NULL "
2042 "- missing change notify request?");
2043 return NULL;
2046 pending = tevent_req_is_in_progress(req);
2047 if (pending && !wait) {
2048 Py_RETURN_NONE;
2051 if (pending) {
2052 struct timeval endtime;
2054 endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
2055 ok = tevent_req_set_endtime(req,
2056 py_cli_state->ev,
2057 endtime);
2058 if (!ok) {
2059 TALLOC_FREE(req);
2060 PyErr_NoMemory();
2061 return NULL;
2065 ok = py_tevent_req_wait_exc(py_cli_state, req);
2066 self->req = NULL;
2067 Py_CLEAR(self->py_cli_state);
2068 if (!ok) {
2069 return NULL;
2072 status = cli_notify_recv(req, req, &num_changes, &changes);
2073 if (!NT_STATUS_IS_OK(status)) {
2074 TALLOC_FREE(req);
2075 PyErr_SetNTSTATUS(status);
2076 return NULL;
2079 result = Py_BuildValue("[]");
2080 if (result == NULL) {
2081 TALLOC_FREE(req);
2082 return NULL;
2085 for (i = 0; i < num_changes; i++) {
2086 PyObject *change = NULL;
2087 int ret;
2089 change = Py_BuildValue("{s:s,s:I}",
2090 "name", changes[i].name,
2091 "action", changes[i].action);
2092 if (change == NULL) {
2093 Py_XDECREF(result);
2094 TALLOC_FREE(req);
2095 return NULL;
2098 ret = PyList_Append(result, change);
2099 Py_DECREF(change);
2100 if (ret == -1) {
2101 Py_XDECREF(result);
2102 TALLOC_FREE(req);
2103 return NULL;
2107 TALLOC_FREE(req);
2108 return result;
2111 static PyMethodDef py_cli_notify_state_methods[] = {
2113 .ml_name = "get_changes",
2114 .ml_meth = (PyCFunction)py_cli_notify_get_changes,
2115 .ml_flags = METH_VARARGS|METH_KEYWORDS,
2116 .ml_doc = "Wait for change notifications: \n"
2117 "N.get_changes(wait=BOOLEAN) -> "
2118 "change notifications as a dictionary\n"
2119 "\t\tList contents of a directory. The keys are, \n"
2120 "\t\t\tname: name of changed object\n"
2121 "\t\t\taction: type of the change\n"
2122 "None is returned if there's no response yet and "
2123 "wait=False is passed"
2126 .ml_name = NULL
2130 static PyTypeObject py_cli_notify_state_type = {
2131 PyVarObject_HEAD_INIT(NULL, 0)
2132 .tp_name = "libsmb_samba_cwrapper.Notify",
2133 .tp_basicsize = sizeof(struct py_cli_notify_state),
2134 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2135 .tp_doc = "notify request",
2136 .tp_dealloc = (destructor)py_cli_notify_state_dealloc,
2137 .tp_methods = py_cli_notify_state_methods,
2141 * Helper to add posix directory listing entries to an overall Python list
2143 static NTSTATUS list_posix_helper(struct file_info *finfo,
2144 const char *mask, void *state)
2146 PyObject *result = (PyObject *)state;
2147 PyObject *file = NULL;
2148 struct dom_sid_buf owner_buf, group_buf;
2149 int ret;
2152 * Build a dictionary representing the file info.
2154 file = Py_BuildValue("{s:s,s:I,"
2155 "s:K,s:K,"
2156 "s:l,s:l,s:l,s:l,"
2157 "s:i,s:K,s:i,s:i,s:I,"
2158 "s:s,s:s,s:k}",
2159 "name",
2160 finfo->name,
2161 "attrib",
2162 finfo->attr,
2163 "size",
2164 finfo->size,
2165 "allocation_size",
2166 finfo->allocated_size,
2167 "btime",
2168 convert_timespec_to_time_t(finfo->btime_ts),
2169 "atime",
2170 convert_timespec_to_time_t(finfo->atime_ts),
2171 "mtime",
2172 convert_timespec_to_time_t(finfo->mtime_ts),
2173 "ctime",
2174 convert_timespec_to_time_t(finfo->ctime_ts),
2175 "perms",
2176 finfo->st_ex_mode,
2177 "ino",
2178 finfo->ino,
2179 "dev",
2180 finfo->st_ex_dev,
2181 "nlink",
2182 finfo->st_ex_nlink,
2183 "reparse_tag",
2184 finfo->reparse_tag,
2185 "owner_sid",
2186 dom_sid_str_buf(&finfo->owner_sid, &owner_buf),
2187 "group_sid",
2188 dom_sid_str_buf(&finfo->group_sid, &group_buf),
2189 "reparse_tag",
2190 (unsigned long)finfo->reparse_tag);
2191 if (file == NULL) {
2192 return NT_STATUS_NO_MEMORY;
2195 ret = PyList_Append(result, file);
2196 Py_CLEAR(file);
2197 if (ret == -1) {
2198 return NT_STATUS_INTERNAL_ERROR;
2201 return NT_STATUS_OK;
2205 * Helper to add directory listing entries to an overall Python list
2207 static NTSTATUS list_helper(struct file_info *finfo,
2208 const char *mask, void *state)
2210 PyObject *result = (PyObject *)state;
2211 PyObject *file = NULL;
2212 PyObject *size = NULL;
2213 int ret;
2215 /* suppress '.' and '..' in the results we return */
2216 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2217 return NT_STATUS_OK;
2219 size = PyLong_FromUnsignedLongLong(finfo->size);
2221 * Build a dictionary representing the file info.
2222 * Note: Windows does not always return short_name (so it may be None)
2224 file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l,s:k}",
2225 "name",
2226 finfo->name,
2227 "attrib",
2228 (int)finfo->attr,
2229 "short_name",
2230 finfo->short_name,
2231 "size",
2232 size,
2233 "mtime",
2234 convert_timespec_to_time_t(finfo->mtime_ts),
2235 "reparse_tag",
2236 (unsigned long)finfo->reparse_tag);
2238 Py_CLEAR(size);
2240 if (file == NULL) {
2241 return NT_STATUS_NO_MEMORY;
2244 if (finfo->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
2245 unsigned long tag = finfo->reparse_tag;
2247 ret = PyDict_SetItemString(
2248 file,
2249 "reparse_tag",
2250 PyLong_FromUnsignedLong(tag));
2251 if (ret == -1) {
2252 return NT_STATUS_INTERNAL_ERROR;
2256 ret = PyList_Append(result, file);
2257 Py_CLEAR(file);
2258 if (ret == -1) {
2259 return NT_STATUS_INTERNAL_ERROR;
2262 return NT_STATUS_OK;
2265 struct do_listing_state {
2266 const char *mask;
2267 NTSTATUS (*callback_fn)(
2268 struct file_info *finfo,
2269 const char *mask,
2270 void *private_data);
2271 void *private_data;
2272 NTSTATUS status;
2275 static void do_listing_cb(struct tevent_req *subreq)
2277 struct do_listing_state *state = tevent_req_callback_data_void(subreq);
2278 struct file_info *finfo = NULL;
2280 state->status = cli_list_recv(subreq, NULL, &finfo);
2281 if (!NT_STATUS_IS_OK(state->status)) {
2282 return;
2284 state->callback_fn(finfo, state->mask, state->private_data);
2285 TALLOC_FREE(finfo);
2288 static NTSTATUS do_listing(struct py_cli_state *self,
2289 const char *base_dir, const char *user_mask,
2290 uint16_t attribute,
2291 unsigned int info_level,
2292 NTSTATUS (*callback_fn)(struct file_info *,
2293 const char *, void *),
2294 void *priv)
2296 char *mask = NULL;
2297 struct do_listing_state state = {
2298 .mask = mask,
2299 .callback_fn = callback_fn,
2300 .private_data = priv,
2302 struct tevent_req *req = NULL;
2303 NTSTATUS status;
2305 if (user_mask == NULL) {
2306 mask = talloc_asprintf(NULL, "%s\\*", base_dir);
2307 } else {
2308 mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
2311 if (mask == NULL) {
2312 return NT_STATUS_NO_MEMORY;
2314 dos_format(mask);
2316 req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
2317 info_level);
2318 if (req == NULL) {
2319 status = NT_STATUS_NO_MEMORY;
2320 goto done;
2322 tevent_req_set_callback(req, do_listing_cb, &state);
2324 if (!py_tevent_req_wait_exc(self, req)) {
2325 return NT_STATUS_INTERNAL_ERROR;
2327 TALLOC_FREE(req);
2329 status = state.status;
2330 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
2331 status = NT_STATUS_OK;
2334 done:
2335 TALLOC_FREE(mask);
2336 return status;
2339 static PyObject *py_cli_list(struct py_cli_state *self,
2340 PyObject *args,
2341 PyObject *kwds)
2343 char *base_dir;
2344 char *user_mask = NULL;
2345 unsigned int attribute = LIST_ATTRIBUTE_MASK;
2346 unsigned int info_level = 0;
2347 NTSTATUS status;
2348 enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2349 PyObject *result = NULL;
2350 const char *kwlist[] = { "directory", "mask", "attribs",
2351 "info_level", NULL };
2352 NTSTATUS (*callback_fn)(struct file_info *, const char *, void *) =
2353 list_helper;
2355 if (!ParseTupleAndKeywords(args, kwds, "z|sII:list", kwlist,
2356 &base_dir, &user_mask, &attribute,
2357 &info_level)) {
2358 return NULL;
2361 result = Py_BuildValue("[]");
2362 if (result == NULL) {
2363 return NULL;
2366 if (!info_level) {
2367 if (proto >= PROTOCOL_SMB2_02) {
2368 info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
2369 } else {
2370 info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
2374 if (info_level == SMB2_FIND_POSIX_INFORMATION) {
2375 callback_fn = list_posix_helper;
2377 status = do_listing(self, base_dir, user_mask, attribute,
2378 info_level, callback_fn, result);
2380 if (!NT_STATUS_IS_OK(status)) {
2381 Py_XDECREF(result);
2382 PyErr_SetNTSTATUS(status);
2383 return NULL;
2386 return result;
2389 static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
2391 NTSTATUS status;
2392 const char *filename = NULL;
2393 struct tevent_req *req = NULL;
2394 const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2396 if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
2397 return NULL;
2400 req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
2401 if (!py_tevent_req_wait_exc(self, req)) {
2402 return NULL;
2404 status = cli_unlink_recv(req);
2405 TALLOC_FREE(req);
2406 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2408 Py_RETURN_NONE;
2411 static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
2413 NTSTATUS status;
2414 struct tevent_req *req = NULL;
2415 const char *dirname = NULL;
2417 if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
2418 return NULL;
2421 req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
2422 if (!py_tevent_req_wait_exc(self, req)) {
2423 return NULL;
2425 status = cli_rmdir_recv(req);
2426 TALLOC_FREE(req);
2427 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2429 Py_RETURN_NONE;
2433 * Create a directory
2435 static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
2437 NTSTATUS status;
2438 const char *dirname = NULL;
2439 struct tevent_req *req = NULL;
2441 if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
2442 return NULL;
2445 req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
2446 if (!py_tevent_req_wait_exc(self, req)) {
2447 return NULL;
2449 status = cli_mkdir_recv(req);
2450 TALLOC_FREE(req);
2451 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2453 Py_RETURN_NONE;
2457 * Does a whoami call
2459 static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
2460 PyObject *Py_UNUSED(ignored))
2462 TALLOC_CTX *frame = talloc_stackframe();
2463 NTSTATUS status;
2464 struct tevent_req *req = NULL;
2465 uint64_t uid;
2466 uint64_t gid;
2467 uint32_t num_gids;
2468 uint64_t *gids = NULL;
2469 uint32_t num_sids;
2470 struct dom_sid *sids = NULL;
2471 bool guest;
2472 PyObject *py_gids = NULL;
2473 PyObject *py_sids = NULL;
2474 PyObject *py_guest = NULL;
2475 PyObject *py_ret = NULL;
2476 Py_ssize_t i;
2478 req = cli_posix_whoami_send(frame, self->ev, self->cli);
2479 if (!py_tevent_req_wait_exc(self, req)) {
2480 goto fail;
2482 status = cli_posix_whoami_recv(req,
2483 frame,
2484 &uid,
2485 &gid,
2486 &num_gids,
2487 &gids,
2488 &num_sids,
2489 &sids,
2490 &guest);
2491 if (!NT_STATUS_IS_OK(status)) {
2492 PyErr_SetNTSTATUS(status);
2493 goto fail;
2495 if (num_gids > PY_SSIZE_T_MAX) {
2496 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
2497 goto fail;
2499 if (num_sids > PY_SSIZE_T_MAX) {
2500 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
2501 goto fail;
2504 py_gids = PyList_New(num_gids);
2505 if (!py_gids) {
2506 goto fail;
2508 for (i = 0; i < num_gids; ++i) {
2509 int ret;
2510 PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
2511 if (!py_item) {
2512 goto fail2;
2515 ret = PyList_SetItem(py_gids, i, py_item);
2516 if (ret) {
2517 goto fail2;
2520 py_sids = PyList_New(num_sids);
2521 if (!py_sids) {
2522 goto fail2;
2524 for (i = 0; i < num_sids; ++i) {
2525 int ret;
2526 struct dom_sid *sid;
2527 PyObject *py_item;
2529 sid = dom_sid_dup(frame, &sids[i]);
2530 if (!sid) {
2531 PyErr_NoMemory();
2532 goto fail3;
2535 py_item = pytalloc_steal(dom_sid_Type, sid);
2536 if (!py_item) {
2537 PyErr_NoMemory();
2538 goto fail3;
2541 ret = PyList_SetItem(py_sids, i, py_item);
2542 if (ret) {
2543 goto fail3;
2547 py_guest = guest ? Py_True : Py_False;
2549 py_ret = Py_BuildValue("KKNNO",
2550 uid,
2551 gid,
2552 py_gids,
2553 py_sids,
2554 py_guest);
2555 if (!py_ret) {
2556 goto fail3;
2559 TALLOC_FREE(frame);
2560 return py_ret;
2562 fail3:
2563 Py_CLEAR(py_sids);
2565 fail2:
2566 Py_CLEAR(py_gids);
2568 fail:
2569 TALLOC_FREE(frame);
2570 return NULL;
2574 * Checks existence of a directory
2576 static bool check_dir_path(struct py_cli_state *self, const char *path)
2578 NTSTATUS status;
2579 struct tevent_req *req = NULL;
2581 req = cli_chkpath_send(NULL, self->ev, self->cli, path);
2582 if (!py_tevent_req_wait_exc(self, req)) {
2583 return false;
2585 status = cli_chkpath_recv(req);
2586 TALLOC_FREE(req);
2588 return NT_STATUS_IS_OK(status);
2591 static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
2593 const char *path = NULL;
2594 bool dir_exists;
2596 if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
2597 return NULL;
2600 dir_exists = check_dir_path(self, path);
2601 return PyBool_FromLong(dir_exists);
2604 static PyObject *py_smb_have_posix(struct py_cli_state *self,
2605 PyObject *Py_UNUSED(ignored))
2607 bool posix = smbXcli_conn_have_posix(self->cli->conn);
2609 if (posix) {
2610 Py_RETURN_TRUE;
2612 Py_RETURN_FALSE;
2615 static PyObject *py_smb_protocol(struct py_cli_state *self,
2616 PyObject *Py_UNUSED(ignored))
2618 enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2619 PyObject *result = PyLong_FromLong(proto);
2620 return result;
2623 static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
2625 int fnum;
2626 unsigned sinfo;
2627 struct tevent_req *req = NULL;
2628 struct security_descriptor *sd = NULL;
2629 NTSTATUS status;
2631 if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
2632 return NULL;
2635 req = cli_query_security_descriptor_send(
2636 NULL, self->ev, self->cli, fnum, sinfo);
2637 if (!py_tevent_req_wait_exc(self, req)) {
2638 return NULL;
2640 status = cli_query_security_descriptor_recv(req, NULL, &sd);
2641 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2643 return py_return_ndr_struct(
2644 "samba.dcerpc.security", "descriptor", sd, sd);
2647 static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
2649 PyObject *py_sd = NULL;
2650 struct tevent_req *req = NULL;
2651 struct security_descriptor *sd = NULL;
2652 uint16_t fnum;
2653 unsigned int sinfo;
2654 NTSTATUS status;
2656 if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
2657 return NULL;
2660 sd = pytalloc_get_type(py_sd, struct security_descriptor);
2661 if (!sd) {
2662 PyErr_Format(PyExc_TypeError,
2663 "Expected dcerpc.security.descriptor as argument, got %s",
2664 pytalloc_get_name(py_sd));
2665 return NULL;
2668 req = cli_set_security_descriptor_send(
2669 NULL, self->ev, self->cli, fnum, sinfo, sd);
2670 if (!py_tevent_req_wait_exc(self, req)) {
2671 return NULL;
2674 status = cli_set_security_descriptor_recv(req);
2675 PyErr_NTSTATUS_NOT_OK_RAISE(status);
2677 Py_RETURN_NONE;
2680 static PyObject *py_smb_smb1_posix(
2681 struct py_cli_state *self, PyObject *Py_UNUSED(ignored))
2683 NTSTATUS status;
2684 struct tevent_req *req = NULL;
2685 uint16_t major, minor;
2686 uint32_t caplow, caphigh;
2687 PyObject *result = NULL;
2689 req = cli_unix_extensions_version_send(NULL, self->ev, self->cli);
2690 if (!py_tevent_req_wait_exc(self, req)) {
2691 return NULL;
2693 status = cli_unix_extensions_version_recv(
2694 req, &major, &minor, &caplow, &caphigh);
2695 TALLOC_FREE(req);
2696 if (!NT_STATUS_IS_OK(status)) {
2697 PyErr_SetNTSTATUS(status);
2698 return NULL;
2701 req = cli_set_unix_extensions_capabilities_send(
2702 NULL, self->ev, self->cli, major, minor, caplow, caphigh);
2703 if (!py_tevent_req_wait_exc(self, req)) {
2704 return NULL;
2706 status = cli_set_unix_extensions_capabilities_recv(req);
2707 TALLOC_FREE(req);
2708 if (!NT_STATUS_IS_OK(status)) {
2709 PyErr_SetNTSTATUS(status);
2710 return NULL;
2713 result = Py_BuildValue(
2714 "[IIII]",
2715 (unsigned)minor,
2716 (unsigned)major,
2717 (unsigned)caplow,
2718 (unsigned)caphigh);
2719 return result;
2722 static PyObject *py_smb_smb1_readlink(
2723 struct py_cli_state *self, PyObject *args)
2725 NTSTATUS status;
2726 const char *filename = NULL;
2727 struct tevent_req *req = NULL;
2728 char *target = NULL;
2729 PyObject *result = NULL;
2731 if (!PyArg_ParseTuple(args, "s:smb1_readlink", &filename)) {
2732 return NULL;
2735 req = cli_posix_readlink_send(NULL, self->ev, self->cli, filename);
2736 if (!py_tevent_req_wait_exc(self, req)) {
2737 return NULL;
2739 status = cli_posix_readlink_recv(req, NULL, &target);
2740 TALLOC_FREE(req);
2741 if (!NT_STATUS_IS_OK(status)) {
2742 PyErr_SetNTSTATUS(status);
2743 return NULL;
2746 result = PyBytes_FromString(target);
2747 TALLOC_FREE(target);
2748 return result;
2751 static PyObject *py_smb_smb1_symlink(
2752 struct py_cli_state *self, PyObject *args)
2754 NTSTATUS status;
2755 const char *target = NULL, *newname = NULL;
2756 struct tevent_req *req = NULL;
2758 if (!PyArg_ParseTuple(args, "ss:smb1_symlink", &target, &newname)) {
2759 return NULL;
2762 req = cli_posix_symlink_send(
2763 NULL, self->ev, self->cli, target, newname);
2764 if (!py_tevent_req_wait_exc(self, req)) {
2765 return NULL;
2767 status = cli_posix_symlink_recv(req);
2768 TALLOC_FREE(req);
2769 if (!NT_STATUS_IS_OK(status)) {
2770 PyErr_SetNTSTATUS(status);
2771 return NULL;
2774 Py_RETURN_NONE;
2777 static PyObject *py_smb_smb1_stat(
2778 struct py_cli_state *self, PyObject *args)
2780 NTSTATUS status;
2781 const char *fname = NULL;
2782 struct tevent_req *req = NULL;
2783 struct stat_ex sbuf = { .st_ex_nlink = 0, };
2785 if (!PyArg_ParseTuple(args, "s:smb1_stat", &fname)) {
2786 return NULL;
2789 req = cli_posix_stat_send(NULL, self->ev, self->cli, fname);
2790 if (!py_tevent_req_wait_exc(self, req)) {
2791 return NULL;
2793 status = cli_posix_stat_recv(req, &sbuf);
2794 TALLOC_FREE(req);
2795 if (!NT_STATUS_IS_OK(status)) {
2796 PyErr_SetNTSTATUS(status);
2797 return NULL;
2800 return Py_BuildValue(
2801 "{sLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsLsL}",
2802 "dev",
2803 (unsigned long long)sbuf.st_ex_dev,
2804 "ino",
2805 (unsigned long long)sbuf.st_ex_ino,
2806 "mode",
2807 (unsigned long long)sbuf.st_ex_mode,
2808 "nlink",
2809 (unsigned long long)sbuf.st_ex_nlink,
2810 "uid",
2811 (unsigned long long)sbuf.st_ex_uid,
2812 "gid",
2813 (unsigned long long)sbuf.st_ex_gid,
2814 "rdev",
2815 (unsigned long long)sbuf.st_ex_size,
2816 "atime_sec",
2817 (unsigned long long)sbuf.st_ex_atime.tv_sec,
2818 "atime_nsec",
2819 (unsigned long long)sbuf.st_ex_atime.tv_nsec,
2820 "mtime_sec",
2821 (unsigned long long)sbuf.st_ex_mtime.tv_sec,
2822 "mtime_nsec",
2823 (unsigned long long)sbuf.st_ex_mtime.tv_nsec,
2824 "ctime_sec",
2825 (unsigned long long)sbuf.st_ex_ctime.tv_sec,
2826 "ctime_nsec",
2827 (unsigned long long)sbuf.st_ex_ctime.tv_nsec,
2828 "btime_sec",
2829 (unsigned long long)sbuf.st_ex_btime.tv_sec,
2830 "btime_nsec",
2831 (unsigned long long)sbuf.st_ex_btime.tv_nsec,
2832 "cached_dos_attributes",
2833 (unsigned long long)sbuf.cached_dos_attributes,
2834 "blksize",
2835 (unsigned long long)sbuf.st_ex_blksize,
2836 "blocks",
2837 (unsigned long long)sbuf.st_ex_blocks,
2838 "flags",
2839 (unsigned long long)sbuf.st_ex_flags,
2840 "iflags",
2841 (unsigned long long)sbuf.st_ex_iflags);
2844 static PyObject *py_cli_mknod(
2845 struct py_cli_state *self, PyObject *args, PyObject *kwds)
2847 char *fname = NULL;
2848 int mode = 0, major = 0, minor = 0, dev = 0;
2849 struct tevent_req *req = NULL;
2850 static const char *kwlist[] = {
2851 "fname", "mode", "major", "minor", NULL,
2853 NTSTATUS status;
2854 bool ok;
2856 ok = ParseTupleAndKeywords(
2857 args,
2858 kwds,
2859 "sI|II:mknod",
2860 kwlist,
2861 &fname,
2862 &mode,
2863 &major,
2864 &minor);
2865 if (!ok) {
2866 return NULL;
2869 #if defined(HAVE_MAKEDEV)
2870 dev = makedev(major, minor);
2871 #endif
2873 req = cli_mknod_send(
2874 NULL, self->ev, self->cli, fname, mode, dev);
2875 if (!py_tevent_req_wait_exc(self, req)) {
2876 return NULL;
2878 status = cli_mknod_recv(req);
2879 TALLOC_FREE(req);
2880 if (!NT_STATUS_IS_OK(status)) {
2881 PyErr_SetNTSTATUS(status);
2882 return NULL;
2884 Py_RETURN_NONE;
2887 static PyObject *py_cli_fsctl(
2888 struct py_cli_state *self, PyObject *args, PyObject *kwds)
2890 int fnum, ctl_code;
2891 int max_out = 0;
2892 char *buf = NULL;
2893 Py_ssize_t buflen;
2894 DATA_BLOB in = { .data = NULL, };
2895 DATA_BLOB out = { .data = NULL, };
2896 struct tevent_req *req = NULL;
2897 PyObject *result = NULL;
2898 static const char *kwlist[] = {
2899 "fnum", "ctl_code", "in", "max_out", NULL,
2901 NTSTATUS status;
2902 bool ok;
2904 ok = ParseTupleAndKeywords(
2905 args,
2906 kwds,
2907 "ii" PYARG_BYTES_LEN "i",
2908 kwlist,
2909 &fnum,
2910 &ctl_code,
2911 &buf,
2912 &buflen,
2913 &max_out);
2914 if (!ok) {
2915 return NULL;
2918 in = (DATA_BLOB) { .data = (uint8_t *)buf, .length = buflen, };
2920 req = cli_fsctl_send(
2921 NULL, self->ev, self->cli, fnum, ctl_code, &in, max_out);
2923 if (!py_tevent_req_wait_exc(self, req)) {
2924 return NULL;
2927 status = cli_fsctl_recv(req, NULL, &out);
2928 if (!NT_STATUS_IS_OK(status)) {
2929 PyErr_SetNTSTATUS(status);
2930 return NULL;
2933 result = PyBytes_FromStringAndSize((char *)out.data, out.length);
2934 data_blob_free(&out);
2935 return result;
2938 static int copy_chunk_cb(off_t n, void *priv)
2940 return 1;
2943 static PyObject *py_cli_copy_chunk(struct py_cli_state *self,
2944 PyObject *args,
2945 PyObject *kwds)
2947 TALLOC_CTX *frame = talloc_stackframe();
2948 struct tevent_req *req = NULL;
2949 PyObject *result = NULL;
2950 int fnum_src;
2951 int fnum_dst;
2952 unsigned long long size;
2953 unsigned long long src_offset;
2954 unsigned long long dst_offset;
2955 off_t written;
2956 static const char *kwlist[] = {
2957 "fnum_src",
2958 "fnum_dst",
2959 "size",
2960 "src_offset",
2961 "dst_offset",
2962 NULL,
2964 NTSTATUS status;
2965 bool ok;
2967 if (smbXcli_conn_protocol(self->cli->conn) < PROTOCOL_SMB2_02) {
2968 errno = EINVAL;
2969 PyErr_SetFromErrno(PyExc_RuntimeError);
2970 goto err;
2973 ok = ParseTupleAndKeywords(
2974 args,
2975 kwds,
2976 "iiKKK",
2977 kwlist,
2978 &fnum_src,
2979 &fnum_dst,
2980 &size,
2981 &src_offset,
2982 &dst_offset);
2983 if (!ok) {
2984 goto err;
2987 req = cli_smb2_splice_send(frame,
2988 self->ev,
2989 self->cli,
2990 fnum_src,
2991 fnum_dst,
2992 size,
2993 src_offset,
2994 dst_offset,
2995 copy_chunk_cb,
2996 NULL);
2997 if (!py_tevent_req_wait_exc(self, req)) {
2998 goto err;
3001 status = cli_smb2_splice_recv(req, &written);
3002 if (!NT_STATUS_IS_OK(status)) {
3003 PyErr_SetNTSTATUS(status);
3004 goto err;
3007 result = Py_BuildValue("K", written);
3009 err:
3010 TALLOC_FREE(frame);
3011 return result;
3014 static PyMethodDef py_cli_state_methods[] = {
3015 { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
3016 "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
3017 { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
3018 "Ping the server connection" },
3019 { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
3020 METH_VARARGS|METH_KEYWORDS,
3021 "Open a file" },
3022 { "get_posix_fs_info",
3023 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_get_posix_fs_info),
3024 METH_NOARGS,
3025 "Get posix filesystem attribute information" },
3026 { "create_ex",
3027 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create_ex),
3028 METH_VARARGS|METH_KEYWORDS,
3029 "Open a file, SMB2 version returning create contexts" },
3030 { "close", (PyCFunction)py_cli_close, METH_VARARGS,
3031 "Close a file handle" },
3032 { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
3033 METH_VARARGS|METH_KEYWORDS,
3034 "Write to a file handle" },
3035 { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
3036 METH_VARARGS|METH_KEYWORDS,
3037 "Read from a file handle" },
3038 { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
3039 py_cli_ftruncate),
3040 METH_VARARGS|METH_KEYWORDS,
3041 "Truncate a file" },
3042 { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
3043 py_cli_delete_on_close),
3044 METH_VARARGS|METH_KEYWORDS,
3045 "Set/Reset the delete on close flag" },
3046 { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
3047 METH_VARARGS|METH_KEYWORDS,
3048 "Wait for change notifications: \n"
3049 "notify(fnum, buffer_size, completion_filter...) -> "
3050 "libsmb_samba_internal.Notify request handle\n" },
3051 { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
3052 METH_VARARGS|METH_KEYWORDS,
3053 "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
3054 "directory contents as a dictionary\n"
3055 "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
3056 "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
3057 "\t\tList contents of a directory. The keys are, \n"
3058 "\t\t\tname: Long name of the directory item\n"
3059 "\t\t\tshort_name: Short name of the directory item\n"
3060 "\t\t\tsize: File size in bytes\n"
3061 "\t\t\tattrib: Attributes\n"
3062 "\t\t\tmtime: Modification time\n" },
3063 { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
3064 METH_VARARGS, "Wait for an oplock break" },
3065 { "unlink", (PyCFunction)py_smb_unlink,
3066 METH_VARARGS,
3067 "unlink(path) -> None\n\n \t\tDelete a file." },
3068 { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
3069 "mkdir(path) -> None\n\n \t\tCreate a directory." },
3070 { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
3071 "posix_whoami() -> (uid, gid, gids, sids, guest)" },
3072 { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
3073 "rmdir(path) -> None\n\n \t\tDelete a directory." },
3074 { "rename",
3075 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
3076 METH_VARARGS|METH_KEYWORDS,
3077 "rename(src,dst) -> None\n\n \t\tRename a file." },
3078 { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
3079 "chkpath(dir_path) -> True or False\n\n"
3080 "\t\tReturn true if directory exists, false otherwise." },
3081 { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
3082 "savefile(path, bytes) -> None\n\n"
3083 "\t\tWrite bytes to file." },
3084 { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
3085 "loadfile(path) -> file contents as a bytes object"
3086 "\n\n\t\tRead contents of a file." },
3087 { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
3088 "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
3089 "\t\tGet security descriptor for opened file." },
3090 { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
3091 "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
3092 "\t\tSet security descriptor for opened file." },
3093 { "protocol",
3094 (PyCFunction)py_smb_protocol,
3095 METH_NOARGS,
3096 "protocol() -> Number"
3098 { "have_posix",
3099 (PyCFunction)py_smb_have_posix,
3100 METH_NOARGS,
3101 "have_posix() -> True/False\n\n"
3102 "\t\tReturn if the server has posix extensions"
3104 { "smb1_posix",
3105 (PyCFunction)py_smb_smb1_posix,
3106 METH_NOARGS,
3107 "Negotiate SMB1 posix extensions",
3109 { "smb1_readlink",
3110 (PyCFunction)py_smb_smb1_readlink,
3111 METH_VARARGS,
3112 "smb1_readlink(path) -> link target",
3114 { "smb1_symlink",
3115 (PyCFunction)py_smb_smb1_symlink,
3116 METH_VARARGS,
3117 "smb1_symlink(target, newname) -> None",
3119 { "smb1_stat",
3120 (PyCFunction)py_smb_smb1_stat,
3121 METH_VARARGS,
3122 "smb1_stat(path) -> stat info",
3124 { "fsctl",
3125 (PyCFunction)py_cli_fsctl,
3126 METH_VARARGS|METH_KEYWORDS,
3127 "fsctl(fnum, ctl_code, in_bytes, max_out) -> out_bytes",
3130 "qfileinfo",
3131 (PyCFunction)py_cli_qfileinfo,
3132 METH_VARARGS | METH_KEYWORDS,
3133 "qfileinfo(fnum, level) -> blob",
3135 { "mknod",
3136 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_mknod),
3137 METH_VARARGS|METH_KEYWORDS,
3138 "mknod(path, mode | major, minor)",
3140 { "copy_chunk",
3141 PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_copy_chunk),
3142 METH_VARARGS|METH_KEYWORDS,
3143 "copy_chunk(fnum_src, fnum_dst, size, src_offset, dst_offset) -> written",
3145 { NULL, NULL, 0, NULL }
3148 static PyTypeObject py_cli_state_type = {
3149 PyVarObject_HEAD_INIT(NULL, 0)
3150 .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
3151 .tp_basicsize = sizeof(struct py_cli_state),
3152 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
3153 .tp_doc = "libsmb cwrapper connection",
3154 .tp_new = py_cli_state_new,
3155 .tp_init = (initproc)py_cli_state_init,
3156 .tp_dealloc = (destructor)py_cli_state_dealloc,
3157 .tp_methods = py_cli_state_methods,
3160 static PyMethodDef py_libsmb_methods[] = {
3162 "unix_mode_to_wire",
3163 (PyCFunction)py_unix_mode_to_wire,
3164 METH_VARARGS,
3165 "Convert mode_t to posix extensions wire format",
3168 "wire_mode_to_unix",
3169 (PyCFunction)py_wire_mode_to_unix,
3170 METH_VARARGS,
3171 "Convert posix wire format mode to mode_t",
3173 {0},
3176 void initlibsmb_samba_cwrapper(void);
3178 static struct PyModuleDef moduledef = {
3179 PyModuleDef_HEAD_INIT,
3180 .m_name = "libsmb_samba_cwrapper",
3181 .m_doc = "libsmb wrapper",
3182 .m_size = -1,
3183 .m_methods = py_libsmb_methods,
3186 MODULE_INIT_FUNC(libsmb_samba_cwrapper)
3188 PyObject *m = NULL;
3189 PyObject *mod = NULL;
3191 talloc_stackframe();
3193 if (PyType_Ready(&py_cli_state_type) < 0) {
3194 return NULL;
3196 if (PyType_Ready(&py_cli_notify_state_type) < 0) {
3197 return NULL;
3200 m = PyModule_Create(&moduledef);
3201 if (m == NULL) {
3202 return m;
3205 /* Import dom_sid type from dcerpc.security */
3206 mod = PyImport_ImportModule("samba.dcerpc.security");
3207 if (mod == NULL) {
3208 return NULL;
3211 dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
3212 if (dom_sid_Type == NULL) {
3213 Py_DECREF(mod);
3214 return NULL;
3217 Py_INCREF(&py_cli_state_type);
3218 PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
3220 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
3222 ADD_FLAGS(PROTOCOL_NONE);
3223 ADD_FLAGS(PROTOCOL_CORE);
3224 ADD_FLAGS(PROTOCOL_COREPLUS);
3225 ADD_FLAGS(PROTOCOL_LANMAN1);
3226 ADD_FLAGS(PROTOCOL_LANMAN2);
3227 ADD_FLAGS(PROTOCOL_NT1);
3228 ADD_FLAGS(PROTOCOL_SMB2_02);
3229 ADD_FLAGS(PROTOCOL_SMB2_10);
3230 ADD_FLAGS(PROTOCOL_SMB3_00);
3231 ADD_FLAGS(PROTOCOL_SMB3_02);
3232 ADD_FLAGS(PROTOCOL_SMB3_11);
3234 ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
3235 ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
3236 ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
3237 ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
3238 ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
3239 ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
3240 ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
3241 ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
3242 ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
3243 ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
3244 ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
3245 ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
3246 ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
3247 ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
3248 ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
3249 ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
3251 ADD_FLAGS(FILE_DIRECTORY_FILE);
3252 ADD_FLAGS(FILE_WRITE_THROUGH);
3253 ADD_FLAGS(FILE_SEQUENTIAL_ONLY);
3254 ADD_FLAGS(FILE_NO_INTERMEDIATE_BUFFERING);
3255 ADD_FLAGS(FILE_SYNCHRONOUS_IO_ALERT);
3256 ADD_FLAGS(FILE_SYNCHRONOUS_IO_NONALERT);
3257 ADD_FLAGS(FILE_NON_DIRECTORY_FILE);
3258 ADD_FLAGS(FILE_CREATE_TREE_CONNECTION);
3259 ADD_FLAGS(FILE_COMPLETE_IF_OPLOCKED);
3260 ADD_FLAGS(FILE_NO_EA_KNOWLEDGE);
3261 ADD_FLAGS(FILE_EIGHT_DOT_THREE_ONLY);
3262 ADD_FLAGS(FILE_RANDOM_ACCESS);
3263 ADD_FLAGS(FILE_DELETE_ON_CLOSE);
3264 ADD_FLAGS(FILE_OPEN_BY_FILE_ID);
3265 ADD_FLAGS(FILE_OPEN_FOR_BACKUP_INTENT);
3266 ADD_FLAGS(FILE_NO_COMPRESSION);
3267 ADD_FLAGS(FILE_RESERVER_OPFILTER);
3268 ADD_FLAGS(FILE_OPEN_REPARSE_POINT);
3269 ADD_FLAGS(FILE_OPEN_NO_RECALL);
3270 ADD_FLAGS(FILE_OPEN_FOR_FREE_SPACE_QUERY);
3272 ADD_FLAGS(FILE_SHARE_READ);
3273 ADD_FLAGS(FILE_SHARE_WRITE);
3274 ADD_FLAGS(FILE_SHARE_DELETE);
3276 ADD_FLAGS(VFS_PWRITE_APPEND_OFFSET);
3278 /* change notify completion filter flags */
3279 ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
3280 ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
3281 ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
3282 ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
3283 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
3284 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
3285 ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
3286 ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
3287 ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
3288 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
3289 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
3290 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
3291 ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
3292 ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
3294 /* change notify action results */
3295 ADD_FLAGS(NOTIFY_ACTION_ADDED);
3296 ADD_FLAGS(NOTIFY_ACTION_REMOVED);
3297 ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
3298 ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
3299 ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
3300 ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
3301 ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
3302 ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
3304 /* CreateDisposition values */
3305 ADD_FLAGS(FILE_SUPERSEDE);
3306 ADD_FLAGS(FILE_OPEN);
3307 ADD_FLAGS(FILE_CREATE);
3308 ADD_FLAGS(FILE_OPEN_IF);
3309 ADD_FLAGS(FILE_OVERWRITE);
3310 ADD_FLAGS(FILE_OVERWRITE_IF);
3312 ADD_FLAGS(FSCTL_DFS_GET_REFERRALS);
3313 ADD_FLAGS(FSCTL_DFS_GET_REFERRALS_EX);
3314 ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_1);
3315 ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_2);
3316 ADD_FLAGS(FSCTL_REQUEST_BATCH_OPLOCK);
3317 ADD_FLAGS(FSCTL_OPLOCK_BREAK_ACKNOWLEDGE);
3318 ADD_FLAGS(FSCTL_OPBATCH_ACK_CLOSE_PENDING);
3319 ADD_FLAGS(FSCTL_OPLOCK_BREAK_NOTIFY);
3320 ADD_FLAGS(FSCTL_GET_COMPRESSION);
3321 ADD_FLAGS(FSCTL_FILESYS_GET_STATISTICS);
3322 ADD_FLAGS(FSCTL_GET_NTFS_VOLUME_DATA);
3323 ADD_FLAGS(FSCTL_IS_VOLUME_DIRTY);
3324 ADD_FLAGS(FSCTL_FIND_FILES_BY_SID);
3325 ADD_FLAGS(FSCTL_SET_OBJECT_ID);
3326 ADD_FLAGS(FSCTL_GET_OBJECT_ID);
3327 ADD_FLAGS(FSCTL_DELETE_OBJECT_ID);
3328 ADD_FLAGS(FSCTL_SET_REPARSE_POINT);
3329 ADD_FLAGS(FSCTL_GET_REPARSE_POINT);
3330 ADD_FLAGS(FSCTL_DELETE_REPARSE_POINT);
3331 ADD_FLAGS(FSCTL_SET_OBJECT_ID_EXTENDED);
3332 ADD_FLAGS(FSCTL_CREATE_OR_GET_OBJECT_ID);
3333 ADD_FLAGS(FSCTL_SET_SPARSE);
3334 ADD_FLAGS(FSCTL_SET_ZERO_DATA);
3335 ADD_FLAGS(FSCTL_SET_ZERO_ON_DEALLOCATION);
3336 ADD_FLAGS(FSCTL_READ_FILE_USN_DATA);
3337 ADD_FLAGS(FSCTL_WRITE_USN_CLOSE_RECORD);
3338 ADD_FLAGS(FSCTL_QUERY_ALLOCATED_RANGES);
3339 ADD_FLAGS(FSCTL_QUERY_ON_DISK_VOLUME_INFO);
3340 ADD_FLAGS(FSCTL_QUERY_SPARING_INFO);
3341 ADD_FLAGS(FSCTL_FILE_LEVEL_TRIM);
3342 ADD_FLAGS(FSCTL_OFFLOAD_READ);
3343 ADD_FLAGS(FSCTL_OFFLOAD_WRITE);
3344 ADD_FLAGS(FSCTL_SET_INTEGRITY_INFORMATION);
3345 ADD_FLAGS(FSCTL_DUP_EXTENTS_TO_FILE);
3346 ADD_FLAGS(FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX);
3347 ADD_FLAGS(FSCTL_STORAGE_QOS_CONTROL);
3348 ADD_FLAGS(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST);
3349 ADD_FLAGS(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT);
3350 ADD_FLAGS(FSCTL_PIPE_PEEK);
3351 ADD_FLAGS(FSCTL_NAMED_PIPE_READ_WRITE);
3352 ADD_FLAGS(FSCTL_PIPE_TRANSCEIVE);
3353 ADD_FLAGS(FSCTL_PIPE_WAIT);
3354 ADD_FLAGS(FSCTL_GET_SHADOW_COPY_DATA);
3355 ADD_FLAGS(FSCTL_SRV_ENUM_SNAPS);
3356 ADD_FLAGS(FSCTL_SRV_REQUEST_RESUME_KEY);
3357 ADD_FLAGS(FSCTL_SRV_COPYCHUNK);
3358 ADD_FLAGS(FSCTL_SRV_COPYCHUNK_WRITE);
3359 ADD_FLAGS(FSCTL_SRV_READ_HASH);
3360 ADD_FLAGS(FSCTL_LMR_REQ_RESILIENCY);
3361 ADD_FLAGS(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION);
3362 ADD_FLAGS(FSCTL_QUERY_NETWORK_INTERFACE_INFO);
3364 ADD_FLAGS(SYMLINK_ERROR_TAG);
3365 ADD_FLAGS(SYMLINK_FLAG_RELATIVE);
3366 ADD_FLAGS(SYMLINK_ADMIN);
3367 ADD_FLAGS(SYMLINK_UNTRUSTED);
3368 ADD_FLAGS(SYMLINK_TRUST_UNKNOWN);
3369 ADD_FLAGS(SYMLINK_TRUST_MASK);
3371 ADD_FLAGS(IO_REPARSE_TAG_RESERVED_ZERO);
3372 ADD_FLAGS(IO_REPARSE_TAG_SYMLINK);
3373 ADD_FLAGS(IO_REPARSE_TAG_MOUNT_POINT);
3374 ADD_FLAGS(IO_REPARSE_TAG_HSM);
3375 ADD_FLAGS(IO_REPARSE_TAG_SIS);
3376 ADD_FLAGS(IO_REPARSE_TAG_DFS);
3377 ADD_FLAGS(IO_REPARSE_TAG_NFS);
3379 ADD_FLAGS(NFS_SPECFILE_LNK);
3380 ADD_FLAGS(NFS_SPECFILE_CHR);
3381 ADD_FLAGS(NFS_SPECFILE_BLK);
3382 ADD_FLAGS(NFS_SPECFILE_FIFO);
3383 ADD_FLAGS(NFS_SPECFILE_SOCK);
3385 ADD_FLAGS(FSCC_FILE_DIRECTORY_INFORMATION);
3386 ADD_FLAGS(FSCC_FILE_FULL_DIRECTORY_INFORMATION);
3387 ADD_FLAGS(FSCC_FILE_BOTH_DIRECTORY_INFORMATION);
3388 ADD_FLAGS(FSCC_FILE_BASIC_INFORMATION);
3389 ADD_FLAGS(FSCC_FILE_STANDARD_INFORMATION);
3390 ADD_FLAGS(FSCC_FILE_INTERNAL_INFORMATION);
3391 ADD_FLAGS(FSCC_FILE_EA_INFORMATION);
3392 ADD_FLAGS(FSCC_FILE_ACCESS_INFORMATION);
3393 ADD_FLAGS(FSCC_FILE_NAME_INFORMATION);
3394 ADD_FLAGS(FSCC_FILE_RENAME_INFORMATION);
3395 ADD_FLAGS(FSCC_FILE_LINK_INFORMATION);
3396 ADD_FLAGS(FSCC_FILE_NAMES_INFORMATION);
3397 ADD_FLAGS(FSCC_FILE_DISPOSITION_INFORMATION);
3398 ADD_FLAGS(FSCC_FILE_POSITION_INFORMATION);
3399 ADD_FLAGS(FSCC_FILE_FULL_EA_INFORMATION);
3400 ADD_FLAGS(FSCC_FILE_MODE_INFORMATION);
3401 ADD_FLAGS(FSCC_FILE_ALIGNMENT_INFORMATION);
3402 ADD_FLAGS(FSCC_FILE_ALL_INFORMATION);
3403 ADD_FLAGS(FSCC_FILE_ALLOCATION_INFORMATION);
3404 ADD_FLAGS(FSCC_FILE_END_OF_FILE_INFORMATION);
3405 ADD_FLAGS(FSCC_FILE_ALTERNATE_NAME_INFORMATION);
3406 ADD_FLAGS(FSCC_FILE_STREAM_INFORMATION);
3407 ADD_FLAGS(FSCC_FILE_PIPE_INFORMATION);
3408 ADD_FLAGS(FSCC_FILE_PIPE_LOCAL_INFORMATION);
3409 ADD_FLAGS(FSCC_FILE_PIPE_REMOTE_INFORMATION);
3410 ADD_FLAGS(FSCC_FILE_MAILSLOT_QUERY_INFORMATION);
3411 ADD_FLAGS(FSCC_FILE_MAILSLOT_SET_INFORMATION);
3412 ADD_FLAGS(FSCC_FILE_COMPRESSION_INFORMATION);
3413 ADD_FLAGS(FSCC_FILE_OBJECTID_INFORMATION);
3414 ADD_FLAGS(FSCC_FILE_COMPLETION_INFORMATION);
3415 ADD_FLAGS(FSCC_FILE_MOVE_CLUSTER_INFORMATION);
3416 ADD_FLAGS(FSCC_FILE_QUOTA_INFORMATION);
3417 ADD_FLAGS(FSCC_FILE_REPARSEPOINT_INFORMATION);
3418 ADD_FLAGS(FSCC_FILE_NETWORK_OPEN_INFORMATION);
3419 ADD_FLAGS(FSCC_FILE_ATTRIBUTE_TAG_INFORMATION);
3420 ADD_FLAGS(FSCC_FILE_TRACKING_INFORMATION);
3421 ADD_FLAGS(FSCC_FILE_ID_BOTH_DIRECTORY_INFORMATION);
3422 ADD_FLAGS(FSCC_FILE_ID_FULL_DIRECTORY_INFORMATION);
3423 ADD_FLAGS(FSCC_FILE_VALID_DATA_LENGTH_INFORMATION);
3424 ADD_FLAGS(FSCC_FILE_SHORT_NAME_INFORMATION);
3425 ADD_FLAGS(FSCC_FILE_SFIO_RESERVE_INFORMATION);
3426 ADD_FLAGS(FSCC_FILE_SFIO_VOLUME_INFORMATION);
3427 ADD_FLAGS(FSCC_FILE_HARD_LINK_INFORMATION);
3428 ADD_FLAGS(FSCC_FILE_NORMALIZED_NAME_INFORMATION);
3429 ADD_FLAGS(FSCC_FILE_ID_GLOBAL_TX_DIRECTORY_INFORMATION);
3430 ADD_FLAGS(FSCC_FILE_STANDARD_LINK_INFORMATION);
3431 ADD_FLAGS(FSCC_FILE_MAXIMUM_INFORMATION);
3432 ADD_FLAGS(FSCC_FILE_POSIX_INFORMATION);
3434 #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
3436 ADD_STRING(SMB2_CREATE_TAG_EXTA);
3437 ADD_STRING(SMB2_CREATE_TAG_MXAC);
3438 ADD_STRING(SMB2_CREATE_TAG_SECD);
3439 ADD_STRING(SMB2_CREATE_TAG_DHNQ);
3440 ADD_STRING(SMB2_CREATE_TAG_DHNC);
3441 ADD_STRING(SMB2_CREATE_TAG_ALSI);
3442 ADD_STRING(SMB2_CREATE_TAG_TWRP);
3443 ADD_STRING(SMB2_CREATE_TAG_QFID);
3444 ADD_STRING(SMB2_CREATE_TAG_RQLS);
3445 ADD_STRING(SMB2_CREATE_TAG_DH2Q);
3446 ADD_STRING(SMB2_CREATE_TAG_DH2C);
3447 ADD_STRING(SMB2_CREATE_TAG_AAPL);
3448 ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
3449 ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
3450 ADD_STRING(SMB2_CREATE_TAG_POSIX);
3451 ADD_FLAGS(SMB2_FIND_POSIX_INFORMATION);
3452 ADD_FLAGS(FILE_SUPERSEDE);
3453 ADD_FLAGS(FILE_OPEN);
3454 ADD_FLAGS(FILE_CREATE);
3455 ADD_FLAGS(FILE_OPEN_IF);
3456 ADD_FLAGS(FILE_OVERWRITE);
3457 ADD_FLAGS(FILE_OVERWRITE_IF);
3458 ADD_FLAGS(FILE_DIRECTORY_FILE);
3460 ADD_FLAGS(SMB2_CLOSE_FLAGS_FULL_INFORMATION);
3462 return m;