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/>.
26 #include "python/py3compat.h"
27 #include "python/modules.h"
28 #include "libcli/smb/smbXcli_base.h"
29 #include "libcli/smb/smb2_negotiate_context.h"
30 #include "libsmb/libsmb.h"
31 #include "libcli/security/security.h"
32 #include "system/select.h"
33 #include "source4/libcli/util/pyerrors.h"
34 #include "auth/credentials/pycredentials.h"
36 #include "libsmb/clirap.h"
37 #include "librpc/rpc/pyrpc_util.h"
39 #define LIST_ATTRIBUTE_MASK \
40 (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
42 static PyTypeObject
*dom_sid_Type
= NULL
;
44 static PyTypeObject
*get_pytype(const char *module
, const char *type
)
49 mod
= PyImport_ImportModule(module
);
51 PyErr_Format(PyExc_RuntimeError
,
52 "Unable to import %s to check type %s",
56 result
= (PyTypeObject
*)PyObject_GetAttrString(mod
, type
);
59 PyErr_Format(PyExc_RuntimeError
,
60 "Unable to find type %s in module %s",
68 * We're using "const char * const *" for keywords,
69 * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
70 * inevitable warnings to just one place.
72 static int ParseTupleAndKeywords(PyObject
*args
, PyObject
*kw
,
73 const char *format
, const char * const *keywords
,
76 char **_keywords
= discard_const_p(char *, keywords
);
79 va_start(a
, keywords
);
80 ret
= PyArg_VaParseTupleAndKeywords(args
, kw
, format
,
88 struct py_cli_oplock_break
{
95 struct cli_state
*cli
;
96 struct tevent_context
*ev
;
97 int (*req_wait_fn
)(struct tevent_context
*ev
,
98 struct tevent_req
*req
);
99 struct py_cli_thread
*thread_state
;
101 struct tevent_req
*oplock_waiter
;
102 struct py_cli_oplock_break
*oplock_breaks
;
103 struct py_tevent_cond
*oplock_cond
;
110 struct py_cli_thread
{
113 * Pipe to make the poll thread wake up in our destructor, so
114 * that we can exit and join the thread.
116 int shutdown_pipe
[2];
117 struct tevent_fd
*shutdown_fde
;
122 * Thread state to release the GIL during the poll(2) syscall
124 PyThreadState
*py_threadstate
;
127 static void *py_cli_state_poll_thread(void *private_data
)
129 struct py_cli_state
*self
= (struct py_cli_state
*)private_data
;
130 struct py_cli_thread
*t
= self
->thread_state
;
131 PyGILState_STATE gstate
;
133 gstate
= PyGILState_Ensure();
135 while (!t
->do_shutdown
) {
137 ret
= tevent_loop_once(self
->ev
);
140 PyGILState_Release(gstate
);
144 static void py_cli_state_trace_callback(enum tevent_trace_point point
,
147 struct py_cli_state
*self
= (struct py_cli_state
*)private_data
;
148 struct py_cli_thread
*t
= self
->thread_state
;
151 case TEVENT_TRACE_BEFORE_WAIT
:
152 assert(t
->py_threadstate
== NULL
);
153 t
->py_threadstate
= PyEval_SaveThread();
155 case TEVENT_TRACE_AFTER_WAIT
:
156 assert(t
->py_threadstate
!= NULL
);
157 PyEval_RestoreThread(t
->py_threadstate
);
158 t
->py_threadstate
= NULL
;
165 static void py_cli_state_shutdown_handler(struct tevent_context
*ev
,
166 struct tevent_fd
*fde
,
170 struct py_cli_state
*self
= (struct py_cli_state
*)private_data
;
171 struct py_cli_thread
*t
= self
->thread_state
;
173 if ((flags
& TEVENT_FD_READ
) == 0) {
176 TALLOC_FREE(t
->shutdown_fde
);
177 t
->do_shutdown
= true;
180 static int py_cli_thread_destructor(struct py_cli_thread
*t
)
188 * This will wake the poll thread from the poll(2)
190 written
= write(t
->shutdown_pipe
[1], &c
, 1);
191 } while ((written
== -1) && (errno
== EINTR
));
194 * Allow the poll thread to do its own cleanup under the GIL
196 Py_BEGIN_ALLOW_THREADS
197 ret
= pthread_join(t
->id
, NULL
);
201 if (t
->shutdown_pipe
[0] != -1) {
202 close(t
->shutdown_pipe
[0]);
203 t
->shutdown_pipe
[0] = -1;
205 if (t
->shutdown_pipe
[1] != -1) {
206 close(t
->shutdown_pipe
[1]);
207 t
->shutdown_pipe
[1] = -1;
212 static int py_tevent_cond_req_wait(struct tevent_context
*ev
,
213 struct tevent_req
*req
);
215 static bool py_cli_state_setup_mt_ev(struct py_cli_state
*self
)
217 struct py_cli_thread
*t
= NULL
;
220 self
->ev
= tevent_context_init_byname(NULL
, "poll_mt");
221 if (self
->ev
== NULL
) {
224 samba_tevent_set_debug(self
->ev
, "pylibsmb_tevent_mt");
225 tevent_set_trace_callback(self
->ev
, py_cli_state_trace_callback
, self
);
227 self
->req_wait_fn
= py_tevent_cond_req_wait
;
229 self
->thread_state
= talloc_zero(NULL
, struct py_cli_thread
);
230 if (self
->thread_state
== NULL
) {
233 t
= self
->thread_state
;
235 ret
= pipe(t
->shutdown_pipe
);
239 t
->shutdown_fde
= tevent_add_fd(
240 self
->ev
, self
->ev
, t
->shutdown_pipe
[0], TEVENT_FD_READ
,
241 py_cli_state_shutdown_handler
, self
);
242 if (t
->shutdown_fde
== NULL
) {
246 PyEval_InitThreads();
248 ret
= pthread_create(&t
->id
, NULL
, py_cli_state_poll_thread
, self
);
252 talloc_set_destructor(self
->thread_state
, py_cli_thread_destructor
);
257 TALLOC_FREE(t
->shutdown_fde
);
259 if (t
->shutdown_pipe
[0] != -1) {
260 close(t
->shutdown_pipe
[0]);
261 t
->shutdown_pipe
[0] = -1;
263 if (t
->shutdown_pipe
[1] != -1) {
264 close(t
->shutdown_pipe
[1]);
265 t
->shutdown_pipe
[1] = -1;
269 TALLOC_FREE(self
->thread_state
);
270 TALLOC_FREE(self
->ev
);
274 struct py_tevent_cond
{
275 pthread_mutex_t mutex
;
280 static void py_tevent_signalme(struct tevent_req
*req
);
282 static int py_tevent_cond_wait(struct py_tevent_cond
*cond
)
286 result
= pthread_mutex_init(&cond
->mutex
, NULL
);
290 result
= pthread_cond_init(&cond
->cond
, NULL
);
295 result
= pthread_mutex_lock(&cond
->mutex
);
300 cond
->is_done
= false;
302 while (!cond
->is_done
) {
304 Py_BEGIN_ALLOW_THREADS
305 result
= pthread_cond_wait(&cond
->cond
, &cond
->mutex
);
314 ret
= pthread_mutex_unlock(&cond
->mutex
);
317 ret
= pthread_cond_destroy(&cond
->cond
);
320 ret
= pthread_mutex_destroy(&cond
->mutex
);
326 static int py_tevent_cond_req_wait(struct tevent_context
*ev
,
327 struct tevent_req
*req
)
329 struct py_tevent_cond cond
;
330 tevent_req_set_callback(req
, py_tevent_signalme
, &cond
);
331 return py_tevent_cond_wait(&cond
);
334 static void py_tevent_cond_signal(struct py_tevent_cond
*cond
)
338 ret
= pthread_mutex_lock(&cond
->mutex
);
341 cond
->is_done
= true;
343 ret
= pthread_cond_signal(&cond
->cond
);
345 ret
= pthread_mutex_unlock(&cond
->mutex
);
349 static void py_tevent_signalme(struct tevent_req
*req
)
351 struct py_tevent_cond
*cond
= (struct py_tevent_cond
*)
352 tevent_req_callback_data_void(req
);
354 py_tevent_cond_signal(cond
);
359 static int py_tevent_req_wait(struct tevent_context
*ev
,
360 struct tevent_req
*req
);
362 static bool py_cli_state_setup_ev(struct py_cli_state
*self
)
364 self
->ev
= tevent_context_init(NULL
);
365 if (self
->ev
== NULL
) {
369 samba_tevent_set_debug(self
->ev
, "pylibsmb_tevent");
371 self
->req_wait_fn
= py_tevent_req_wait
;
376 static int py_tevent_req_wait(struct tevent_context
*ev
,
377 struct tevent_req
*req
)
379 while (tevent_req_is_in_progress(req
)) {
382 ret
= tevent_loop_once(ev
);
390 static bool py_tevent_req_wait_exc(struct py_cli_state
*self
,
391 struct tevent_req
*req
)
399 ret
= self
->req_wait_fn(self
->ev
, req
);
403 PyErr_SetFromErrno(PyExc_RuntimeError
);
409 static PyObject
*py_cli_state_new(PyTypeObject
*type
, PyObject
*args
,
412 struct py_cli_state
*self
;
414 self
= (struct py_cli_state
*)type
->tp_alloc(type
, 0);
420 self
->thread_state
= NULL
;
421 self
->oplock_waiter
= NULL
;
422 self
->oplock_cond
= NULL
;
423 self
->oplock_breaks
= NULL
;
424 return (PyObject
*)self
;
427 static struct smb2_negotiate_contexts
*py_cli_get_negotiate_contexts(
428 TALLOC_CTX
*mem_ctx
, PyObject
*list
)
430 struct smb2_negotiate_contexts
*ctxs
= NULL
;
434 ret
= PyList_Check(list
);
439 len
= PyList_Size(list
);
444 ctxs
= talloc_zero(mem_ctx
, struct smb2_negotiate_contexts
);
449 for (i
=0; i
<len
; i
++) {
452 PyObject
*t
= PyList_GetItem(list
, i
);
455 PyObject
*ptype
= NULL
;
458 PyObject
*pdata
= NULL
;
459 DATA_BLOB data
= { .data
= NULL
, };
465 ret
= PyTuple_Check(t
);
470 tlen
= PyTuple_Size(t
);
475 ptype
= PyTuple_GetItem(t
, 0);
479 type
= PyLong_AsLong(ptype
);
480 if ((type
< 0) || (type
> UINT16_MAX
)) {
484 pdata
= PyTuple_GetItem(t
, 1);
486 ret
= PyBytes_Check(pdata
);
491 data
.data
= (uint8_t *)PyBytes_AsString(pdata
);
492 data
.length
= PyBytes_Size(pdata
);
494 status
= smb2_negotiate_context_add(
495 ctxs
, ctxs
, type
, data
.data
, data
.length
);
496 if (!NT_STATUS_IS_OK(status
)) {
507 static void py_cli_got_oplock_break(struct tevent_req
*req
);
509 static int py_cli_state_init(struct py_cli_state
*self
, PyObject
*args
,
514 PyObject
*creds
= NULL
;
515 struct cli_credentials
*cli_creds
;
516 PyObject
*py_lp
= Py_None
;
517 PyObject
*py_multi_threaded
= Py_False
;
518 bool multi_threaded
= false;
519 PyObject
*py_force_smb1
= Py_False
;
520 bool force_smb1
= false;
521 PyObject
*py_ipc
= Py_False
;
522 PyObject
*py_posix
= Py_False
;
523 PyObject
*py_negotiate_contexts
= NULL
;
524 struct smb2_negotiate_contexts
*negotiate_contexts
= NULL
;
525 bool use_ipc
= false;
526 bool request_posix
= false;
527 struct tevent_req
*req
;
531 static const char *kwlist
[] = {
532 "host", "share", "lp", "creds",
533 "multi_threaded", "force_smb1",
536 "negotiate_contexts",
540 PyTypeObject
*py_type_Credentials
= get_pytype(
541 "samba.credentials", "Credentials");
542 if (py_type_Credentials
== NULL
) {
546 ret
= ParseTupleAndKeywords(
547 args
, kwds
, "ssO|O!OOOOO", kwlist
,
548 &host
, &share
, &py_lp
,
549 py_type_Credentials
, &creds
,
554 &py_negotiate_contexts
);
556 Py_DECREF(py_type_Credentials
);
562 multi_threaded
= PyObject_IsTrue(py_multi_threaded
);
563 force_smb1
= PyObject_IsTrue(py_force_smb1
);
567 * As most of the cli_*_send() function
568 * don't support SMB2 (it's only plugged
569 * into the sync wrapper functions currently)
570 * we have a way to force SMB1.
572 flags
= CLI_FULL_CONNECTION_FORCE_SMB1
;
575 use_ipc
= PyObject_IsTrue(py_ipc
);
577 flags
|= CLI_FULL_CONNECTION_IPC
;
580 request_posix
= PyObject_IsTrue(py_posix
);
582 flags
|= CLI_FULL_CONNECTION_REQUEST_POSIX
;
585 if (py_negotiate_contexts
!= NULL
) {
586 negotiate_contexts
= py_cli_get_negotiate_contexts(
587 talloc_tos(), py_negotiate_contexts
);
588 if (negotiate_contexts
== NULL
) {
593 if (multi_threaded
) {
595 ret
= py_cli_state_setup_mt_ev(self
);
600 PyErr_SetString(PyExc_RuntimeError
,
601 "No PTHREAD support available");
605 ret
= py_cli_state_setup_ev(self
);
612 cli_creds
= cli_credentials_init_anon(NULL
);
614 cli_creds
= PyCredentials_AsCliCredentials(creds
);
617 req
= cli_full_connection_creds_send(
618 NULL
, self
->ev
, "myname", host
, NULL
, 0, share
, "?????",
621 if (!py_tevent_req_wait_exc(self
, req
)) {
624 status
= cli_full_connection_creds_recv(req
, &self
->cli
);
627 if (!NT_STATUS_IS_OK(status
)) {
628 PyErr_SetNTSTATUS(status
);
633 * Oplocks require a multi threaded connection
635 if (self
->thread_state
== NULL
) {
639 self
->oplock_waiter
= cli_smb_oplock_break_waiter_send(
640 self
->ev
, self
->ev
, self
->cli
);
641 if (self
->oplock_waiter
== NULL
) {
645 tevent_req_set_callback(self
->oplock_waiter
, py_cli_got_oplock_break
,
650 static void py_cli_got_oplock_break(struct tevent_req
*req
)
652 struct py_cli_state
*self
= (struct py_cli_state
*)
653 tevent_req_callback_data_void(req
);
654 struct py_cli_oplock_break b
;
655 struct py_cli_oplock_break
*tmp
;
659 status
= cli_smb_oplock_break_waiter_recv(req
, &b
.fnum
, &b
.level
);
661 self
->oplock_waiter
= NULL
;
663 if (!NT_STATUS_IS_OK(status
)) {
667 num_breaks
= talloc_array_length(self
->oplock_breaks
);
668 tmp
= talloc_realloc(self
->ev
, self
->oplock_breaks
,
669 struct py_cli_oplock_break
, num_breaks
+1);
673 self
->oplock_breaks
= tmp
;
674 self
->oplock_breaks
[num_breaks
] = b
;
676 if (self
->oplock_cond
!= NULL
) {
677 py_tevent_cond_signal(self
->oplock_cond
);
680 self
->oplock_waiter
= cli_smb_oplock_break_waiter_send(
681 self
->ev
, self
->ev
, self
->cli
);
682 if (self
->oplock_waiter
== NULL
) {
685 tevent_req_set_callback(self
->oplock_waiter
, py_cli_got_oplock_break
,
689 static PyObject
*py_cli_get_oplock_break(struct py_cli_state
*self
,
692 size_t num_oplock_breaks
;
694 if (!PyArg_ParseTuple(args
, "")) {
698 if (self
->thread_state
== NULL
) {
699 PyErr_SetString(PyExc_RuntimeError
,
700 "get_oplock_break() only possible on "
701 "a multi_threaded connection");
705 if (self
->oplock_cond
!= NULL
) {
707 PyErr_SetFromErrno(PyExc_RuntimeError
);
711 num_oplock_breaks
= talloc_array_length(self
->oplock_breaks
);
713 if (num_oplock_breaks
== 0) {
714 struct py_tevent_cond cond
;
717 self
->oplock_cond
= &cond
;
718 ret
= py_tevent_cond_wait(&cond
);
719 self
->oplock_cond
= NULL
;
723 PyErr_SetFromErrno(PyExc_RuntimeError
);
728 num_oplock_breaks
= talloc_array_length(self
->oplock_breaks
);
729 if (num_oplock_breaks
> 0) {
732 result
= Py_BuildValue(
734 "fnum", self
->oplock_breaks
[0].fnum
,
735 "level", self
->oplock_breaks
[0].level
);
737 memmove(&self
->oplock_breaks
[0], &self
->oplock_breaks
[1],
738 sizeof(self
->oplock_breaks
[0]) *
739 (num_oplock_breaks
- 1));
740 self
->oplock_breaks
= talloc_realloc(
741 NULL
, self
->oplock_breaks
, struct py_cli_oplock_break
,
742 num_oplock_breaks
- 1);
749 static void py_cli_state_dealloc(struct py_cli_state
*self
)
751 TALLOC_FREE(self
->thread_state
);
752 TALLOC_FREE(self
->oplock_waiter
);
753 TALLOC_FREE(self
->ev
);
755 if (self
->cli
!= NULL
) {
756 cli_shutdown(self
->cli
);
759 Py_TYPE(self
)->tp_free((PyObject
*)self
);
762 static PyObject
*py_cli_settimeout(struct py_cli_state
*self
, PyObject
*args
)
764 unsigned int nmsecs
= 0;
765 unsigned int omsecs
= 0;
767 if (!PyArg_ParseTuple(args
, "I", &nmsecs
)) {
771 omsecs
= cli_set_timeout(self
->cli
, nmsecs
);
773 return PyLong_FromLong(omsecs
);
776 static PyObject
*py_cli_echo(struct py_cli_state
*self
,
777 PyObject
*Py_UNUSED(ignored
))
779 DATA_BLOB data
= data_blob_string_const("keepalive");
780 struct tevent_req
*req
= NULL
;
783 req
= cli_echo_send(NULL
, self
->ev
, self
->cli
, 1, data
);
784 if (!py_tevent_req_wait_exc(self
, req
)) {
787 status
= cli_echo_recv(req
);
789 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
794 static PyObject
*py_cli_create(struct py_cli_state
*self
, PyObject
*args
,
798 unsigned CreateFlags
= 0;
799 unsigned DesiredAccess
= FILE_GENERIC_READ
;
800 unsigned FileAttributes
= 0;
801 unsigned ShareAccess
= 0;
802 unsigned CreateDisposition
= FILE_OPEN
;
803 unsigned CreateOptions
= 0;
804 unsigned ImpersonationLevel
= SMB2_IMPERSONATION_IMPERSONATION
;
805 unsigned SecurityFlags
= 0;
807 struct tevent_req
*req
;
810 static const char *kwlist
[] = {
811 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
812 "ShareAccess", "CreateDisposition", "CreateOptions",
813 "ImpersonationLevel", "SecurityFlags", NULL
};
815 if (!ParseTupleAndKeywords(
816 args
, kwds
, "s|IIIIIIII", kwlist
,
817 &fname
, &CreateFlags
, &DesiredAccess
, &FileAttributes
,
818 &ShareAccess
, &CreateDisposition
, &CreateOptions
,
819 &ImpersonationLevel
, &SecurityFlags
)) {
823 req
= cli_ntcreate_send(NULL
, self
->ev
, self
->cli
, fname
, CreateFlags
,
824 DesiredAccess
, FileAttributes
, ShareAccess
,
825 CreateDisposition
, CreateOptions
,
826 ImpersonationLevel
, SecurityFlags
);
827 if (!py_tevent_req_wait_exc(self
, req
)) {
830 status
= cli_ntcreate_recv(req
, &fnum
, NULL
);
833 if (!NT_STATUS_IS_OK(status
)) {
834 PyErr_SetNTSTATUS(status
);
837 return Py_BuildValue("I", (unsigned)fnum
);
840 static PyObject
*py_cli_close(struct py_cli_state
*self
, PyObject
*args
)
842 struct tevent_req
*req
;
846 if (!PyArg_ParseTuple(args
, "i", &fnum
)) {
850 req
= cli_close_send(NULL
, self
->ev
, self
->cli
, fnum
);
851 if (!py_tevent_req_wait_exc(self
, req
)) {
854 status
= cli_close_recv(req
);
857 if (!NT_STATUS_IS_OK(status
)) {
858 PyErr_SetNTSTATUS(status
);
864 static PyObject
*py_cli_rename(
865 struct py_cli_state
*self
, PyObject
*args
, PyObject
*kwds
)
867 char *fname_src
= NULL
, *fname_dst
= NULL
;
869 struct tevent_req
*req
= NULL
;
873 static const char *kwlist
[] = { "src", "dst", "replace", NULL
};
875 ok
= ParseTupleAndKeywords(
876 args
, kwds
, "ss|p", kwlist
, &fname_src
, &fname_dst
, &replace
);
881 req
= cli_rename_send(
882 NULL
, self
->ev
, self
->cli
, fname_src
, fname_dst
, replace
);
883 if (!py_tevent_req_wait_exc(self
, req
)) {
886 status
= cli_rename_recv(req
);
889 if (!NT_STATUS_IS_OK(status
)) {
890 PyErr_SetNTSTATUS(status
);
904 * cli_push() helper to write a chunk of data to a remote file
906 static size_t push_data(uint8_t *buf
, size_t n
, void *priv
)
908 struct push_state
*state
= (struct push_state
*)priv
;
909 char *curr_ptr
= NULL
;
913 if (state
->nread
>= state
->total_data
) {
917 curr_ptr
= state
->data
+ state
->nread
;
918 remaining
= state
->total_data
- state
->nread
;
919 copied_bytes
= MIN(remaining
, n
);
921 memcpy(buf
, curr_ptr
, copied_bytes
);
922 state
->nread
+= copied_bytes
;
927 * Writes a file with the contents specified
929 static PyObject
*py_smb_savefile(struct py_cli_state
*self
, PyObject
*args
)
932 const char *filename
= NULL
;
936 struct tevent_req
*req
= NULL
;
937 struct push_state state
;
939 if (!PyArg_ParseTuple(args
, "s"PYARG_BYTES_LEN
":savefile", &filename
,
944 /* create a new file handle for writing to */
945 req
= cli_ntcreate_send(NULL
, self
->ev
, self
->cli
, filename
, 0,
946 FILE_WRITE_DATA
, FILE_ATTRIBUTE_NORMAL
,
947 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
948 FILE_OVERWRITE_IF
, FILE_NON_DIRECTORY_FILE
,
949 SMB2_IMPERSONATION_IMPERSONATION
, 0);
950 if (!py_tevent_req_wait_exc(self
, req
)) {
953 status
= cli_ntcreate_recv(req
, &fnum
, NULL
);
955 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
957 /* write the new file contents */
960 state
.total_data
= size
;
962 req
= cli_push_send(NULL
, self
->ev
, self
->cli
, fnum
, 0, 0, 0,
964 if (!py_tevent_req_wait_exc(self
, req
)) {
967 status
= cli_push_recv(req
);
969 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
971 /* close the file handle */
972 req
= cli_close_send(NULL
, self
->ev
, self
->cli
, fnum
);
973 if (!py_tevent_req_wait_exc(self
, req
)) {
976 status
= cli_close_recv(req
);
977 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
982 static PyObject
*py_cli_write(struct py_cli_state
*self
, PyObject
*args
,
989 unsigned long long offset
;
990 struct tevent_req
*req
;
994 static const char *kwlist
[] = {
995 "fnum", "buffer", "offset", "mode", NULL
};
997 if (!ParseTupleAndKeywords(
998 args
, kwds
, "i" PYARG_BYTES_LEN
"K|I", kwlist
,
999 &fnum
, &buf
, &buflen
, &offset
, &mode
)) {
1003 req
= cli_write_send(NULL
, self
->ev
, self
->cli
, fnum
, mode
,
1004 (uint8_t *)buf
, offset
, buflen
);
1005 if (!py_tevent_req_wait_exc(self
, req
)) {
1008 status
= cli_write_recv(req
, &written
);
1011 if (!NT_STATUS_IS_OK(status
)) {
1012 PyErr_SetNTSTATUS(status
);
1015 return Py_BuildValue("K", (unsigned long long)written
);
1019 * Returns the size of the given file
1021 static NTSTATUS
py_smb_filesize(struct py_cli_state
*self
, uint16_t fnum
,
1025 struct tevent_req
*req
= NULL
;
1027 req
= cli_qfileinfo_basic_send(NULL
, self
->ev
, self
->cli
, fnum
);
1028 if (!py_tevent_req_wait_exc(self
, req
)) {
1029 return NT_STATUS_INTERNAL_ERROR
;
1031 status
= cli_qfileinfo_basic_recv(
1032 req
, NULL
, size
, NULL
, NULL
, NULL
, NULL
, NULL
);
1038 * Loads the specified file's contents and returns it
1040 static PyObject
*py_smb_loadfile(struct py_cli_state
*self
, PyObject
*args
)
1043 const char *filename
= NULL
;
1044 struct tevent_req
*req
= NULL
;
1049 PyObject
*result
= NULL
;
1051 if (!PyArg_ParseTuple(args
, "s:loadfile", &filename
)) {
1055 /* get a read file handle */
1056 req
= cli_ntcreate_send(NULL
, self
->ev
, self
->cli
, filename
, 0,
1057 FILE_READ_DATA
| FILE_READ_ATTRIBUTES
,
1058 FILE_ATTRIBUTE_NORMAL
,
1059 FILE_SHARE_READ
, FILE_OPEN
, 0,
1060 SMB2_IMPERSONATION_IMPERSONATION
, 0);
1061 if (!py_tevent_req_wait_exc(self
, req
)) {
1064 status
= cli_ntcreate_recv(req
, &fnum
, NULL
);
1066 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1068 /* get a buffer to hold the file contents */
1069 status
= py_smb_filesize(self
, fnum
, &size
);
1070 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1072 result
= PyBytes_FromStringAndSize(NULL
, size
);
1073 if (result
== NULL
) {
1077 /* read the file contents */
1078 buf
= PyBytes_AS_STRING(result
);
1079 req
= cli_pull_send(NULL
, self
->ev
, self
->cli
, fnum
, 0, size
,
1080 size
, cli_read_sink
, &buf
);
1081 if (!py_tevent_req_wait_exc(self
, req
)) {
1085 status
= cli_pull_recv(req
, &nread
);
1087 if (!NT_STATUS_IS_OK(status
)) {
1089 PyErr_SetNTSTATUS(status
);
1093 /* close the file handle */
1094 req
= cli_close_send(NULL
, self
->ev
, self
->cli
, fnum
);
1095 if (!py_tevent_req_wait_exc(self
, req
)) {
1099 status
= cli_close_recv(req
);
1101 if (!NT_STATUS_IS_OK(status
)) {
1103 PyErr_SetNTSTATUS(status
);
1107 /* sanity-check we read the expected number of bytes */
1110 PyErr_Format(PyExc_IOError
,
1111 "read invalid - got %zu requested %zu",
1117 if (_PyBytes_Resize(&result
, nread
) < 0) {
1125 static PyObject
*py_cli_read(struct py_cli_state
*self
, PyObject
*args
,
1129 unsigned long long offset
;
1131 struct tevent_req
*req
;
1137 static const char *kwlist
[] = {
1138 "fnum", "offset", "size", NULL
};
1140 if (!ParseTupleAndKeywords(
1141 args
, kwds
, "iKI", kwlist
, &fnum
, &offset
,
1146 result
= PyBytes_FromStringAndSize(NULL
, size
);
1147 if (result
== NULL
) {
1150 buf
= PyBytes_AS_STRING(result
);
1152 req
= cli_read_send(NULL
, self
->ev
, self
->cli
, fnum
,
1154 if (!py_tevent_req_wait_exc(self
, req
)) {
1158 status
= cli_read_recv(req
, &received
);
1161 if (!NT_STATUS_IS_OK(status
)) {
1163 PyErr_SetNTSTATUS(status
);
1167 if (received
> size
) {
1169 PyErr_Format(PyExc_IOError
,
1170 "read invalid - got %zu requested %u",
1175 if (received
< size
) {
1176 if (_PyBytes_Resize(&result
, received
) < 0) {
1184 static PyObject
*py_cli_ftruncate(struct py_cli_state
*self
, PyObject
*args
,
1188 unsigned long long size
;
1189 struct tevent_req
*req
;
1192 static const char *kwlist
[] = {
1193 "fnum", "size", NULL
};
1195 if (!ParseTupleAndKeywords(
1196 args
, kwds
, "IK", kwlist
, &fnum
, &size
)) {
1200 req
= cli_ftruncate_send(NULL
, self
->ev
, self
->cli
, fnum
, size
);
1201 if (!py_tevent_req_wait_exc(self
, req
)) {
1204 status
= cli_ftruncate_recv(req
);
1207 if (!NT_STATUS_IS_OK(status
)) {
1208 PyErr_SetNTSTATUS(status
);
1214 static PyObject
*py_cli_delete_on_close(struct py_cli_state
*self
,
1218 unsigned fnum
, flag
;
1219 struct tevent_req
*req
;
1222 static const char *kwlist
[] = {
1223 "fnum", "flag", NULL
};
1225 if (!ParseTupleAndKeywords(
1226 args
, kwds
, "II", kwlist
, &fnum
, &flag
)) {
1230 req
= cli_nt_delete_on_close_send(NULL
, self
->ev
, self
->cli
, fnum
,
1232 if (!py_tevent_req_wait_exc(self
, req
)) {
1235 status
= cli_nt_delete_on_close_recv(req
);
1238 if (!NT_STATUS_IS_OK(status
)) {
1239 PyErr_SetNTSTATUS(status
);
1245 struct py_cli_notify_state
{
1247 struct py_cli_state
*py_cli_state
;
1248 struct tevent_req
*req
;
1251 static void py_cli_notify_state_dealloc(struct py_cli_notify_state
*self
)
1253 TALLOC_FREE(self
->req
);
1254 if (self
->py_cli_state
!= NULL
) {
1255 Py_DECREF(self
->py_cli_state
);
1256 self
->py_cli_state
= NULL
;
1258 Py_TYPE(self
)->tp_free(self
);
1261 static PyTypeObject py_cli_notify_state_type
;
1263 static PyObject
*py_cli_notify(struct py_cli_state
*self
,
1267 static const char *kwlist
[] = {
1270 "completion_filter",
1275 unsigned buffer_size
= 0;
1276 unsigned completion_filter
= 0;
1277 PyObject
*py_recursive
= Py_False
;
1278 bool recursive
= false;
1279 struct tevent_req
*req
= NULL
;
1280 struct tevent_queue
*send_queue
= NULL
;
1281 struct tevent_req
*flush_req
= NULL
;
1283 struct py_cli_notify_state
*py_notify_state
= NULL
;
1284 struct timeval endtime
;
1286 ok
= ParseTupleAndKeywords(args
,
1298 recursive
= PyObject_IsTrue(py_recursive
);
1300 req
= cli_notify_send(NULL
,
1313 * Just wait for the request being submitted to
1314 * the kernel/socket/wire.
1316 send_queue
= smbXcli_conn_send_queue(self
->cli
->conn
);
1317 flush_req
= tevent_queue_wait_send(req
,
1320 endtime
= timeval_current_ofs_msec(self
->cli
->timeout
);
1321 ok
= tevent_req_set_endtime(flush_req
,
1329 ok
= py_tevent_req_wait_exc(self
, flush_req
);
1334 TALLOC_FREE(flush_req
);
1336 py_notify_state
= (struct py_cli_notify_state
*)
1337 py_cli_notify_state_type
.tp_alloc(&py_cli_notify_state_type
, 0);
1338 if (py_notify_state
== NULL
) {
1344 py_notify_state
->py_cli_state
= self
;
1345 py_notify_state
->req
= req
;
1347 return (PyObject
*)py_notify_state
;
1350 static PyObject
*py_cli_notify_get_changes(struct py_cli_notify_state
*self
,
1354 struct py_cli_state
*py_cli_state
= self
->py_cli_state
;
1355 struct tevent_req
*req
= self
->req
;
1357 uint32_t num_changes
= 0;
1358 struct notify_change
*changes
= NULL
;
1359 PyObject
*result
= NULL
;
1362 static const char *kwlist
[] = {
1366 PyObject
*py_wait
= Py_False
;
1370 ok
= ParseTupleAndKeywords(args
,
1379 wait
= PyObject_IsTrue(py_wait
);
1382 PyErr_SetString(PyExc_RuntimeError
,
1384 "- missing change notify request?");
1388 pending
= tevent_req_is_in_progress(req
);
1389 if (pending
&& !wait
) {
1394 struct timeval endtime
;
1396 endtime
= timeval_current_ofs_msec(py_cli_state
->cli
->timeout
);
1397 ok
= tevent_req_set_endtime(req
,
1407 ok
= py_tevent_req_wait_exc(py_cli_state
, req
);
1409 Py_DECREF(self
->py_cli_state
);
1410 self
->py_cli_state
= NULL
;
1415 status
= cli_notify_recv(req
, req
, &num_changes
, &changes
);
1416 if (!NT_STATUS_IS_OK(status
)) {
1418 PyErr_SetNTSTATUS(status
);
1422 result
= Py_BuildValue("[]");
1423 if (result
== NULL
) {
1428 for (i
= 0; i
< num_changes
; i
++) {
1429 PyObject
*change
= NULL
;
1432 change
= Py_BuildValue("{s:s,s:I}",
1433 "name", changes
[i
].name
,
1434 "action", changes
[i
].action
);
1435 if (change
== NULL
) {
1441 ret
= PyList_Append(result
, change
);
1454 static PyMethodDef py_cli_notify_state_methods
[] = {
1456 .ml_name
= "get_changes",
1457 .ml_meth
= (PyCFunction
)py_cli_notify_get_changes
,
1458 .ml_flags
= METH_VARARGS
|METH_KEYWORDS
,
1459 .ml_doc
= "Wait for change notifications: \n"
1460 "N.get_changes(wait=BOOLEAN) -> "
1461 "change notifications as a dictionary\n"
1462 "\t\tList contents of a directory. The keys are, \n"
1463 "\t\t\tname: name of changed object\n"
1464 "\t\t\taction: type of the change\n"
1465 "None is returned if there's no response jet and "
1466 "wait=False is passed"
1473 static PyTypeObject py_cli_notify_state_type
= {
1474 PyVarObject_HEAD_INIT(NULL
, 0)
1475 .tp_name
= "libsmb_samba_cwrapper.Notify",
1476 .tp_basicsize
= sizeof(struct py_cli_notify_state
),
1477 .tp_flags
= Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
,
1478 .tp_doc
= "notify request",
1479 .tp_dealloc
= (destructor
)py_cli_notify_state_dealloc
,
1480 .tp_methods
= py_cli_notify_state_methods
,
1484 * Helper to add directory listing entries to an overall Python list
1486 static NTSTATUS
list_helper(struct file_info
*finfo
,
1487 const char *mask
, void *state
)
1489 PyObject
*result
= (PyObject
*)state
;
1490 PyObject
*file
= NULL
;
1491 PyObject
*size
= NULL
;
1494 /* suppress '.' and '..' in the results we return */
1495 if (ISDOT(finfo
->name
) || ISDOTDOT(finfo
->name
)) {
1496 return NT_STATUS_OK
;
1498 size
= PyLong_FromUnsignedLongLong(finfo
->size
);
1500 * Build a dictionary representing the file info.
1501 * Note: Windows does not always return short_name (so it may be None)
1503 file
= Py_BuildValue("{s:s,s:i,s:s,s:O,s:l}",
1504 "name", finfo
->name
,
1505 "attrib", (int)finfo
->attr
,
1506 "short_name", finfo
->short_name
,
1509 convert_timespec_to_time_t(finfo
->mtime_ts
));
1514 return NT_STATUS_NO_MEMORY
;
1517 ret
= PyList_Append(result
, file
);
1520 return NT_STATUS_INTERNAL_ERROR
;
1523 return NT_STATUS_OK
;
1526 struct do_listing_state
{
1528 NTSTATUS (*callback_fn
)(
1529 struct file_info
*finfo
,
1531 void *private_data
);
1536 static void do_listing_cb(struct tevent_req
*subreq
)
1538 struct do_listing_state
*state
= tevent_req_callback_data_void(subreq
);
1539 struct file_info
*finfo
= NULL
;
1541 state
->status
= cli_list_recv(subreq
, NULL
, &finfo
);
1542 if (!NT_STATUS_IS_OK(state
->status
)) {
1545 state
->callback_fn(finfo
, state
->mask
, state
->private_data
);
1549 static NTSTATUS
do_listing(struct py_cli_state
*self
,
1550 const char *base_dir
, const char *user_mask
,
1552 NTSTATUS (*callback_fn
)(struct file_info
*,
1553 const char *, void *),
1557 unsigned int info_level
= SMB_FIND_FILE_BOTH_DIRECTORY_INFO
;
1558 struct do_listing_state state
= {
1560 .callback_fn
= callback_fn
,
1561 .private_data
= priv
,
1563 struct tevent_req
*req
= NULL
;
1566 if (user_mask
== NULL
) {
1567 mask
= talloc_asprintf(NULL
, "%s\\*", base_dir
);
1569 mask
= talloc_asprintf(NULL
, "%s\\%s", base_dir
, user_mask
);
1573 return NT_STATUS_NO_MEMORY
;
1577 req
= cli_list_send(NULL
, self
->ev
, self
->cli
, mask
, attribute
,
1580 status
= NT_STATUS_NO_MEMORY
;
1583 tevent_req_set_callback(req
, do_listing_cb
, &state
);
1585 if (!py_tevent_req_wait_exc(self
, req
)) {
1586 return NT_STATUS_INTERNAL_ERROR
;
1590 status
= state
.status
;
1591 if (NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_FILES
)) {
1592 status
= NT_STATUS_OK
;
1600 static PyObject
*py_cli_list(struct py_cli_state
*self
,
1605 char *user_mask
= NULL
;
1606 unsigned int attribute
= LIST_ATTRIBUTE_MASK
;
1608 PyObject
*result
= NULL
;
1609 const char *kwlist
[] = { "directory", "mask", "attribs", NULL
};
1611 if (!ParseTupleAndKeywords(args
, kwds
, "z|sI:list", kwlist
,
1612 &base_dir
, &user_mask
, &attribute
)) {
1616 result
= Py_BuildValue("[]");
1617 if (result
== NULL
) {
1621 status
= do_listing(self
, base_dir
, user_mask
, attribute
,
1622 list_helper
, result
);
1624 if (!NT_STATUS_IS_OK(status
)) {
1626 PyErr_SetNTSTATUS(status
);
1633 static PyObject
*py_smb_unlink(struct py_cli_state
*self
, PyObject
*args
)
1636 const char *filename
= NULL
;
1637 struct tevent_req
*req
= NULL
;
1638 const uint32_t attrs
= (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
);
1640 if (!PyArg_ParseTuple(args
, "s:unlink", &filename
)) {
1644 req
= cli_unlink_send(NULL
, self
->ev
, self
->cli
, filename
, attrs
);
1645 if (!py_tevent_req_wait_exc(self
, req
)) {
1648 status
= cli_unlink_recv(req
);
1650 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1655 static PyObject
*py_smb_rmdir(struct py_cli_state
*self
, PyObject
*args
)
1658 struct tevent_req
*req
= NULL
;
1659 const char *dirname
= NULL
;
1661 if (!PyArg_ParseTuple(args
, "s:rmdir", &dirname
)) {
1665 req
= cli_rmdir_send(NULL
, self
->ev
, self
->cli
, dirname
);
1666 if (!py_tevent_req_wait_exc(self
, req
)) {
1669 status
= cli_rmdir_recv(req
);
1671 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1677 * Create a directory
1679 static PyObject
*py_smb_mkdir(struct py_cli_state
*self
, PyObject
*args
)
1682 const char *dirname
= NULL
;
1683 struct tevent_req
*req
= NULL
;
1685 if (!PyArg_ParseTuple(args
, "s:mkdir", &dirname
)) {
1689 req
= cli_mkdir_send(NULL
, self
->ev
, self
->cli
, dirname
);
1690 if (!py_tevent_req_wait_exc(self
, req
)) {
1693 status
= cli_mkdir_recv(req
);
1695 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1701 * Does a whoami call
1703 static PyObject
*py_smb_posix_whoami(struct py_cli_state
*self
,
1704 PyObject
*Py_UNUSED(ignored
))
1706 TALLOC_CTX
*frame
= talloc_stackframe();
1708 struct tevent_req
*req
= NULL
;
1712 uint64_t *gids
= NULL
;
1714 struct dom_sid
*sids
= NULL
;
1716 PyObject
*py_gids
= NULL
;
1717 PyObject
*py_sids
= NULL
;
1718 PyObject
*py_guest
= NULL
;
1719 PyObject
*py_ret
= NULL
;
1722 req
= cli_posix_whoami_send(frame
, self
->ev
, self
->cli
);
1723 if (!py_tevent_req_wait_exc(self
, req
)) {
1726 status
= cli_posix_whoami_recv(req
,
1735 if (!NT_STATUS_IS_OK(status
)) {
1736 PyErr_SetNTSTATUS(status
);
1739 if (num_gids
> PY_SSIZE_T_MAX
) {
1740 PyErr_SetString(PyExc_OverflowError
, "posix_whoami: Too many GIDs");
1743 if (num_sids
> PY_SSIZE_T_MAX
) {
1744 PyErr_SetString(PyExc_OverflowError
, "posix_whoami: Too many SIDs");
1748 py_gids
= PyList_New(num_gids
);
1752 for (i
= 0; i
< num_gids
; ++i
) {
1754 PyObject
*py_item
= PyLong_FromUnsignedLongLong(gids
[i
]);
1759 ret
= PyList_SetItem(py_gids
, i
, py_item
);
1764 py_sids
= PyList_New(num_sids
);
1768 for (i
= 0; i
< num_sids
; ++i
) {
1770 struct dom_sid
*sid
;
1773 sid
= dom_sid_dup(frame
, &sids
[i
]);
1779 py_item
= pytalloc_steal(dom_sid_Type
, sid
);
1785 ret
= PyList_SetItem(py_sids
, i
, py_item
);
1791 py_guest
= guest
? Py_True
: Py_False
;
1793 py_ret
= Py_BuildValue("KKNNO",
1818 * Checks existence of a directory
1820 static bool check_dir_path(struct py_cli_state
*self
, const char *path
)
1823 struct tevent_req
*req
= NULL
;
1825 req
= cli_chkpath_send(NULL
, self
->ev
, self
->cli
, path
);
1826 if (!py_tevent_req_wait_exc(self
, req
)) {
1829 status
= cli_chkpath_recv(req
);
1832 return NT_STATUS_IS_OK(status
);
1835 static PyObject
*py_smb_chkpath(struct py_cli_state
*self
, PyObject
*args
)
1837 const char *path
= NULL
;
1840 if (!PyArg_ParseTuple(args
, "s:chkpath", &path
)) {
1844 dir_exists
= check_dir_path(self
, path
);
1845 return PyBool_FromLong(dir_exists
);
1848 static PyObject
*py_smb_have_posix(struct py_cli_state
*self
,
1849 PyObject
*Py_UNUSED(ignored
))
1851 bool posix
= smbXcli_conn_have_posix(self
->cli
->conn
);
1859 static PyObject
*py_smb_get_sd(struct py_cli_state
*self
, PyObject
*args
)
1863 struct tevent_req
*req
= NULL
;
1864 struct security_descriptor
*sd
= NULL
;
1867 if (!PyArg_ParseTuple(args
, "iI:get_acl", &fnum
, &sinfo
)) {
1871 req
= cli_query_security_descriptor_send(
1872 NULL
, self
->ev
, self
->cli
, fnum
, sinfo
);
1873 if (!py_tevent_req_wait_exc(self
, req
)) {
1876 status
= cli_query_security_descriptor_recv(req
, NULL
, &sd
);
1877 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1879 return py_return_ndr_struct(
1880 "samba.dcerpc.security", "descriptor", sd
, sd
);
1883 static PyObject
*py_smb_set_sd(struct py_cli_state
*self
, PyObject
*args
)
1885 PyObject
*py_sd
= NULL
;
1886 struct tevent_req
*req
= NULL
;
1887 struct security_descriptor
*sd
= NULL
;
1892 if (!PyArg_ParseTuple(args
, "iOI:set_sd", &fnum
, &py_sd
, &sinfo
)) {
1896 sd
= pytalloc_get_type(py_sd
, struct security_descriptor
);
1898 PyErr_Format(PyExc_TypeError
,
1899 "Expected dcerpc.security.descriptor as argument, got %s",
1900 pytalloc_get_name(py_sd
));
1904 req
= cli_set_security_descriptor_send(
1905 NULL
, self
->ev
, self
->cli
, fnum
, sinfo
, sd
);
1906 if (!py_tevent_req_wait_exc(self
, req
)) {
1910 status
= cli_set_security_descriptor_recv(req
);
1911 PyErr_NTSTATUS_NOT_OK_RAISE(status
);
1916 static PyMethodDef py_cli_state_methods
[] = {
1917 { "settimeout", (PyCFunction
)py_cli_settimeout
, METH_VARARGS
,
1918 "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
1919 { "echo", (PyCFunction
)py_cli_echo
, METH_NOARGS
,
1920 "Ping the server connection" },
1921 { "create", PY_DISCARD_FUNC_SIG(PyCFunction
, py_cli_create
),
1922 METH_VARARGS
|METH_KEYWORDS
,
1924 { "close", (PyCFunction
)py_cli_close
, METH_VARARGS
,
1925 "Close a file handle" },
1926 { "write", PY_DISCARD_FUNC_SIG(PyCFunction
, py_cli_write
),
1927 METH_VARARGS
|METH_KEYWORDS
,
1928 "Write to a file handle" },
1929 { "read", PY_DISCARD_FUNC_SIG(PyCFunction
, py_cli_read
),
1930 METH_VARARGS
|METH_KEYWORDS
,
1931 "Read from a file handle" },
1932 { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction
,
1934 METH_VARARGS
|METH_KEYWORDS
,
1935 "Truncate a file" },
1936 { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction
,
1937 py_cli_delete_on_close
),
1938 METH_VARARGS
|METH_KEYWORDS
,
1939 "Set/Reset the delete on close flag" },
1940 { "notify", PY_DISCARD_FUNC_SIG(PyCFunction
, py_cli_notify
),
1941 METH_VARARGS
|METH_KEYWORDS
,
1942 "Wait for change notifications: \n"
1943 "notify(fnum, buffer_size, completion_filter...) -> "
1944 "libsmb_samba_internal.Notify request handle\n" },
1945 { "list", PY_DISCARD_FUNC_SIG(PyCFunction
, py_cli_list
),
1946 METH_VARARGS
|METH_KEYWORDS
,
1947 "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
1948 "directory contents as a dictionary\n"
1949 "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
1950 "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
1951 "\t\tList contents of a directory. The keys are, \n"
1952 "\t\t\tname: Long name of the directory item\n"
1953 "\t\t\tshort_name: Short name of the directory item\n"
1954 "\t\t\tsize: File size in bytes\n"
1955 "\t\t\tattrib: Attributes\n"
1956 "\t\t\tmtime: Modification time\n" },
1957 { "get_oplock_break", (PyCFunction
)py_cli_get_oplock_break
,
1958 METH_VARARGS
, "Wait for an oplock break" },
1959 { "unlink", (PyCFunction
)py_smb_unlink
,
1961 "unlink(path) -> None\n\n \t\tDelete a file." },
1962 { "mkdir", (PyCFunction
)py_smb_mkdir
, METH_VARARGS
,
1963 "mkdir(path) -> None\n\n \t\tCreate a directory." },
1964 { "posix_whoami", (PyCFunction
)py_smb_posix_whoami
, METH_NOARGS
,
1965 "posix_whoami() -> (uid, gid, gids, sids, guest)" },
1966 { "rmdir", (PyCFunction
)py_smb_rmdir
, METH_VARARGS
,
1967 "rmdir(path) -> None\n\n \t\tDelete a directory." },
1969 PY_DISCARD_FUNC_SIG(PyCFunction
, py_cli_rename
),
1970 METH_VARARGS
|METH_KEYWORDS
,
1971 "rename(src,dst) -> None\n\n \t\tRename a file." },
1972 { "chkpath", (PyCFunction
)py_smb_chkpath
, METH_VARARGS
,
1973 "chkpath(dir_path) -> True or False\n\n"
1974 "\t\tReturn true if directory exists, false otherwise." },
1975 { "savefile", (PyCFunction
)py_smb_savefile
, METH_VARARGS
,
1976 "savefile(path, bytes) -> None\n\n"
1977 "\t\tWrite bytes to file." },
1978 { "loadfile", (PyCFunction
)py_smb_loadfile
, METH_VARARGS
,
1979 "loadfile(path) -> file contents as a bytes object"
1980 "\n\n\t\tRead contents of a file." },
1981 { "get_sd", (PyCFunction
)py_smb_get_sd
, METH_VARARGS
,
1982 "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
1983 "\t\tGet security descriptor for opened file." },
1984 { "set_sd", (PyCFunction
)py_smb_set_sd
, METH_VARARGS
,
1985 "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
1986 "\t\tSet security descriptor for opened file." },
1988 (PyCFunction
)py_smb_have_posix
,
1990 "have_posix() -> True/False\n\n"
1991 "\t\tReturn if the server has posix extensions"
1993 { NULL
, NULL
, 0, NULL
}
1996 static PyTypeObject py_cli_state_type
= {
1997 PyVarObject_HEAD_INIT(NULL
, 0)
1998 .tp_name
= "libsmb_samba_cwrapper.LibsmbCConn",
1999 .tp_basicsize
= sizeof(struct py_cli_state
),
2000 .tp_flags
= Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
,
2001 .tp_doc
= "libsmb cwrapper connection",
2002 .tp_new
= py_cli_state_new
,
2003 .tp_init
= (initproc
)py_cli_state_init
,
2004 .tp_dealloc
= (destructor
)py_cli_state_dealloc
,
2005 .tp_methods
= py_cli_state_methods
,
2008 static PyMethodDef py_libsmb_methods
[] = {
2012 void initlibsmb_samba_cwrapper(void);
2014 static struct PyModuleDef moduledef
= {
2015 PyModuleDef_HEAD_INIT
,
2016 .m_name
= "libsmb_samba_cwrapper",
2017 .m_doc
= "libsmb wrapper",
2019 .m_methods
= py_libsmb_methods
,
2022 MODULE_INIT_FUNC(libsmb_samba_cwrapper
)
2025 PyObject
*mod
= NULL
;
2027 talloc_stackframe();
2029 if (PyType_Ready(&py_cli_state_type
) < 0) {
2032 if (PyType_Ready(&py_cli_notify_state_type
) < 0) {
2036 m
= PyModule_Create(&moduledef
);
2041 /* Import dom_sid type from dcerpc.security */
2042 mod
= PyImport_ImportModule("samba.dcerpc.security");
2047 dom_sid_Type
= (PyTypeObject
*)PyObject_GetAttrString(mod
, "dom_sid");
2048 if (dom_sid_Type
== NULL
) {
2053 Py_INCREF(&py_cli_state_type
);
2054 PyModule_AddObject(m
, "LibsmbCConn", (PyObject
*)&py_cli_state_type
);
2056 #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
2058 ADD_FLAGS(FILE_ATTRIBUTE_READONLY
);
2059 ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN
);
2060 ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM
);
2061 ADD_FLAGS(FILE_ATTRIBUTE_VOLUME
);
2062 ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY
);
2063 ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE
);
2064 ADD_FLAGS(FILE_ATTRIBUTE_DEVICE
);
2065 ADD_FLAGS(FILE_ATTRIBUTE_NORMAL
);
2066 ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY
);
2067 ADD_FLAGS(FILE_ATTRIBUTE_SPARSE
);
2068 ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT
);
2069 ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED
);
2070 ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE
);
2071 ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED
);
2072 ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED
);
2073 ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK
);
2075 ADD_FLAGS(FILE_SHARE_READ
);
2076 ADD_FLAGS(FILE_SHARE_WRITE
);
2077 ADD_FLAGS(FILE_SHARE_DELETE
);
2079 /* change notify completion filter flags */
2080 ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME
);
2081 ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME
);
2082 ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES
);
2083 ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE
);
2084 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE
);
2085 ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS
);
2086 ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION
);
2087 ADD_FLAGS(FILE_NOTIFY_CHANGE_EA
);
2088 ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY
);
2089 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME
);
2090 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE
);
2091 ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE
);
2092 ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME
);
2093 ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL
);
2095 /* change notify action results */
2096 ADD_FLAGS(NOTIFY_ACTION_ADDED
);
2097 ADD_FLAGS(NOTIFY_ACTION_REMOVED
);
2098 ADD_FLAGS(NOTIFY_ACTION_MODIFIED
);
2099 ADD_FLAGS(NOTIFY_ACTION_OLD_NAME
);
2100 ADD_FLAGS(NOTIFY_ACTION_NEW_NAME
);
2101 ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM
);
2102 ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM
);
2103 ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM
);
2105 #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
2107 ADD_STRING(SMB2_CREATE_TAG_EXTA
);
2108 ADD_STRING(SMB2_CREATE_TAG_MXAC
);
2109 ADD_STRING(SMB2_CREATE_TAG_SECD
);
2110 ADD_STRING(SMB2_CREATE_TAG_DHNQ
);
2111 ADD_STRING(SMB2_CREATE_TAG_DHNC
);
2112 ADD_STRING(SMB2_CREATE_TAG_ALSI
);
2113 ADD_STRING(SMB2_CREATE_TAG_TWRP
);
2114 ADD_STRING(SMB2_CREATE_TAG_QFID
);
2115 ADD_STRING(SMB2_CREATE_TAG_RQLS
);
2116 ADD_STRING(SMB2_CREATE_TAG_DH2Q
);
2117 ADD_STRING(SMB2_CREATE_TAG_DH2C
);
2118 ADD_STRING(SMB2_CREATE_TAG_AAPL
);
2119 ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID
);
2120 ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT
);
2121 ADD_STRING(SMB2_CREATE_TAG_POSIX
);