LCOV - code coverage report
Current view: top level - source3/libsmb - pylibsmb.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 507 877 57.8 %
Date: 2024-06-13 04:01:37 Functions: 34 48 70.8 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *
       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.
       7             :  *
       8             :  * Copyright (C) Volker Lendecke 2012
       9             :  *
      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.
      14             :  *
      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.
      19             :  *
      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/>.
      22             : */
      23             : 
      24             : #include <Python.h>
      25             : #include "includes.h"
      26             : #include "python/py3compat.h"
      27             : #include "python/modules.h"
      28             : #include "libcli/smb/smbXcli_base.h"
      29             : #include "libsmb/libsmb.h"
      30             : #include "libcli/security/security.h"
      31             : #include "system/select.h"
      32             : #include "source4/libcli/util/pyerrors.h"
      33             : #include "auth/credentials/pycredentials.h"
      34             : #include "trans2.h"
      35             : #include "libsmb/clirap.h"
      36             : #include "librpc/rpc/pyrpc_util.h"
      37             : 
      38             : #define LIST_ATTRIBUTE_MASK \
      39             :         (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
      40             : 
      41             : static PyTypeObject *dom_sid_Type = NULL;
      42             : 
      43         689 : static PyTypeObject *get_pytype(const char *module, const char *type)
      44             : {
      45             :         PyObject *mod;
      46             :         PyTypeObject *result;
      47             : 
      48         689 :         mod = PyImport_ImportModule(module);
      49         689 :         if (mod == NULL) {
      50           0 :                 PyErr_Format(PyExc_RuntimeError,
      51             :                              "Unable to import %s to check type %s",
      52             :                              module, type);
      53           0 :                 return NULL;
      54             :         }
      55         689 :         result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
      56         689 :         Py_DECREF(mod);
      57         689 :         if (result == NULL) {
      58           0 :                 PyErr_Format(PyExc_RuntimeError,
      59             :                              "Unable to find type %s in module %s",
      60             :                              module, type);
      61           0 :                 return NULL;
      62             :         }
      63         689 :         return result;
      64             : }
      65             : 
      66             : /*
      67             :  * We're using "const char * const *" for keywords,
      68             :  * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
      69             :  * inevitable warnings to just one place.
      70             :  */
      71        3870 : static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
      72             :                                  const char *format, const char * const *keywords,
      73             :                                  ...)
      74             : {
      75        3870 :         char **_keywords = discard_const_p(char *, keywords);
      76             :         va_list a;
      77             :         int ret;
      78        3870 :         va_start(a, keywords);
      79        3870 :         ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
      80             :                                             _keywords, a);
      81        3870 :         va_end(a);
      82        3870 :         return ret;
      83             : }
      84             : 
      85             : struct py_cli_thread;
      86             : 
      87             : struct py_cli_oplock_break {
      88             :         uint16_t fnum;
      89             :         uint8_t level;
      90             : };
      91             : 
      92             : struct py_cli_state {
      93             :         PyObject_HEAD
      94             :         struct cli_state *cli;
      95             :         struct tevent_context *ev;
      96             :         int (*req_wait_fn)(struct tevent_context *ev,
      97             :                            struct tevent_req *req);
      98             :         struct py_cli_thread *thread_state;
      99             : 
     100             :         struct tevent_req *oplock_waiter;
     101             :         struct py_cli_oplock_break *oplock_breaks;
     102             :         struct py_tevent_cond *oplock_cond;
     103             : };
     104             : 
     105             : #ifdef HAVE_PTHREAD
     106             : 
     107             : #include <pthread.h>
     108             : 
     109             : struct py_cli_thread {
     110             : 
     111             :         /*
     112             :          * Pipe to make the poll thread wake up in our destructor, so
     113             :          * that we can exit and join the thread.
     114             :          */
     115             :         int shutdown_pipe[2];
     116             :         struct tevent_fd *shutdown_fde;
     117             :         bool do_shutdown;
     118             :         pthread_t id;
     119             : 
     120             :         /*
     121             :          * Thread state to release the GIL during the poll(2) syscall
     122             :          */
     123             :         PyThreadState *py_threadstate;
     124             : };
     125             : 
     126           0 : static void *py_cli_state_poll_thread(void *private_data)
     127             : {
     128           0 :         struct py_cli_state *self = (struct py_cli_state *)private_data;
     129           0 :         struct py_cli_thread *t = self->thread_state;
     130             :         PyGILState_STATE gstate;
     131             : 
     132           0 :         gstate = PyGILState_Ensure();
     133             : 
     134           0 :         while (!t->do_shutdown) {
     135             :                 int ret;
     136           0 :                 ret = tevent_loop_once(self->ev);
     137           0 :                 assert(ret == 0);
     138             :         }
     139           0 :         PyGILState_Release(gstate);
     140           0 :         return NULL;
     141             : }
     142             : 
     143           0 : static void py_cli_state_trace_callback(enum tevent_trace_point point,
     144             :                                         void *private_data)
     145             : {
     146           0 :         struct py_cli_state *self = (struct py_cli_state *)private_data;
     147           0 :         struct py_cli_thread *t = self->thread_state;
     148             : 
     149           0 :         switch(point) {
     150           0 :         case TEVENT_TRACE_BEFORE_WAIT:
     151           0 :                 assert(t->py_threadstate == NULL);
     152           0 :                 t->py_threadstate = PyEval_SaveThread();
     153           0 :                 break;
     154           0 :         case TEVENT_TRACE_AFTER_WAIT:
     155           0 :                 assert(t->py_threadstate != NULL);
     156           0 :                 PyEval_RestoreThread(t->py_threadstate);
     157           0 :                 t->py_threadstate = NULL;
     158           0 :                 break;
     159           0 :         default:
     160           0 :                 break;
     161             :         }
     162           0 : }
     163             : 
     164           0 : static void py_cli_state_shutdown_handler(struct tevent_context *ev,
     165             :                                           struct tevent_fd *fde,
     166             :                                           uint16_t flags,
     167             :                                           void *private_data)
     168             : {
     169           0 :         struct py_cli_state *self = (struct py_cli_state *)private_data;
     170           0 :         struct py_cli_thread *t = self->thread_state;
     171             : 
     172           0 :         if ((flags & TEVENT_FD_READ) == 0) {
     173           0 :                 return;
     174             :         }
     175           0 :         TALLOC_FREE(t->shutdown_fde);
     176           0 :         t->do_shutdown = true;
     177             : }
     178             : 
     179           0 : static int py_cli_thread_destructor(struct py_cli_thread *t)
     180             : {
     181           0 :         char c = 0;
     182             :         ssize_t written;
     183             :         int ret;
     184             : 
     185             :         do {
     186             :                 /*
     187             :                  * This will wake the poll thread from the poll(2)
     188             :                  */
     189           0 :                 written = write(t->shutdown_pipe[1], &c, 1);
     190           0 :         } while ((written == -1) && (errno == EINTR));
     191             : 
     192             :         /*
     193             :          * Allow the poll thread to do its own cleanup under the GIL
     194             :          */
     195           0 :         Py_BEGIN_ALLOW_THREADS
     196           0 :         ret = pthread_join(t->id, NULL);
     197           0 :         Py_END_ALLOW_THREADS
     198           0 :         assert(ret == 0);
     199             : 
     200           0 :         if (t->shutdown_pipe[0] != -1) {
     201           0 :                 close(t->shutdown_pipe[0]);
     202           0 :                 t->shutdown_pipe[0] = -1;
     203             :         }
     204           0 :         if (t->shutdown_pipe[1] != -1) {
     205           0 :                 close(t->shutdown_pipe[1]);
     206           0 :                 t->shutdown_pipe[1] = -1;
     207             :         }
     208           0 :         return 0;
     209             : }
     210             : 
     211             : static int py_tevent_cond_req_wait(struct tevent_context *ev,
     212             :                                    struct tevent_req *req);
     213             : 
     214           0 : static bool py_cli_state_setup_mt_ev(struct py_cli_state *self)
     215             : {
     216           0 :         struct py_cli_thread *t = NULL;
     217             :         int ret;
     218             : 
     219           0 :         self->ev = tevent_context_init_byname(NULL, "poll_mt");
     220           0 :         if (self->ev == NULL) {
     221           0 :                 goto fail;
     222             :         }
     223           0 :         samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
     224           0 :         tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
     225             : 
     226           0 :         self->req_wait_fn = py_tevent_cond_req_wait;
     227             : 
     228           0 :         self->thread_state = talloc_zero(NULL, struct py_cli_thread);
     229           0 :         if (self->thread_state == NULL) {
     230           0 :                 goto fail;
     231             :         }
     232           0 :         t = self->thread_state;
     233             : 
     234           0 :         ret = pipe(t->shutdown_pipe);
     235           0 :         if (ret == -1) {
     236           0 :                 goto fail;
     237             :         }
     238           0 :         t->shutdown_fde = tevent_add_fd(
     239             :                 self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ,
     240             :                 py_cli_state_shutdown_handler, self);
     241           0 :         if (t->shutdown_fde == NULL) {
     242           0 :                 goto fail;
     243             :         }
     244             : 
     245           0 :         PyEval_InitThreads();
     246             : 
     247           0 :         ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
     248           0 :         if (ret != 0) {
     249           0 :                 goto fail;
     250             :         }
     251           0 :         talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
     252           0 :         return true;
     253             : 
     254           0 : fail:
     255           0 :         if (t != NULL) {
     256           0 :                 TALLOC_FREE(t->shutdown_fde);
     257             : 
     258           0 :                 if (t->shutdown_pipe[0] != -1) {
     259           0 :                         close(t->shutdown_pipe[0]);
     260           0 :                         t->shutdown_pipe[0] = -1;
     261             :                 }
     262           0 :                 if (t->shutdown_pipe[1] != -1) {
     263           0 :                         close(t->shutdown_pipe[1]);
     264           0 :                         t->shutdown_pipe[1] = -1;
     265             :                 }
     266             :         }
     267             : 
     268           0 :         TALLOC_FREE(self->thread_state);
     269           0 :         TALLOC_FREE(self->ev);
     270           0 :         return false;
     271             : }
     272             : 
     273             : struct py_tevent_cond {
     274             :         pthread_mutex_t mutex;
     275             :         pthread_cond_t cond;
     276             :         bool is_done;
     277             : };
     278             : 
     279             : static void py_tevent_signalme(struct tevent_req *req);
     280             : 
     281           0 : static int py_tevent_cond_wait(struct py_tevent_cond *cond)
     282             : {
     283             :         int ret, result;
     284             : 
     285           0 :         result = pthread_mutex_init(&cond->mutex, NULL);
     286           0 :         if (result != 0) {
     287           0 :                 goto fail;
     288             :         }
     289           0 :         result = pthread_cond_init(&cond->cond, NULL);
     290           0 :         if (result != 0) {
     291           0 :                 goto fail_mutex;
     292             :         }
     293             : 
     294           0 :         result = pthread_mutex_lock(&cond->mutex);
     295           0 :         if (result != 0) {
     296           0 :                 goto fail_cond;
     297             :         }
     298             : 
     299           0 :         cond->is_done = false;
     300             : 
     301           0 :         while (!cond->is_done) {
     302             : 
     303           0 :                 Py_BEGIN_ALLOW_THREADS
     304           0 :                 result = pthread_cond_wait(&cond->cond, &cond->mutex);
     305           0 :                 Py_END_ALLOW_THREADS
     306             : 
     307           0 :                 if (result != 0) {
     308           0 :                         goto fail_unlock;
     309             :                 }
     310             :         }
     311             : 
     312           0 : fail_unlock:
     313           0 :         ret = pthread_mutex_unlock(&cond->mutex);
     314           0 :         assert(ret == 0);
     315           0 : fail_cond:
     316           0 :         ret = pthread_cond_destroy(&cond->cond);
     317           0 :         assert(ret == 0);
     318           0 : fail_mutex:
     319           0 :         ret = pthread_mutex_destroy(&cond->mutex);
     320           0 :         assert(ret == 0);
     321           0 : fail:
     322           0 :         return result;
     323             : }
     324             : 
     325           0 : static int py_tevent_cond_req_wait(struct tevent_context *ev,
     326             :                                    struct tevent_req *req)
     327             : {
     328             :         struct py_tevent_cond cond;
     329           0 :         tevent_req_set_callback(req, py_tevent_signalme, &cond);
     330           0 :         return py_tevent_cond_wait(&cond);
     331             : }
     332             : 
     333           0 : static void py_tevent_cond_signal(struct py_tevent_cond *cond)
     334             : {
     335             :         int ret;
     336             : 
     337           0 :         ret = pthread_mutex_lock(&cond->mutex);
     338           0 :         assert(ret == 0);
     339             : 
     340           0 :         cond->is_done = true;
     341             : 
     342           0 :         ret = pthread_cond_signal(&cond->cond);
     343           0 :         assert(ret == 0);
     344           0 :         ret = pthread_mutex_unlock(&cond->mutex);
     345           0 :         assert(ret == 0);
     346           0 : }
     347             : 
     348           0 : static void py_tevent_signalme(struct tevent_req *req)
     349             : {
     350           0 :         struct py_tevent_cond *cond = (struct py_tevent_cond *)
     351           0 :                 tevent_req_callback_data_void(req);
     352             : 
     353           0 :         py_tevent_cond_signal(cond);
     354           0 : }
     355             : 
     356             : #endif
     357             : 
     358             : static int py_tevent_req_wait(struct tevent_context *ev,
     359             :                               struct tevent_req *req);
     360             : 
     361         689 : static bool py_cli_state_setup_ev(struct py_cli_state *self)
     362             : {
     363         689 :         self->ev = tevent_context_init(NULL);
     364         689 :         if (self->ev == NULL) {
     365           0 :                 return false;
     366             :         }
     367             : 
     368         689 :         samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
     369             : 
     370         689 :         self->req_wait_fn = py_tevent_req_wait;
     371             : 
     372         689 :         return true;
     373             : }
     374             : 
     375       13723 : static int py_tevent_req_wait(struct tevent_context *ev,
     376             :                               struct tevent_req *req)
     377             : {
     378      150954 :         while (tevent_req_is_in_progress(req)) {
     379             :                 int ret;
     380             : 
     381      124020 :                 ret = tevent_loop_once(ev);
     382      124020 :                 if (ret != 0) {
     383           0 :                         return ret;
     384             :                 }
     385             :         }
     386       13723 :         return 0;
     387             : }
     388             : 
     389       13723 : static bool py_tevent_req_wait_exc(struct py_cli_state *self,
     390             :                                    struct tevent_req *req)
     391             : {
     392             :         int ret;
     393             : 
     394       13723 :         if (req == NULL) {
     395           0 :                 PyErr_NoMemory();
     396           0 :                 return false;
     397             :         }
     398       13723 :         ret = self->req_wait_fn(self->ev, req);
     399       13723 :         if (ret != 0) {
     400           0 :                 TALLOC_FREE(req);
     401           0 :                 errno = ret;
     402           0 :                 PyErr_SetFromErrno(PyExc_RuntimeError);
     403           0 :                 return false;
     404             :         }
     405       13723 :         return true;
     406             : }
     407             : 
     408         689 : static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
     409             :                                   PyObject *kwds)
     410             : {
     411             :         struct py_cli_state *self;
     412             : 
     413         689 :         self = (struct py_cli_state *)type->tp_alloc(type, 0);
     414         689 :         if (self == NULL) {
     415           0 :                 return NULL;
     416             :         }
     417         689 :         self->cli = NULL;
     418         689 :         self->ev = NULL;
     419         689 :         self->thread_state = NULL;
     420         689 :         self->oplock_waiter = NULL;
     421         689 :         self->oplock_cond = NULL;
     422         689 :         self->oplock_breaks = NULL;
     423         689 :         return (PyObject *)self;
     424             : }
     425             : 
     426             : static void py_cli_got_oplock_break(struct tevent_req *req);
     427             : 
     428         689 : static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
     429             :                              PyObject *kwds)
     430             : {
     431             :         NTSTATUS status;
     432             :         char *host, *share;
     433         689 :         PyObject *creds = NULL;
     434             :         struct cli_credentials *cli_creds;
     435         689 :         PyObject *py_lp = Py_None;
     436         689 :         PyObject *py_multi_threaded = Py_False;
     437         689 :         bool multi_threaded = false;
     438         689 :         PyObject *py_force_smb1 = Py_False;
     439         689 :         bool force_smb1 = false;
     440         689 :         PyObject *py_ipc = Py_False;
     441         689 :         bool use_ipc = false;
     442             :         struct tevent_req *req;
     443             :         bool ret;
     444         689 :         int flags = 0;
     445             : 
     446             :         static const char *kwlist[] = {
     447             :                 "host", "share", "lp", "creds",
     448             :                 "multi_threaded", "force_smb1",
     449             :                 "ipc",
     450             :                 NULL
     451             :         };
     452             : 
     453         689 :         PyTypeObject *py_type_Credentials = get_pytype(
     454             :                 "samba.credentials", "Credentials");
     455         689 :         if (py_type_Credentials == NULL) {
     456           0 :                 return -1;
     457             :         }
     458             : 
     459         689 :         ret = ParseTupleAndKeywords(
     460             :                 args, kwds, "ssO|O!OOO", kwlist,
     461             :                 &host, &share, &py_lp,
     462             :                 py_type_Credentials, &creds,
     463             :                 &py_multi_threaded,
     464             :                 &py_force_smb1,
     465             :                 &py_ipc);
     466             : 
     467         689 :         Py_DECREF(py_type_Credentials);
     468             : 
     469         689 :         if (!ret) {
     470           0 :                 return -1;
     471             :         }
     472             : 
     473         689 :         multi_threaded = PyObject_IsTrue(py_multi_threaded);
     474         689 :         force_smb1 = PyObject_IsTrue(py_force_smb1);
     475             : 
     476         689 :         if (force_smb1) {
     477             :                 /*
     478             :                  * As most of the cli_*_send() function
     479             :                  * don't support SMB2 (it's only plugged
     480             :                  * into the sync wrapper functions currently)
     481             :                  * we have a way to force SMB1.
     482             :                  */
     483           3 :                 flags = CLI_FULL_CONNECTION_FORCE_SMB1;
     484             :         }
     485             : 
     486         689 :         use_ipc = PyObject_IsTrue(py_ipc);
     487         689 :         if (use_ipc) {
     488          39 :                 flags |= CLI_FULL_CONNECTION_IPC;
     489             :         }
     490             : 
     491         689 :         if (multi_threaded) {
     492             : #ifdef HAVE_PTHREAD
     493           0 :                 ret = py_cli_state_setup_mt_ev(self);
     494           0 :                 if (!ret) {
     495           0 :                         return -1;
     496             :                 }
     497             : #else
     498             :                 PyErr_SetString(PyExc_RuntimeError,
     499             :                                 "No PTHREAD support available");
     500             :                 return -1;
     501             : #endif
     502             :         } else {
     503         689 :                 ret = py_cli_state_setup_ev(self);
     504         689 :                 if (!ret) {
     505           0 :                         return -1;
     506             :                 }
     507             :         }
     508             : 
     509         689 :         if (creds == NULL) {
     510           0 :                 cli_creds = cli_credentials_init_anon(NULL);
     511             :         } else {
     512         689 :                 cli_creds = PyCredentials_AsCliCredentials(creds);
     513             :         }
     514             : 
     515         689 :         req = cli_full_connection_creds_send(
     516             :                 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
     517             :                 cli_creds, flags);
     518         689 :         if (!py_tevent_req_wait_exc(self, req)) {
     519           0 :                 return -1;
     520             :         }
     521         689 :         status = cli_full_connection_creds_recv(req, &self->cli);
     522         689 :         TALLOC_FREE(req);
     523             : 
     524         689 :         if (!NT_STATUS_IS_OK(status)) {
     525          20 :                 PyErr_SetNTSTATUS(status);
     526          20 :                 return -1;
     527             :         }
     528             : 
     529             :         /*
     530             :          * Oplocks require a multi threaded connection
     531             :          */
     532         669 :         if (self->thread_state == NULL) {
     533         669 :                 return 0;
     534             :         }
     535             : 
     536           0 :         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
     537           0 :                 self->ev, self->ev, self->cli);
     538           0 :         if (self->oplock_waiter == NULL) {
     539           0 :                 PyErr_NoMemory();
     540           0 :                 return -1;
     541             :         }
     542           0 :         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
     543             :                                 self);
     544           0 :         return 0;
     545             : }
     546             : 
     547           0 : static void py_cli_got_oplock_break(struct tevent_req *req)
     548             : {
     549           0 :         struct py_cli_state *self = (struct py_cli_state *)
     550           0 :                 tevent_req_callback_data_void(req);
     551             :         struct py_cli_oplock_break b;
     552             :         struct py_cli_oplock_break *tmp;
     553             :         size_t num_breaks;
     554             :         NTSTATUS status;
     555             : 
     556           0 :         status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
     557           0 :         TALLOC_FREE(req);
     558           0 :         self->oplock_waiter = NULL;
     559             : 
     560           0 :         if (!NT_STATUS_IS_OK(status)) {
     561           0 :                 return;
     562             :         }
     563             : 
     564           0 :         num_breaks = talloc_array_length(self->oplock_breaks);
     565           0 :         tmp = talloc_realloc(self->ev, self->oplock_breaks,
     566             :                              struct py_cli_oplock_break, num_breaks+1);
     567           0 :         if (tmp == NULL) {
     568           0 :                 return;
     569             :         }
     570           0 :         self->oplock_breaks = tmp;
     571           0 :         self->oplock_breaks[num_breaks] = b;
     572             : 
     573           0 :         if (self->oplock_cond != NULL) {
     574           0 :                 py_tevent_cond_signal(self->oplock_cond);
     575             :         }
     576             : 
     577           0 :         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
     578           0 :                 self->ev, self->ev, self->cli);
     579           0 :         if (self->oplock_waiter == NULL) {
     580           0 :                 return;
     581             :         }
     582           0 :         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
     583             :                                 self);
     584             : }
     585             : 
     586           0 : static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
     587             :                                          PyObject *args)
     588             : {
     589             :         size_t num_oplock_breaks;
     590             : 
     591           0 :         if (!PyArg_ParseTuple(args, "")) {
     592           0 :                 return NULL;
     593             :         }
     594             : 
     595           0 :         if (self->thread_state == NULL) {
     596           0 :                 PyErr_SetString(PyExc_RuntimeError,
     597             :                                 "get_oplock_break() only possible on "
     598             :                                 "a multi_threaded connection");
     599           0 :                 return NULL;
     600             :         }
     601             : 
     602           0 :         if (self->oplock_cond != NULL) {
     603           0 :                 errno = EBUSY;
     604           0 :                 PyErr_SetFromErrno(PyExc_RuntimeError);
     605           0 :                 return NULL;
     606             :         }
     607             : 
     608           0 :         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
     609             : 
     610           0 :         if (num_oplock_breaks == 0) {
     611             :                 struct py_tevent_cond cond;
     612             :                 int ret;
     613             : 
     614           0 :                 self->oplock_cond = &cond;
     615           0 :                 ret = py_tevent_cond_wait(&cond);
     616           0 :                 self->oplock_cond = NULL;
     617             : 
     618           0 :                 if (ret != 0) {
     619           0 :                         errno = ret;
     620           0 :                         PyErr_SetFromErrno(PyExc_RuntimeError);
     621           0 :                         return NULL;
     622             :                 }
     623             :         }
     624             : 
     625           0 :         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
     626           0 :         if (num_oplock_breaks > 0) {
     627             :                 PyObject *result;
     628             : 
     629           0 :                 result = Py_BuildValue(
     630             :                         "{s:i,s:i}",
     631           0 :                         "fnum", self->oplock_breaks[0].fnum,
     632           0 :                         "level", self->oplock_breaks[0].level);
     633             : 
     634           0 :                 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
     635             :                         sizeof(self->oplock_breaks[0]) *
     636           0 :                         (num_oplock_breaks - 1));
     637           0 :                 self->oplock_breaks = talloc_realloc(
     638             :                         NULL, self->oplock_breaks, struct py_cli_oplock_break,
     639             :                         num_oplock_breaks - 1);
     640             : 
     641           0 :                 return result;
     642             :         }
     643           0 :         Py_RETURN_NONE;
     644             : }
     645             : 
     646         689 : static void py_cli_state_dealloc(struct py_cli_state *self)
     647             : {
     648         689 :         TALLOC_FREE(self->thread_state);
     649         689 :         TALLOC_FREE(self->oplock_waiter);
     650         689 :         TALLOC_FREE(self->ev);
     651             : 
     652         689 :         if (self->cli != NULL) {
     653         669 :                 cli_shutdown(self->cli);
     654         669 :                 self->cli = NULL;
     655             :         }
     656         689 :         Py_TYPE(self)->tp_free((PyObject *)self);
     657         689 : }
     658             : 
     659         495 : static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
     660             : {
     661         495 :         unsigned int nmsecs = 0;
     662         495 :         unsigned int omsecs = 0;
     663             : 
     664         495 :         if (!PyArg_ParseTuple(args, "I", &nmsecs)) {
     665           0 :                 return NULL;
     666             :         }
     667             : 
     668         495 :         omsecs = cli_set_timeout(self->cli, nmsecs);
     669             : 
     670         495 :         return PyLong_FromLong(omsecs);
     671             : }
     672             : 
     673          48 : static PyObject *py_cli_echo(struct py_cli_state *self,
     674             :                              PyObject *Py_UNUSED(ignored))
     675             : {
     676          48 :         DATA_BLOB data = data_blob_string_const("keepalive");
     677          48 :         struct tevent_req *req = NULL;
     678             :         NTSTATUS status;
     679             : 
     680          48 :         req = cli_echo_send(NULL, self->ev, self->cli, 1, data);
     681          48 :         if (!py_tevent_req_wait_exc(self, req)) {
     682           0 :                 return NULL;
     683             :         }
     684          48 :         status = cli_echo_recv(req);
     685          48 :         TALLOC_FREE(req);
     686          48 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
     687             : 
     688          48 :         Py_RETURN_NONE;
     689             : }
     690             : 
     691         523 : static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
     692             :                                PyObject *kwds)
     693             : {
     694             :         char *fname;
     695         523 :         unsigned CreateFlags = 0;
     696         523 :         unsigned DesiredAccess = FILE_GENERIC_READ;
     697         523 :         unsigned FileAttributes = 0;
     698         523 :         unsigned ShareAccess = 0;
     699         523 :         unsigned CreateDisposition = FILE_OPEN;
     700         523 :         unsigned CreateOptions = 0;
     701         523 :         unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
     702         523 :         unsigned SecurityFlags = 0;
     703             :         uint16_t fnum;
     704             :         struct tevent_req *req;
     705             :         NTSTATUS status;
     706             : 
     707             :         static const char *kwlist[] = {
     708             :                 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
     709             :                 "ShareAccess", "CreateDisposition", "CreateOptions",
     710             :                 "ImpersonationLevel", "SecurityFlags", NULL };
     711             : 
     712         523 :         if (!ParseTupleAndKeywords(
     713             :                     args, kwds, "s|IIIIIIII", kwlist,
     714             :                     &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
     715             :                     &ShareAccess, &CreateDisposition, &CreateOptions,
     716             :                     &ImpersonationLevel, &SecurityFlags)) {
     717           0 :                 return NULL;
     718             :         }
     719             : 
     720         523 :         req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
     721             :                                 DesiredAccess, FileAttributes, ShareAccess,
     722             :                                 CreateDisposition, CreateOptions,
     723             :                                 ImpersonationLevel, SecurityFlags);
     724         523 :         if (!py_tevent_req_wait_exc(self, req)) {
     725           0 :                 return NULL;
     726             :         }
     727         523 :         status = cli_ntcreate_recv(req, &fnum, NULL);
     728         523 :         TALLOC_FREE(req);
     729             : 
     730         523 :         if (!NT_STATUS_IS_OK(status)) {
     731           0 :                 PyErr_SetNTSTATUS(status);
     732           0 :                 return NULL;
     733             :         }
     734         523 :         return Py_BuildValue("I", (unsigned)fnum);
     735             : }
     736             : 
     737         523 : static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
     738             : {
     739             :         struct tevent_req *req;
     740             :         int fnum;
     741             :         NTSTATUS status;
     742             : 
     743         523 :         if (!PyArg_ParseTuple(args, "i", &fnum)) {
     744           0 :                 return NULL;
     745             :         }
     746             : 
     747         523 :         req = cli_close_send(NULL, self->ev, self->cli, fnum);
     748         523 :         if (!py_tevent_req_wait_exc(self, req)) {
     749           0 :                 return NULL;
     750             :         }
     751         523 :         status = cli_close_recv(req);
     752         523 :         TALLOC_FREE(req);
     753             : 
     754         523 :         if (!NT_STATUS_IS_OK(status)) {
     755           0 :                 PyErr_SetNTSTATUS(status);
     756           0 :                 return NULL;
     757             :         }
     758         523 :         Py_RETURN_NONE;
     759             : }
     760             : 
     761           0 : static PyObject *py_cli_rename(
     762             :         struct py_cli_state *self, PyObject *args, PyObject *kwds)
     763             : {
     764           0 :         char *fname_src = NULL, *fname_dst = NULL;
     765           0 :         int replace = false;
     766           0 :         struct tevent_req *req = NULL;
     767             :         NTSTATUS status;
     768             :         bool ok;
     769             : 
     770             :         static const char *kwlist[] = { "src", "dst", "replace", NULL };
     771             : 
     772           0 :         ok = ParseTupleAndKeywords(
     773             :                 args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
     774           0 :         if (!ok) {
     775           0 :                 return NULL;
     776             :         }
     777             : 
     778           0 :         req = cli_rename_send(
     779             :                 NULL, self->ev, self->cli, fname_src, fname_dst, replace);
     780           0 :         if (!py_tevent_req_wait_exc(self, req)) {
     781           0 :                 return NULL;
     782             :         }
     783           0 :         status = cli_rename_recv(req);
     784           0 :         TALLOC_FREE(req);
     785             : 
     786           0 :         if (!NT_STATUS_IS_OK(status)) {
     787           0 :                 PyErr_SetNTSTATUS(status);
     788           0 :                 return NULL;
     789             :         }
     790           0 :         Py_RETURN_NONE;
     791             : }
     792             : 
     793             : 
     794             : struct push_state {
     795             :         char *data;
     796             :         off_t nread;
     797             :         off_t total_data;
     798             : };
     799             : 
     800             : /*
     801             :  * cli_push() helper to write a chunk of data to a remote file
     802             :  */
     803        1068 : static size_t push_data(uint8_t *buf, size_t n, void *priv)
     804             : {
     805        1068 :         struct push_state *state = (struct push_state *)priv;
     806        1068 :         char *curr_ptr = NULL;
     807             :         off_t remaining;
     808             :         size_t copied_bytes;
     809             : 
     810        1068 :         if (state->nread >= state->total_data) {
     811         556 :                 return 0;
     812             :         }
     813             : 
     814         512 :         curr_ptr = state->data + state->nread;
     815         512 :         remaining = state->total_data - state->nread;
     816         512 :         copied_bytes = MIN(remaining, n);
     817             : 
     818         512 :         memcpy(buf, curr_ptr, copied_bytes);
     819         512 :         state->nread += copied_bytes;
     820         512 :         return copied_bytes;
     821             : }
     822             : 
     823             : /*
     824             :  * Writes a file with the contents specified
     825             :  */
     826         556 : static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
     827             : {
     828             :         uint16_t fnum;
     829         556 :         const char *filename = NULL;
     830         556 :         char *data = NULL;
     831         556 :         Py_ssize_t size = 0;
     832             :         NTSTATUS status;
     833         556 :         struct tevent_req *req = NULL;
     834             :         struct push_state state;
     835             : 
     836         556 :         if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
     837             :                               &data, &size)) {
     838           0 :                 return NULL;
     839             :         }
     840             : 
     841             :         /* create a new file handle for writing to */
     842         556 :         req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
     843             :                                 FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
     844             :                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
     845             :                                 FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
     846             :                                 SMB2_IMPERSONATION_IMPERSONATION, 0);
     847         556 :         if (!py_tevent_req_wait_exc(self, req)) {
     848           0 :                 return NULL;
     849             :         }
     850         556 :         status = cli_ntcreate_recv(req, &fnum, NULL);
     851         556 :         TALLOC_FREE(req);
     852         556 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
     853             : 
     854             :         /* write the new file contents */
     855         556 :         state.data = data;
     856         556 :         state.nread = 0;
     857         556 :         state.total_data = size;
     858             : 
     859         556 :         req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
     860             :                             push_data, &state);
     861         556 :         if (!py_tevent_req_wait_exc(self, req)) {
     862           0 :                 return NULL;
     863             :         }
     864         556 :         status = cli_push_recv(req);
     865         556 :         TALLOC_FREE(req);
     866         556 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
     867             : 
     868             :         /* close the file handle */
     869         556 :         req = cli_close_send(NULL, self->ev, self->cli, fnum);
     870         556 :         if (!py_tevent_req_wait_exc(self, req)) {
     871           0 :                 return NULL;
     872             :         }
     873         556 :         status = cli_close_recv(req);
     874         556 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
     875             : 
     876         556 :         Py_RETURN_NONE;
     877             : }
     878             : 
     879         492 : static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
     880             :                               PyObject *kwds)
     881             : {
     882             :         int fnum;
     883         492 :         unsigned mode = 0;
     884             :         char *buf;
     885             :         Py_ssize_t buflen;
     886             :         unsigned long long offset;
     887             :         struct tevent_req *req;
     888             :         NTSTATUS status;
     889             :         size_t written;
     890             : 
     891             :         static const char *kwlist[] = {
     892             :                 "fnum", "buffer", "offset", "mode", NULL };
     893             : 
     894         492 :         if (!ParseTupleAndKeywords(
     895             :                     args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
     896             :                     &fnum, &buf, &buflen, &offset, &mode)) {
     897           0 :                 return NULL;
     898             :         }
     899             : 
     900         492 :         req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
     901             :                              (uint8_t *)buf, offset, buflen);
     902         492 :         if (!py_tevent_req_wait_exc(self, req)) {
     903           0 :                 return NULL;
     904             :         }
     905         492 :         status = cli_write_recv(req, &written);
     906         492 :         TALLOC_FREE(req);
     907             : 
     908         492 :         if (!NT_STATUS_IS_OK(status)) {
     909           0 :                 PyErr_SetNTSTATUS(status);
     910           0 :                 return NULL;
     911             :         }
     912         492 :         return Py_BuildValue("K", (unsigned long long)written);
     913             : }
     914             : 
     915             : /*
     916             :  * Returns the size of the given file
     917             :  */
     918         468 : static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
     919             :                                 off_t *size)
     920             : {
     921             :         NTSTATUS status;
     922         468 :         struct tevent_req *req = NULL;
     923             : 
     924         468 :         req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
     925         468 :         if (!py_tevent_req_wait_exc(self, req)) {
     926           0 :                 return NT_STATUS_INTERNAL_ERROR;
     927             :         }
     928         468 :         status = cli_qfileinfo_basic_recv(
     929             :                 req, NULL, size, NULL, NULL, NULL, NULL, NULL);
     930         468 :         TALLOC_FREE(req);
     931         468 :         return status;
     932             : }
     933             : 
     934             : /*
     935             :  * Loads the specified file's contents and returns it
     936             :  */
     937         534 : static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
     938             : {
     939             :         NTSTATUS status;
     940         534 :         const char *filename = NULL;
     941         534 :         struct tevent_req *req = NULL;
     942             :         uint16_t fnum;
     943             :         off_t size;
     944         534 :         char *buf = NULL;
     945         534 :         off_t nread = 0;
     946         534 :         PyObject *result = NULL;
     947             : 
     948         534 :         if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
     949           0 :                 return NULL;
     950             :         }
     951             : 
     952             :         /* get a read file handle */
     953         534 :         req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
     954             :                                 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
     955             :                                 FILE_ATTRIBUTE_NORMAL,
     956             :                                 FILE_SHARE_READ, FILE_OPEN, 0,
     957             :                                 SMB2_IMPERSONATION_IMPERSONATION, 0);
     958         534 :         if (!py_tevent_req_wait_exc(self, req)) {
     959           0 :                 return NULL;
     960             :         }
     961         534 :         status = cli_ntcreate_recv(req, &fnum, NULL);
     962         534 :         TALLOC_FREE(req);
     963         534 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
     964             : 
     965             :         /* get a buffer to hold the file contents */
     966         468 :         status = py_smb_filesize(self, fnum, &size);
     967         468 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
     968             : 
     969         468 :         result = PyBytes_FromStringAndSize(NULL, size);
     970         468 :         if (result == NULL) {
     971           0 :                 return NULL;
     972             :         }
     973             : 
     974             :         /* read the file contents */
     975         468 :         buf = PyBytes_AS_STRING(result);
     976         468 :         req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
     977             :                             size, cli_read_sink, &buf);
     978         468 :         if (!py_tevent_req_wait_exc(self, req)) {
     979           0 :                 Py_XDECREF(result);
     980           0 :                 return NULL;
     981             :         }
     982         468 :         status = cli_pull_recv(req, &nread);
     983         468 :         TALLOC_FREE(req);
     984         468 :         if (!NT_STATUS_IS_OK(status)) {
     985           0 :                 Py_XDECREF(result);
     986           0 :                 PyErr_SetNTSTATUS(status);
     987           0 :                 return NULL;
     988             :         }
     989             : 
     990             :         /* close the file handle */
     991         468 :         req = cli_close_send(NULL, self->ev, self->cli, fnum);
     992         468 :         if (!py_tevent_req_wait_exc(self, req)) {
     993           0 :                 Py_XDECREF(result);
     994           0 :                 return NULL;
     995             :         }
     996         468 :         status = cli_close_recv(req);
     997         468 :         TALLOC_FREE(req);
     998         468 :         if (!NT_STATUS_IS_OK(status)) {
     999           0 :                 Py_XDECREF(result);
    1000           0 :                 PyErr_SetNTSTATUS(status);
    1001           0 :                 return NULL;
    1002             :         }
    1003             : 
    1004             :         /* sanity-check we read the expected number of bytes */
    1005         468 :         if (nread > size) {
    1006           0 :                 Py_XDECREF(result);
    1007           0 :                 PyErr_Format(PyExc_IOError,
    1008             :                              "read invalid - got %zu requested %zu",
    1009             :                              nread, size);
    1010           0 :                 return NULL;
    1011             :         }
    1012             : 
    1013         468 :         if (nread < size) {
    1014           0 :                 if (_PyBytes_Resize(&result, nread) < 0) {
    1015           0 :                         return NULL;
    1016             :                 }
    1017             :         }
    1018             : 
    1019         468 :         return result;
    1020             : }
    1021             : 
    1022         495 : static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
    1023             :                              PyObject *kwds)
    1024             : {
    1025             :         int fnum;
    1026             :         unsigned long long offset;
    1027             :         unsigned size;
    1028             :         struct tevent_req *req;
    1029             :         NTSTATUS status;
    1030             :         char *buf;
    1031             :         size_t received;
    1032             :         PyObject *result;
    1033             : 
    1034             :         static const char *kwlist[] = {
    1035             :                 "fnum", "offset", "size", NULL };
    1036             : 
    1037         495 :         if (!ParseTupleAndKeywords(
    1038             :                     args, kwds, "iKI", kwlist, &fnum, &offset,
    1039             :                     &size)) {
    1040           0 :                 return NULL;
    1041             :         }
    1042             : 
    1043         495 :         result = PyBytes_FromStringAndSize(NULL, size);
    1044         495 :         if (result == NULL) {
    1045           0 :                 return NULL;
    1046             :         }
    1047         495 :         buf = PyBytes_AS_STRING(result);
    1048             : 
    1049         495 :         req = cli_read_send(NULL, self->ev, self->cli, fnum,
    1050             :                             buf, offset, size);
    1051         495 :         if (!py_tevent_req_wait_exc(self, req)) {
    1052           0 :                 Py_XDECREF(result);
    1053           0 :                 return NULL;
    1054             :         }
    1055         495 :         status = cli_read_recv(req, &received);
    1056         495 :         TALLOC_FREE(req);
    1057             : 
    1058         495 :         if (!NT_STATUS_IS_OK(status)) {
    1059           3 :                 Py_XDECREF(result);
    1060           3 :                 PyErr_SetNTSTATUS(status);
    1061           3 :                 return NULL;
    1062             :         }
    1063             : 
    1064         492 :         if (received > size) {
    1065           0 :                 Py_XDECREF(result);
    1066           0 :                 PyErr_Format(PyExc_IOError,
    1067             :                              "read invalid - got %zu requested %u",
    1068             :                              received, size);
    1069           0 :                 return NULL;
    1070             :         }
    1071             : 
    1072         492 :         if (received < size) {
    1073         492 :                 if (_PyBytes_Resize(&result, received) < 0) {
    1074           0 :                         return NULL;
    1075             :                 }
    1076             :         }
    1077             : 
    1078         492 :         return result;
    1079             : }
    1080             : 
    1081           0 : static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
    1082             :                                   PyObject *kwds)
    1083             : {
    1084             :         int fnum;
    1085             :         unsigned long long size;
    1086             :         struct tevent_req *req;
    1087             :         NTSTATUS status;
    1088             : 
    1089             :         static const char *kwlist[] = {
    1090             :                 "fnum", "size", NULL };
    1091             : 
    1092           0 :         if (!ParseTupleAndKeywords(
    1093             :                     args, kwds, "IK", kwlist, &fnum, &size)) {
    1094           0 :                 return NULL;
    1095             :         }
    1096             : 
    1097           0 :         req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
    1098           0 :         if (!py_tevent_req_wait_exc(self, req)) {
    1099           0 :                 return NULL;
    1100             :         }
    1101           0 :         status = cli_ftruncate_recv(req);
    1102           0 :         TALLOC_FREE(req);
    1103             : 
    1104           0 :         if (!NT_STATUS_IS_OK(status)) {
    1105           0 :                 PyErr_SetNTSTATUS(status);
    1106           0 :                 return NULL;
    1107             :         }
    1108           0 :         Py_RETURN_NONE;
    1109             : }
    1110             : 
    1111           0 : static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
    1112             :                                         PyObject *args,
    1113             :                                         PyObject *kwds)
    1114             : {
    1115             :         unsigned fnum, flag;
    1116             :         struct tevent_req *req;
    1117             :         NTSTATUS status;
    1118             : 
    1119             :         static const char *kwlist[] = {
    1120             :                 "fnum", "flag", NULL };
    1121             : 
    1122           0 :         if (!ParseTupleAndKeywords(
    1123             :                     args, kwds, "II", kwlist, &fnum, &flag)) {
    1124           0 :                 return NULL;
    1125             :         }
    1126             : 
    1127           0 :         req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
    1128             :                                           flag);
    1129           0 :         if (!py_tevent_req_wait_exc(self, req)) {
    1130           0 :                 return NULL;
    1131             :         }
    1132           0 :         status = cli_nt_delete_on_close_recv(req);
    1133           0 :         TALLOC_FREE(req);
    1134             : 
    1135           0 :         if (!NT_STATUS_IS_OK(status)) {
    1136           0 :                 PyErr_SetNTSTATUS(status);
    1137           0 :                 return NULL;
    1138             :         }
    1139           0 :         Py_RETURN_NONE;
    1140             : }
    1141             : 
    1142             : struct py_cli_notify_state {
    1143             :         PyObject_HEAD
    1144             :         struct py_cli_state *py_cli_state;
    1145             :         struct tevent_req *req;
    1146             : };
    1147             : 
    1148          42 : static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
    1149             : {
    1150          42 :         TALLOC_FREE(self->req);
    1151          42 :         if (self->py_cli_state != NULL) {
    1152           0 :                 Py_DECREF(self->py_cli_state);
    1153           0 :                 self->py_cli_state = NULL;
    1154             :         }
    1155          42 :         Py_TYPE(self)->tp_free(self);
    1156          42 : }
    1157             : 
    1158             : static PyTypeObject py_cli_notify_state_type;
    1159             : 
    1160          42 : static PyObject *py_cli_notify(struct py_cli_state *self,
    1161             :                                PyObject *args,
    1162             :                                PyObject *kwds)
    1163             : {
    1164             :         static const char *kwlist[] = {
    1165             :                 "fnum",
    1166             :                 "buffer_size",
    1167             :                 "completion_filter",
    1168             :                 "recursive",
    1169             :                 NULL
    1170             :         };
    1171          42 :         unsigned fnum = 0;
    1172          42 :         unsigned buffer_size = 0;
    1173          42 :         unsigned completion_filter = 0;
    1174          42 :         PyObject *py_recursive = Py_False;
    1175          42 :         bool recursive = false;
    1176          42 :         struct tevent_req *req = NULL;
    1177          42 :         struct tevent_queue *send_queue = NULL;
    1178          42 :         struct tevent_req *flush_req = NULL;
    1179             :         bool ok;
    1180          42 :         struct py_cli_notify_state *py_notify_state = NULL;
    1181             :         struct timeval endtime;
    1182             : 
    1183          42 :         ok = ParseTupleAndKeywords(args,
    1184             :                                    kwds,
    1185             :                                    "IIIO",
    1186             :                                    kwlist,
    1187             :                                    &fnum,
    1188             :                                    &buffer_size,
    1189             :                                    &completion_filter,
    1190             :                                    &py_recursive);
    1191          42 :         if (!ok) {
    1192           0 :                 return NULL;
    1193             :         }
    1194             : 
    1195          42 :         recursive = PyObject_IsTrue(py_recursive);
    1196             : 
    1197          42 :         req = cli_notify_send(NULL,
    1198             :                               self->ev,
    1199             :                               self->cli,
    1200             :                               fnum,
    1201             :                               buffer_size,
    1202             :                               completion_filter,
    1203             :                               recursive);
    1204          42 :         if (req == NULL) {
    1205           0 :                 PyErr_NoMemory();
    1206           0 :                 return NULL;
    1207             :         }
    1208             : 
    1209             :         /*
    1210             :          * Just wait for the request being submitted to
    1211             :          * the kernel/socket/wire.
    1212             :          */
    1213          42 :         send_queue = smbXcli_conn_send_queue(self->cli->conn);
    1214          42 :         flush_req = tevent_queue_wait_send(req,
    1215             :                                            self->ev,
    1216             :                                            send_queue);
    1217          42 :         endtime = timeval_current_ofs_msec(self->cli->timeout);
    1218          42 :         ok = tevent_req_set_endtime(flush_req,
    1219             :                                     self->ev,
    1220             :                                     endtime);
    1221          42 :         if (!ok) {
    1222           0 :                 TALLOC_FREE(req);
    1223           0 :                 PyErr_NoMemory();
    1224           0 :                 return NULL;
    1225             :         }
    1226          42 :         ok = py_tevent_req_wait_exc(self, flush_req);
    1227          42 :         if (!ok) {
    1228           0 :                 TALLOC_FREE(req);
    1229           0 :                 return NULL;
    1230             :         }
    1231          42 :         TALLOC_FREE(flush_req);
    1232             : 
    1233          21 :         py_notify_state = (struct py_cli_notify_state *)
    1234          42 :                 py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
    1235          42 :         if (py_notify_state == NULL) {
    1236           0 :                 TALLOC_FREE(req);
    1237           0 :                 PyErr_NoMemory();
    1238           0 :                 return NULL;
    1239             :         }
    1240          42 :         Py_INCREF(self);
    1241          42 :         py_notify_state->py_cli_state = self;
    1242          42 :         py_notify_state->req = req;
    1243             : 
    1244          42 :         return (PyObject *)py_notify_state;
    1245             : }
    1246             : 
    1247          98 : static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
    1248             :                                            PyObject *args,
    1249             :                                            PyObject *kwds)
    1250             : {
    1251          98 :         struct py_cli_state *py_cli_state = self->py_cli_state;
    1252          98 :         struct tevent_req *req = self->req;
    1253             :         uint32_t i;
    1254          98 :         uint32_t num_changes = 0;
    1255          98 :         struct notify_change *changes = NULL;
    1256          98 :         PyObject *result = NULL;
    1257             :         NTSTATUS status;
    1258             :         bool ok;
    1259             :         static const char *kwlist[] = {
    1260             :                 "wait",
    1261             :                 NULL
    1262             :         };
    1263          98 :         PyObject *py_wait = Py_False;
    1264          98 :         bool wait = false;
    1265             :         bool pending;
    1266             : 
    1267          98 :         ok = ParseTupleAndKeywords(args,
    1268             :                                    kwds,
    1269             :                                    "O",
    1270             :                                    kwlist,
    1271             :                                    &py_wait);
    1272          98 :         if (!ok) {
    1273           0 :                 return NULL;
    1274             :         }
    1275             : 
    1276          98 :         wait = PyObject_IsTrue(py_wait);
    1277             : 
    1278          98 :         if (req == NULL) {
    1279           0 :                 PyErr_SetString(PyExc_RuntimeError,
    1280             :                                 "TODO req == NULL "
    1281             :                                 "- missing change notify request?");
    1282           0 :                 return NULL;
    1283             :         }
    1284             : 
    1285          98 :         pending = tevent_req_is_in_progress(req);
    1286          98 :         if (pending && !wait) {
    1287          56 :                 Py_RETURN_NONE;
    1288             :         }
    1289             : 
    1290          42 :         if (pending) {
    1291             :                 struct timeval endtime;
    1292             : 
    1293          30 :                 endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
    1294          30 :                 ok = tevent_req_set_endtime(req,
    1295             :                                             py_cli_state->ev,
    1296             :                                             endtime);
    1297          30 :                 if (!ok) {
    1298           0 :                         TALLOC_FREE(req);
    1299           0 :                         PyErr_NoMemory();
    1300           0 :                         return NULL;
    1301             :                 }
    1302             :         }
    1303             : 
    1304          42 :         ok = py_tevent_req_wait_exc(py_cli_state, req);
    1305          42 :         self->req = NULL;
    1306          42 :         Py_DECREF(self->py_cli_state);
    1307          42 :         self->py_cli_state = NULL;
    1308          42 :         if (!ok) {
    1309           0 :                 return NULL;
    1310             :         }
    1311             : 
    1312          42 :         status = cli_notify_recv(req, req, &num_changes, &changes);
    1313          42 :         if (!NT_STATUS_IS_OK(status)) {
    1314          12 :                 TALLOC_FREE(req);
    1315          12 :                 PyErr_SetNTSTATUS(status);
    1316          12 :                 return NULL;
    1317             :         }
    1318             : 
    1319          30 :         result = Py_BuildValue("[]");
    1320          30 :         if (result == NULL) {
    1321           0 :                 TALLOC_FREE(req);
    1322           0 :                 return NULL;
    1323             :         }
    1324             : 
    1325          60 :         for (i = 0; i < num_changes; i++) {
    1326          30 :                 PyObject *change = NULL;
    1327             :                 int ret;
    1328             : 
    1329          45 :                 change = Py_BuildValue("{s:s,s:I}",
    1330          30 :                                        "name", changes[i].name,
    1331          30 :                                        "action", changes[i].action);
    1332          30 :                 if (change == NULL) {
    1333           0 :                         Py_XDECREF(result);
    1334           0 :                         TALLOC_FREE(req);
    1335           0 :                         return NULL;
    1336             :                 }
    1337             : 
    1338          30 :                 ret = PyList_Append(result, change);
    1339          30 :                 Py_DECREF(change);
    1340          30 :                 if (ret == -1) {
    1341           0 :                         Py_XDECREF(result);
    1342           0 :                         TALLOC_FREE(req);
    1343           0 :                         return NULL;
    1344             :                 }
    1345             :         }
    1346             : 
    1347          30 :         TALLOC_FREE(req);
    1348          30 :         return result;
    1349             : }
    1350             : 
    1351             : static PyMethodDef py_cli_notify_state_methods[] = {
    1352             :         {
    1353             :                 .ml_name = "get_changes",
    1354             :                 .ml_meth = (PyCFunction)py_cli_notify_get_changes,
    1355             :                 .ml_flags = METH_VARARGS|METH_KEYWORDS,
    1356             :                 .ml_doc  = "Wait for change notifications: \n"
    1357             :                            "N.get_changes(wait=BOOLEAN) -> "
    1358             :                            "change notifications as a dictionary\n"
    1359             :                            "\t\tList contents of a directory. The keys are, \n"
    1360             :                            "\t\t\tname: name of changed object\n"
    1361             :                            "\t\t\taction: type of the change\n"
    1362             :                            "None is returned if there's no response jet and "
    1363             :                            "wait=False is passed"
    1364             :         },
    1365             :         {
    1366             :                 .ml_name = NULL
    1367             :         }
    1368             : };
    1369             : 
    1370             : static PyTypeObject py_cli_notify_state_type = {
    1371             :         PyVarObject_HEAD_INIT(NULL, 0)
    1372             :         .tp_name = "libsmb_samba_cwrapper.Notify",
    1373             :         .tp_basicsize = sizeof(struct py_cli_notify_state),
    1374             :         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    1375             :         .tp_doc = "notify request",
    1376             :         .tp_dealloc = (destructor)py_cli_notify_state_dealloc,
    1377             :         .tp_methods = py_cli_notify_state_methods,
    1378             : };
    1379             : 
    1380             : /*
    1381             :  * Helper to add directory listing entries to an overall Python list
    1382             :  */
    1383        5111 : static NTSTATUS list_helper(struct file_info *finfo,
    1384             :                             const char *mask, void *state)
    1385             : {
    1386        5111 :         PyObject *result = (PyObject *)state;
    1387        5111 :         PyObject *file = NULL;
    1388        5111 :         PyObject *size = NULL;
    1389             :         int ret;
    1390             : 
    1391             :         /* suppress '.' and '..' in the results we return */
    1392        5111 :         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
    1393        3060 :                 return NT_STATUS_OK;
    1394             :         }
    1395        2051 :         size = PyLong_FromUnsignedLongLong(finfo->size);
    1396             :         /*
    1397             :          * Build a dictionary representing the file info.
    1398             :          * Note: Windows does not always return short_name (so it may be None)
    1399             :          */
    1400        4102 :         file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l}",
    1401             :                              "name", finfo->name,
    1402        2051 :                              "attrib", (int)finfo->attr,
    1403             :                              "short_name", finfo->short_name,
    1404             :                              "size", size,
    1405             :                              "mtime",
    1406             :                              convert_timespec_to_time_t(finfo->mtime_ts));
    1407             : 
    1408        2051 :         Py_CLEAR(size);
    1409             : 
    1410        2051 :         if (file == NULL) {
    1411           0 :                 return NT_STATUS_NO_MEMORY;
    1412             :         }
    1413             : 
    1414        2051 :         ret = PyList_Append(result, file);
    1415        2051 :         Py_CLEAR(file);
    1416        2051 :         if (ret == -1) {
    1417           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1418             :         }
    1419             : 
    1420        2051 :         return NT_STATUS_OK;
    1421             : }
    1422             : 
    1423             : struct do_listing_state {
    1424             :         const char *mask;
    1425             :         NTSTATUS (*callback_fn)(
    1426             :                 struct file_info *finfo,
    1427             :                 const char *mask,
    1428             :                 void *private_data);
    1429             :         void *private_data;
    1430             :         NTSTATUS status;
    1431             : };
    1432             : 
    1433        8173 : static void do_listing_cb(struct tevent_req *subreq)
    1434             : {
    1435        8173 :         struct do_listing_state *state = tevent_req_callback_data_void(subreq);
    1436        8173 :         struct file_info *finfo = NULL;
    1437             : 
    1438        8173 :         state->status = cli_list_recv(subreq, NULL, &finfo);
    1439        8173 :         if (!NT_STATUS_IS_OK(state->status)) {
    1440        3062 :                 return;
    1441             :         }
    1442        5111 :         state->callback_fn(finfo, state->mask, state->private_data);
    1443        5111 :         TALLOC_FREE(finfo);
    1444             : }
    1445             : 
    1446        1531 : static NTSTATUS do_listing(struct py_cli_state *self,
    1447             :                            const char *base_dir, const char *user_mask,
    1448             :                            uint16_t attribute,
    1449             :                            NTSTATUS (*callback_fn)(struct file_info *,
    1450             :                                                    const char *, void *),
    1451             :                            void *priv)
    1452             : {
    1453        1531 :         char *mask = NULL;
    1454        1531 :         unsigned int info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
    1455        1531 :         struct do_listing_state state = {
    1456             :                 .mask = mask,
    1457             :                 .callback_fn = callback_fn,
    1458             :                 .private_data = priv,
    1459             :         };
    1460        1531 :         struct tevent_req *req = NULL;
    1461             :         NTSTATUS status;
    1462             : 
    1463        1531 :         if (user_mask == NULL) {
    1464        1529 :                 mask = talloc_asprintf(NULL, "%s\\*", base_dir);
    1465             :         } else {
    1466           2 :                 mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
    1467             :         }
    1468             : 
    1469        1531 :         if (mask == NULL) {
    1470           0 :                 return NT_STATUS_NO_MEMORY;
    1471             :         }
    1472        1531 :         dos_format(mask);
    1473             : 
    1474        1531 :         req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
    1475             :                             info_level);
    1476        1531 :         if (req == NULL) {
    1477           0 :                 status = NT_STATUS_NO_MEMORY;
    1478           0 :                 goto done;
    1479             :         }
    1480        1531 :         tevent_req_set_callback(req, do_listing_cb, &state);
    1481             : 
    1482        1531 :         if (!py_tevent_req_wait_exc(self, req)) {
    1483           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1484             :         }
    1485        1531 :         TALLOC_FREE(req);
    1486             : 
    1487        1531 :         status = state.status;
    1488        1531 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
    1489        1531 :                 status = NT_STATUS_OK;
    1490             :         }
    1491             : 
    1492        1531 : done:
    1493        1531 :         TALLOC_FREE(mask);
    1494        1531 :         return status;
    1495             : }
    1496             : 
    1497        1531 : static PyObject *py_cli_list(struct py_cli_state *self,
    1498             :                              PyObject *args,
    1499             :                              PyObject *kwds)
    1500             : {
    1501             :         char *base_dir;
    1502        1531 :         char *user_mask = NULL;
    1503        1531 :         unsigned int attribute = LIST_ATTRIBUTE_MASK;
    1504             :         NTSTATUS status;
    1505        1531 :         PyObject *result = NULL;
    1506        1531 :         const char *kwlist[] = { "directory", "mask", "attribs", NULL };
    1507             : 
    1508        1531 :         if (!ParseTupleAndKeywords(args, kwds, "z|sI:list", kwlist,
    1509             :                                    &base_dir, &user_mask, &attribute)) {
    1510           0 :                 return NULL;
    1511             :         }
    1512             : 
    1513        1531 :         result = Py_BuildValue("[]");
    1514        1531 :         if (result == NULL) {
    1515           0 :                 return NULL;
    1516             :         }
    1517             : 
    1518        1531 :         status = do_listing(self, base_dir, user_mask, attribute,
    1519             :                             list_helper, result);
    1520             : 
    1521        1531 :         if (!NT_STATUS_IS_OK(status)) {
    1522           0 :                 Py_XDECREF(result);
    1523           0 :                 PyErr_SetNTSTATUS(status);
    1524           0 :                 return NULL;
    1525             :         }
    1526             : 
    1527        1531 :         return result;
    1528             : }
    1529             : 
    1530         464 : static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
    1531             : {
    1532             :         NTSTATUS status;
    1533         464 :         const char *filename = NULL;
    1534         464 :         struct tevent_req *req = NULL;
    1535         464 :         const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
    1536             : 
    1537         464 :         if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
    1538           0 :                 return NULL;
    1539             :         }
    1540             : 
    1541         464 :         req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
    1542         464 :         if (!py_tevent_req_wait_exc(self, req)) {
    1543           0 :                 return NULL;
    1544             :         }
    1545         464 :         status = cli_unlink_recv(req);
    1546         464 :         TALLOC_FREE(req);
    1547         464 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
    1548             : 
    1549         457 :         Py_RETURN_NONE;
    1550             : }
    1551             : 
    1552         969 : static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
    1553             : {
    1554             :         NTSTATUS status;
    1555         969 :         struct tevent_req *req = NULL;
    1556         969 :         const char *dirname = NULL;
    1557             : 
    1558         969 :         if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
    1559           0 :                 return NULL;
    1560             :         }
    1561             : 
    1562         969 :         req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
    1563         969 :         if (!py_tevent_req_wait_exc(self, req)) {
    1564           0 :                 return NULL;
    1565             :         }
    1566         969 :         status = cli_rmdir_recv(req);
    1567         969 :         TALLOC_FREE(req);
    1568         969 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
    1569             : 
    1570         969 :         Py_RETURN_NONE;
    1571             : }
    1572             : 
    1573             : /*
    1574             :  * Create a directory
    1575             :  */
    1576         912 : static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
    1577             : {
    1578             :         NTSTATUS status;
    1579         912 :         const char *dirname = NULL;
    1580         912 :         struct tevent_req *req = NULL;
    1581             : 
    1582         912 :         if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
    1583           0 :                 return NULL;
    1584             :         }
    1585             : 
    1586         912 :         req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
    1587         912 :         if (!py_tevent_req_wait_exc(self, req)) {
    1588           0 :                 return NULL;
    1589             :         }
    1590         912 :         status = cli_mkdir_recv(req);
    1591         912 :         TALLOC_FREE(req);
    1592         912 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
    1593             : 
    1594         856 :         Py_RETURN_NONE;
    1595             : }
    1596             : 
    1597             : /*
    1598             :  * Does a whoami call
    1599             :  */
    1600           8 : static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
    1601             :                                      PyObject *Py_UNUSED(ignored))
    1602             : {
    1603           8 :         TALLOC_CTX *frame = talloc_stackframe();
    1604             :         NTSTATUS status;
    1605           8 :         struct tevent_req *req = NULL;
    1606             :         uint64_t uid;
    1607             :         uint64_t gid;
    1608             :         uint32_t num_gids;
    1609           8 :         uint64_t *gids = NULL;
    1610             :         uint32_t num_sids;
    1611           8 :         struct dom_sid *sids = NULL;
    1612             :         bool guest;
    1613           8 :         PyObject *py_gids = NULL;
    1614           8 :         PyObject *py_sids = NULL;
    1615           8 :         PyObject *py_guest = NULL;
    1616           8 :         PyObject *py_ret = NULL;
    1617             :         Py_ssize_t i;
    1618             : 
    1619           8 :         req = cli_posix_whoami_send(frame, self->ev, self->cli);
    1620           8 :         if (!py_tevent_req_wait_exc(self, req)) {
    1621           0 :                 goto fail;
    1622             :         }
    1623           8 :         status = cli_posix_whoami_recv(req,
    1624             :                                 frame,
    1625             :                                 &uid,
    1626             :                                 &gid,
    1627             :                                 &num_gids,
    1628             :                                 &gids,
    1629             :                                 &num_sids,
    1630             :                                 &sids,
    1631             :                                 &guest);
    1632           8 :         if (!NT_STATUS_IS_OK(status)) {
    1633           0 :                 PyErr_SetNTSTATUS(status);
    1634           0 :                 goto fail;
    1635             :         }
    1636             :         if (num_gids > PY_SSIZE_T_MAX) {
    1637             :                 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
    1638             :                 goto fail;
    1639             :         }
    1640             :         if (num_sids > PY_SSIZE_T_MAX) {
    1641             :                 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
    1642             :                 goto fail;
    1643             :         }
    1644             : 
    1645           8 :         py_gids = PyList_New(num_gids);
    1646           8 :         if (!py_gids) {
    1647           0 :                 goto fail;
    1648             :         }
    1649          44 :         for (i = 0; i < num_gids; ++i) {
    1650             :                 int ret;
    1651          36 :                 PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
    1652          36 :                 if (!py_item) {
    1653           0 :                         goto fail2;
    1654             :                 }
    1655             : 
    1656          36 :                 ret = PyList_SetItem(py_gids, i, py_item);
    1657          36 :                 if (ret) {
    1658           0 :                         goto fail2;
    1659             :                 }
    1660             :         }
    1661           8 :         py_sids = PyList_New(num_sids);
    1662           8 :         if (!py_sids) {
    1663           0 :                 goto fail2;
    1664             :         }
    1665          98 :         for (i = 0; i < num_sids; ++i) {
    1666             :                 int ret;
    1667             :                 struct dom_sid *sid;
    1668             :                 PyObject *py_item;
    1669             : 
    1670          90 :                 sid = dom_sid_dup(frame, &sids[i]);
    1671          90 :                 if (!sid) {
    1672           0 :                         PyErr_NoMemory();
    1673           0 :                         goto fail3;
    1674             :                 }
    1675             : 
    1676          90 :                 py_item = pytalloc_steal(dom_sid_Type, sid);
    1677          90 :                 if (!py_item) {
    1678           0 :                         PyErr_NoMemory();
    1679           0 :                         goto fail3;
    1680             :                 }
    1681             : 
    1682          90 :                 ret = PyList_SetItem(py_sids, i, py_item);
    1683          90 :                 if (ret) {
    1684           0 :                         goto fail3;
    1685             :                 }
    1686             :         }
    1687             : 
    1688           8 :         py_guest = guest ? Py_True : Py_False;
    1689             : 
    1690           8 :         py_ret = Py_BuildValue("KKNNO",
    1691             :                         uid,
    1692             :                         gid,
    1693             :                         py_gids,
    1694             :                         py_sids,
    1695             :                         py_guest);
    1696           8 :         if (!py_ret) {
    1697           0 :                 goto fail3;
    1698             :         }
    1699             : 
    1700           8 :         TALLOC_FREE(frame);
    1701           8 :         return py_ret;
    1702             : 
    1703           0 : fail3:
    1704           0 :         Py_CLEAR(py_sids);
    1705             : 
    1706           0 : fail2:
    1707           0 :         Py_CLEAR(py_gids);
    1708             : 
    1709           0 : fail:
    1710           0 :         TALLOC_FREE(frame);
    1711           0 :         return NULL;
    1712             : }
    1713             : 
    1714             : /*
    1715             :  * Checks existence of a directory
    1716             :  */
    1717        2907 : static bool check_dir_path(struct py_cli_state *self, const char *path)
    1718             : {
    1719             :         NTSTATUS status;
    1720        2907 :         struct tevent_req *req = NULL;
    1721             : 
    1722        2907 :         req = cli_chkpath_send(NULL, self->ev, self->cli, path);
    1723        2907 :         if (!py_tevent_req_wait_exc(self, req)) {
    1724           0 :                 return false;
    1725             :         }
    1726        2907 :         status = cli_chkpath_recv(req);
    1727        2907 :         TALLOC_FREE(req);
    1728             : 
    1729        2907 :         return NT_STATUS_IS_OK(status);
    1730             : }
    1731             : 
    1732        2907 : static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
    1733             : {
    1734        2907 :         const char *path = NULL;
    1735             :         bool dir_exists;
    1736             : 
    1737        2907 :         if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
    1738           0 :                 return NULL;
    1739             :         }
    1740             : 
    1741        2907 :         dir_exists = check_dir_path(self, path);
    1742        2907 :         return PyBool_FromLong(dir_exists);
    1743             : }
    1744             : 
    1745         310 : static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
    1746             : {
    1747             :         int fnum;
    1748             :         unsigned sinfo;
    1749         310 :         struct tevent_req *req = NULL;
    1750         310 :         struct security_descriptor *sd = NULL;
    1751             :         NTSTATUS status;
    1752             : 
    1753         310 :         if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
    1754           0 :                 return NULL;
    1755             :         }
    1756             : 
    1757         310 :         req = cli_query_security_descriptor_send(
    1758             :                 NULL, self->ev, self->cli, fnum, sinfo);
    1759         310 :         if (!py_tevent_req_wait_exc(self, req)) {
    1760           0 :                 return NULL;
    1761             :         }
    1762         310 :         status = cli_query_security_descriptor_recv(req, NULL, &sd);
    1763         310 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
    1764             : 
    1765         310 :         return py_return_ndr_struct(
    1766             :                 "samba.dcerpc.security", "descriptor", sd, sd);
    1767             : }
    1768             : 
    1769         162 : static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
    1770             : {
    1771         162 :         PyObject *py_sd = NULL;
    1772         162 :         struct tevent_req *req = NULL;
    1773         162 :         struct security_descriptor *sd = NULL;
    1774             :         uint16_t fnum;
    1775             :         unsigned int sinfo;
    1776             :         NTSTATUS status;
    1777             : 
    1778         162 :         if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
    1779           0 :                 return NULL;
    1780             :         }
    1781             : 
    1782         162 :         sd = pytalloc_get_type(py_sd, struct security_descriptor);
    1783         162 :         if (!sd) {
    1784           0 :                 PyErr_Format(PyExc_TypeError,
    1785             :                         "Expected dcerpc.security.descriptor as argument, got %s",
    1786             :                         pytalloc_get_name(py_sd));
    1787           0 :                 return NULL;
    1788             :         }
    1789             : 
    1790         162 :         req = cli_set_security_descriptor_send(
    1791             :                 NULL, self->ev, self->cli, fnum, sinfo, sd);
    1792         162 :         if (!py_tevent_req_wait_exc(self, req)) {
    1793           0 :                 return NULL;
    1794             :         }
    1795             : 
    1796         162 :         status = cli_set_security_descriptor_recv(req);
    1797         162 :         PyErr_NTSTATUS_NOT_OK_RAISE(status);
    1798             : 
    1799         162 :         Py_RETURN_NONE;
    1800             : }
    1801             : 
    1802             : static PyMethodDef py_cli_state_methods[] = {
    1803             :         { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
    1804             :           "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
    1805             :         { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
    1806             :           "Ping the server connection" },
    1807             :         { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
    1808             :                 METH_VARARGS|METH_KEYWORDS,
    1809             :           "Open a file" },
    1810             :         { "close", (PyCFunction)py_cli_close, METH_VARARGS,
    1811             :           "Close a file handle" },
    1812             :         { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
    1813             :                 METH_VARARGS|METH_KEYWORDS,
    1814             :           "Write to a file handle" },
    1815             :         { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
    1816             :                 METH_VARARGS|METH_KEYWORDS,
    1817             :           "Read from a file handle" },
    1818             :         { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
    1819             :                         py_cli_ftruncate),
    1820             :           METH_VARARGS|METH_KEYWORDS,
    1821             :           "Truncate a file" },
    1822             :         { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
    1823             :                                          py_cli_delete_on_close),
    1824             :           METH_VARARGS|METH_KEYWORDS,
    1825             :           "Set/Reset the delete on close flag" },
    1826             :         { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
    1827             :           METH_VARARGS|METH_KEYWORDS,
    1828             :           "Wait for change notifications: \n"
    1829             :           "notify(fnum, buffer_size, completion_filter...) -> "
    1830             :           "libsmb_samba_internal.Notify request handle\n" },
    1831             :         { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
    1832             :                 METH_VARARGS|METH_KEYWORDS,
    1833             :           "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
    1834             :           "directory contents as a dictionary\n"
    1835             :           "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
    1836             :           "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
    1837             :           "\t\tList contents of a directory. The keys are, \n"
    1838             :           "\t\t\tname: Long name of the directory item\n"
    1839             :           "\t\t\tshort_name: Short name of the directory item\n"
    1840             :           "\t\t\tsize: File size in bytes\n"
    1841             :           "\t\t\tattrib: Attributes\n"
    1842             :           "\t\t\tmtime: Modification time\n" },
    1843             :         { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
    1844             :           METH_VARARGS, "Wait for an oplock break" },
    1845             :         { "unlink", (PyCFunction)py_smb_unlink,
    1846             :           METH_VARARGS,
    1847             :           "unlink(path) -> None\n\n \t\tDelete a file." },
    1848             :         { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
    1849             :           "mkdir(path) -> None\n\n \t\tCreate a directory." },
    1850             :         { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
    1851             :         "posix_whoami() -> (uid, gid, gids, sids, guest)" },
    1852             :         { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
    1853             :           "rmdir(path) -> None\n\n \t\tDelete a directory." },
    1854             :         { "rename",
    1855             :           PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
    1856             :           METH_VARARGS|METH_KEYWORDS,
    1857             :           "rename(src,dst) -> None\n\n \t\tRename a file." },
    1858             :         { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
    1859             :           "chkpath(dir_path) -> True or False\n\n"
    1860             :           "\t\tReturn true if directory exists, false otherwise." },
    1861             :         { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
    1862             :           "savefile(path, bytes) -> None\n\n"
    1863             :           "\t\tWrite bytes to file." },
    1864             :         { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
    1865             :           "loadfile(path) -> file contents as a bytes object"
    1866             :           "\n\n\t\tRead contents of a file." },
    1867             :         { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
    1868             :           "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
    1869             :           "\t\tGet security descriptor for opened file." },
    1870             :         { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
    1871             :           "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
    1872             :           "\t\tSet security descriptor for opened file." },
    1873             :         { NULL, NULL, 0, NULL }
    1874             : };
    1875             : 
    1876             : static PyTypeObject py_cli_state_type = {
    1877             :         PyVarObject_HEAD_INIT(NULL, 0)
    1878             :         .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
    1879             :         .tp_basicsize = sizeof(struct py_cli_state),
    1880             :         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    1881             :         .tp_doc = "libsmb cwrapper connection",
    1882             :         .tp_new = py_cli_state_new,
    1883             :         .tp_init = (initproc)py_cli_state_init,
    1884             :         .tp_dealloc = (destructor)py_cli_state_dealloc,
    1885             :         .tp_methods = py_cli_state_methods,
    1886             : };
    1887             : 
    1888             : static PyMethodDef py_libsmb_methods[] = {
    1889             :         {0},
    1890             : };
    1891             : 
    1892             : void initlibsmb_samba_cwrapper(void);
    1893             : 
    1894             : static struct PyModuleDef moduledef = {
    1895             :     PyModuleDef_HEAD_INIT,
    1896             :     .m_name = "libsmb_samba_cwrapper",
    1897             :     .m_doc = "libsmb wrapper",
    1898             :     .m_size = -1,
    1899             :     .m_methods = py_libsmb_methods,
    1900             : };
    1901             : 
    1902        1199 : MODULE_INIT_FUNC(libsmb_samba_cwrapper)
    1903             : {
    1904        1199 :         PyObject *m = NULL;
    1905        1199 :         PyObject *mod = NULL;
    1906             : 
    1907        1199 :         talloc_stackframe();
    1908             : 
    1909        1199 :         if (PyType_Ready(&py_cli_state_type) < 0) {
    1910           0 :                 return NULL;
    1911             :         }
    1912        1199 :         if (PyType_Ready(&py_cli_notify_state_type) < 0) {
    1913           0 :                 return NULL;
    1914             :         }
    1915             : 
    1916        1199 :         m = PyModule_Create(&moduledef);
    1917        1199 :         if (m == NULL) {
    1918           0 :                 return m;
    1919             :         }
    1920             : 
    1921             :         /* Import dom_sid type from dcerpc.security */
    1922        1199 :         mod = PyImport_ImportModule("samba.dcerpc.security");
    1923        1199 :         if (mod == NULL) {
    1924           0 :                 return NULL;
    1925             :         }
    1926             : 
    1927        1199 :         dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
    1928        1199 :         if (dom_sid_Type == NULL) {
    1929           0 :                 Py_DECREF(mod);
    1930           0 :                 return NULL;
    1931             :         }
    1932             : 
    1933        1199 :         Py_INCREF(&py_cli_state_type);
    1934        1199 :         PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
    1935             : 
    1936             : #define ADD_FLAGS(val)  PyModule_AddObject(m, #val, PyLong_FromLong(val))
    1937             : 
    1938        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
    1939        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
    1940        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
    1941        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
    1942        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
    1943        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
    1944        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
    1945        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
    1946        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
    1947        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
    1948        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
    1949        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
    1950        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
    1951        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
    1952        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
    1953        1199 :         ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
    1954             : 
    1955        1199 :         ADD_FLAGS(FILE_SHARE_READ);
    1956        1199 :         ADD_FLAGS(FILE_SHARE_WRITE);
    1957        1199 :         ADD_FLAGS(FILE_SHARE_DELETE);
    1958             : 
    1959             :         /* change notify completion filter flags */
    1960        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
    1961        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
    1962        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
    1963        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
    1964        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
    1965        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
    1966        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
    1967        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
    1968        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
    1969        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
    1970        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
    1971        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
    1972        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
    1973        1199 :         ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
    1974             : 
    1975             :         /* change notify action results */
    1976        1199 :         ADD_FLAGS(NOTIFY_ACTION_ADDED);
    1977        1199 :         ADD_FLAGS(NOTIFY_ACTION_REMOVED);
    1978        1199 :         ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
    1979        1199 :         ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
    1980        1199 :         ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
    1981        1199 :         ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
    1982        1199 :         ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
    1983        1199 :         ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
    1984             : 
    1985        1199 :         return m;
    1986             : }

Generated by: LCOV version 1.13