pylibsmb: Add smb1_symlink()
[samba.git] / source3 / libsmb / pylibsmb.c
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 /*
25 Template code to use this library:
26
27 -------------------------
28 from samba.samba3 import libsmb_samba_internal as libsmb
29 from samba.samba3 import param as s3param
30 from samba import (credentials,NTSTATUSError)
31
32 lp = s3param.get_context()
33 lp.load("/etc/samba/smb.conf");
34
35 creds = credentials.Credentials()
36 creds.guess(lp)
37 creds.set_username("administrator")
38 creds.set_password("1234")
39
40 c = libsmb.Conn("127.0.0.1",
41                 "tmp",
42                 lp,
43                 creds,
44                 multi_threaded=True)
45 -------------------------
46 */
47
48 #include <Python.h>
49 #include "includes.h"
50 #include "python/py3compat.h"
51 #include "python/modules.h"
52 #include "libcli/smb/smbXcli_base.h"
53 #include "libcli/smb/smb2_negotiate_context.h"
54 #include "libcli/smb/reparse_symlink.h"
55 #include "libsmb/libsmb.h"
56 #include "libcli/security/security.h"
57 #include "system/select.h"
58 #include "source4/libcli/util/pyerrors.h"
59 #include "auth/credentials/pycredentials.h"
60 #include "trans2.h"
61 #include "libsmb/clirap.h"
62 #include "librpc/rpc/pyrpc_util.h"
63
64 #define LIST_ATTRIBUTE_MASK \
65         (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN)
66
67 static PyTypeObject *dom_sid_Type = NULL;
68
69 static PyTypeObject *get_pytype(const char *module, const char *type)
70 {
71         PyObject *mod;
72         PyTypeObject *result;
73
74         mod = PyImport_ImportModule(module);
75         if (mod == NULL) {
76                 PyErr_Format(PyExc_RuntimeError,
77                              "Unable to import %s to check type %s",
78                              module, type);
79                 return NULL;
80         }
81         result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
82         Py_DECREF(mod);
83         if (result == NULL) {
84                 PyErr_Format(PyExc_RuntimeError,
85                              "Unable to find type %s in module %s",
86                              module, type);
87                 return NULL;
88         }
89         return result;
90 }
91
92 /*
93  * We're using "const char * const *" for keywords,
94  * PyArg_ParseTupleAndKeywords expects a "char **". Confine the
95  * inevitable warnings to just one place.
96  */
97 static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
98                                  const char *format, const char * const *keywords,
99                                  ...)
100 {
101         char **_keywords = discard_const_p(char *, keywords);
102         va_list a;
103         int ret;
104         va_start(a, keywords);
105         ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
106                                             _keywords, a);
107         va_end(a);
108         return ret;
109 }
110
111 struct py_cli_thread;
112
113 struct py_cli_oplock_break {
114         uint16_t fnum;
115         uint8_t level;
116 };
117
118 struct py_cli_state {
119         PyObject_HEAD
120         struct cli_state *cli;
121         struct tevent_context *ev;
122         int (*req_wait_fn)(struct tevent_context *ev,
123                            struct tevent_req *req);
124         struct py_cli_thread *thread_state;
125
126         struct tevent_req *oplock_waiter;
127         struct py_cli_oplock_break *oplock_breaks;
128         struct py_tevent_cond *oplock_cond;
129 };
130
131 #ifdef HAVE_PTHREAD
132
133 #include <pthread.h>
134
135 struct py_cli_thread {
136
137         /*
138          * Pipe to make the poll thread wake up in our destructor, so
139          * that we can exit and join the thread.
140          */
141         int shutdown_pipe[2];
142         struct tevent_fd *shutdown_fde;
143         bool do_shutdown;
144         pthread_t id;
145
146         /*
147          * Thread state to release the GIL during the poll(2) syscall
148          */
149         PyThreadState *py_threadstate;
150 };
151
152 static void *py_cli_state_poll_thread(void *private_data)
153 {
154         struct py_cli_state *self = (struct py_cli_state *)private_data;
155         struct py_cli_thread *t = self->thread_state;
156         PyGILState_STATE gstate;
157
158         gstate = PyGILState_Ensure();
159
160         while (!t->do_shutdown) {
161                 int ret;
162                 ret = tevent_loop_once(self->ev);
163                 assert(ret == 0);
164         }
165         PyGILState_Release(gstate);
166         return NULL;
167 }
168
169 static void py_cli_state_trace_callback(enum tevent_trace_point point,
170                                         void *private_data)
171 {
172         struct py_cli_state *self = (struct py_cli_state *)private_data;
173         struct py_cli_thread *t = self->thread_state;
174
175         switch(point) {
176         case TEVENT_TRACE_BEFORE_WAIT:
177                 assert(t->py_threadstate == NULL);
178                 t->py_threadstate = PyEval_SaveThread();
179                 break;
180         case TEVENT_TRACE_AFTER_WAIT:
181                 assert(t->py_threadstate != NULL);
182                 PyEval_RestoreThread(t->py_threadstate);
183                 t->py_threadstate = NULL;
184                 break;
185         default:
186                 break;
187         }
188 }
189
190 static void py_cli_state_shutdown_handler(struct tevent_context *ev,
191                                           struct tevent_fd *fde,
192                                           uint16_t flags,
193                                           void *private_data)
194 {
195         struct py_cli_state *self = (struct py_cli_state *)private_data;
196         struct py_cli_thread *t = self->thread_state;
197
198         if ((flags & TEVENT_FD_READ) == 0) {
199                 return;
200         }
201         TALLOC_FREE(t->shutdown_fde);
202         t->do_shutdown = true;
203 }
204
205 static int py_cli_thread_destructor(struct py_cli_thread *t)
206 {
207         char c = 0;
208         ssize_t written;
209         int ret;
210
211         do {
212                 /*
213                  * This will wake the poll thread from the poll(2)
214                  */
215                 written = write(t->shutdown_pipe[1], &c, 1);
216         } while ((written == -1) && (errno == EINTR));
217
218         /*
219          * Allow the poll thread to do its own cleanup under the GIL
220          */
221         Py_BEGIN_ALLOW_THREADS
222         ret = pthread_join(t->id, NULL);
223         Py_END_ALLOW_THREADS
224         assert(ret == 0);
225
226         if (t->shutdown_pipe[0] != -1) {
227                 close(t->shutdown_pipe[0]);
228                 t->shutdown_pipe[0] = -1;
229         }
230         if (t->shutdown_pipe[1] != -1) {
231                 close(t->shutdown_pipe[1]);
232                 t->shutdown_pipe[1] = -1;
233         }
234         return 0;
235 }
236
237 static int py_tevent_cond_req_wait(struct tevent_context *ev,
238                                    struct tevent_req *req);
239
240 static bool py_cli_state_setup_mt_ev(struct py_cli_state *self)
241 {
242         struct py_cli_thread *t = NULL;
243         int ret;
244
245         self->ev = tevent_context_init_byname(NULL, "poll_mt");
246         if (self->ev == NULL) {
247                 goto fail;
248         }
249         samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
250         tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
251
252         self->req_wait_fn = py_tevent_cond_req_wait;
253
254         self->thread_state = talloc_zero(NULL, struct py_cli_thread);
255         if (self->thread_state == NULL) {
256                 goto fail;
257         }
258         t = self->thread_state;
259
260         ret = pipe(t->shutdown_pipe);
261         if (ret == -1) {
262                 goto fail;
263         }
264         t->shutdown_fde = tevent_add_fd(
265                 self->ev, self->ev, t->shutdown_pipe[0], TEVENT_FD_READ,
266                 py_cli_state_shutdown_handler, self);
267         if (t->shutdown_fde == NULL) {
268                 goto fail;
269         }
270
271         PyEval_InitThreads();
272
273         ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
274         if (ret != 0) {
275                 goto fail;
276         }
277         talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
278         return true;
279
280 fail:
281         if (t != NULL) {
282                 TALLOC_FREE(t->shutdown_fde);
283
284                 if (t->shutdown_pipe[0] != -1) {
285                         close(t->shutdown_pipe[0]);
286                         t->shutdown_pipe[0] = -1;
287                 }
288                 if (t->shutdown_pipe[1] != -1) {
289                         close(t->shutdown_pipe[1]);
290                         t->shutdown_pipe[1] = -1;
291                 }
292         }
293
294         TALLOC_FREE(self->thread_state);
295         TALLOC_FREE(self->ev);
296         return false;
297 }
298
299 struct py_tevent_cond {
300         pthread_mutex_t mutex;
301         pthread_cond_t cond;
302         bool is_done;
303 };
304
305 static void py_tevent_signalme(struct tevent_req *req);
306
307 static int py_tevent_cond_wait(struct py_tevent_cond *cond)
308 {
309         int ret, result;
310
311         result = pthread_mutex_init(&cond->mutex, NULL);
312         if (result != 0) {
313                 goto fail;
314         }
315         result = pthread_cond_init(&cond->cond, NULL);
316         if (result != 0) {
317                 goto fail_mutex;
318         }
319
320         result = pthread_mutex_lock(&cond->mutex);
321         if (result != 0) {
322                 goto fail_cond;
323         }
324
325         cond->is_done = false;
326
327         while (!cond->is_done) {
328
329                 Py_BEGIN_ALLOW_THREADS
330                 result = pthread_cond_wait(&cond->cond, &cond->mutex);
331                 Py_END_ALLOW_THREADS
332
333                 if (result != 0) {
334                         goto fail_unlock;
335                 }
336         }
337
338 fail_unlock:
339         ret = pthread_mutex_unlock(&cond->mutex);
340         assert(ret == 0);
341 fail_cond:
342         ret = pthread_cond_destroy(&cond->cond);
343         assert(ret == 0);
344 fail_mutex:
345         ret = pthread_mutex_destroy(&cond->mutex);
346         assert(ret == 0);
347 fail:
348         return result;
349 }
350
351 static int py_tevent_cond_req_wait(struct tevent_context *ev,
352                                    struct tevent_req *req)
353 {
354         struct py_tevent_cond cond;
355         tevent_req_set_callback(req, py_tevent_signalme, &cond);
356         return py_tevent_cond_wait(&cond);
357 }
358
359 static void py_tevent_cond_signal(struct py_tevent_cond *cond)
360 {
361         int ret;
362
363         ret = pthread_mutex_lock(&cond->mutex);
364         assert(ret == 0);
365
366         cond->is_done = true;
367
368         ret = pthread_cond_signal(&cond->cond);
369         assert(ret == 0);
370         ret = pthread_mutex_unlock(&cond->mutex);
371         assert(ret == 0);
372 }
373
374 static void py_tevent_signalme(struct tevent_req *req)
375 {
376         struct py_tevent_cond *cond = (struct py_tevent_cond *)
377                 tevent_req_callback_data_void(req);
378
379         py_tevent_cond_signal(cond);
380 }
381
382 #endif
383
384 static int py_tevent_req_wait(struct tevent_context *ev,
385                               struct tevent_req *req);
386
387 static bool py_cli_state_setup_ev(struct py_cli_state *self)
388 {
389         self->ev = tevent_context_init(NULL);
390         if (self->ev == NULL) {
391                 return false;
392         }
393
394         samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
395
396         self->req_wait_fn = py_tevent_req_wait;
397
398         return true;
399 }
400
401 static int py_tevent_req_wait(struct tevent_context *ev,
402                               struct tevent_req *req)
403 {
404         while (tevent_req_is_in_progress(req)) {
405                 int ret;
406
407                 ret = tevent_loop_once(ev);
408                 if (ret != 0) {
409                         return ret;
410                 }
411         }
412         return 0;
413 }
414
415 static bool py_tevent_req_wait_exc(struct py_cli_state *self,
416                                    struct tevent_req *req)
417 {
418         int ret;
419
420         if (req == NULL) {
421                 PyErr_NoMemory();
422                 return false;
423         }
424         ret = self->req_wait_fn(self->ev, req);
425         if (ret != 0) {
426                 TALLOC_FREE(req);
427                 errno = ret;
428                 PyErr_SetFromErrno(PyExc_RuntimeError);
429                 return false;
430         }
431         return true;
432 }
433
434 static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
435                                   PyObject *kwds)
436 {
437         struct py_cli_state *self;
438
439         self = (struct py_cli_state *)type->tp_alloc(type, 0);
440         if (self == NULL) {
441                 return NULL;
442         }
443         self->cli = NULL;
444         self->ev = NULL;
445         self->thread_state = NULL;
446         self->oplock_waiter = NULL;
447         self->oplock_cond = NULL;
448         self->oplock_breaks = NULL;
449         return (PyObject *)self;
450 }
451
452 static struct smb2_negotiate_contexts *py_cli_get_negotiate_contexts(
453         TALLOC_CTX *mem_ctx, PyObject *list)
454 {
455         struct smb2_negotiate_contexts *ctxs = NULL;
456         Py_ssize_t i, len;
457         int ret;
458
459         ret = PyList_Check(list);
460         if (!ret) {
461                 goto fail;
462         }
463
464         len = PyList_Size(list);
465         if (len == 0) {
466                 goto fail;
467         }
468
469         ctxs = talloc_zero(mem_ctx, struct smb2_negotiate_contexts);
470         if (ctxs == NULL) {
471                 goto fail;
472         }
473
474         for (i=0; i<len; i++) {
475                 NTSTATUS status;
476
477                 PyObject *t = PyList_GetItem(list, i);
478                 Py_ssize_t tlen;
479
480                 PyObject *ptype = NULL;
481                 long type;
482
483                 PyObject *pdata = NULL;
484                 DATA_BLOB data = { .data = NULL, };
485
486                 if (t == NULL) {
487                         goto fail;
488                 }
489
490                 ret = PyTuple_Check(t);
491                 if (!ret) {
492                         goto fail;
493                 }
494
495                 tlen = PyTuple_Size(t);
496                 if (tlen != 2) {
497                         goto fail;
498                 }
499
500                 ptype = PyTuple_GetItem(t, 0);
501                 if (ptype == NULL) {
502                         goto fail;
503                 }
504                 type = PyLong_AsLong(ptype);
505                 if ((type < 0) || (type > UINT16_MAX)) {
506                         goto fail;
507                 }
508
509                 pdata = PyTuple_GetItem(t, 1);
510
511                 ret = PyBytes_Check(pdata);
512                 if (!ret) {
513                         goto fail;
514                 }
515
516                 data.data = (uint8_t *)PyBytes_AsString(pdata);
517                 data.length = PyBytes_Size(pdata);
518
519                 status = smb2_negotiate_context_add(
520                         ctxs, ctxs, type, data.data, data.length);
521                 if (!NT_STATUS_IS_OK(status)) {
522                         goto fail;
523                 }
524         }
525         return ctxs;
526
527 fail:
528         TALLOC_FREE(ctxs);
529         return NULL;
530 }
531
532 static void py_cli_got_oplock_break(struct tevent_req *req);
533
534 static int py_cli_state_init(struct py_cli_state *self, PyObject *args,
535                              PyObject *kwds)
536 {
537         NTSTATUS status;
538         char *host, *share;
539         PyObject *creds = NULL;
540         struct cli_credentials *cli_creds;
541         PyObject *py_lp = Py_None;
542         PyObject *py_multi_threaded = Py_False;
543         bool multi_threaded = false;
544         PyObject *py_force_smb1 = Py_False;
545         bool force_smb1 = false;
546         PyObject *py_ipc = Py_False;
547         PyObject *py_posix = Py_False;
548         PyObject *py_negotiate_contexts = NULL;
549         struct smb2_negotiate_contexts *negotiate_contexts = NULL;
550         bool use_ipc = false;
551         bool request_posix = false;
552         struct tevent_req *req;
553         bool ret;
554         int flags = 0;
555
556         static const char *kwlist[] = {
557                 "host", "share", "lp", "creds",
558                 "multi_threaded", "force_smb1",
559                 "ipc",
560                 "posix",
561                 "negotiate_contexts",
562                 NULL
563         };
564
565         PyTypeObject *py_type_Credentials = get_pytype(
566                 "samba.credentials", "Credentials");
567         if (py_type_Credentials == NULL) {
568                 return -1;
569         }
570
571         ret = ParseTupleAndKeywords(
572                 args, kwds, "ssO|O!OOOOO", kwlist,
573                 &host, &share, &py_lp,
574                 py_type_Credentials, &creds,
575                 &py_multi_threaded,
576                 &py_force_smb1,
577                 &py_ipc,
578                 &py_posix,
579                 &py_negotiate_contexts);
580
581         Py_DECREF(py_type_Credentials);
582
583         if (!ret) {
584                 return -1;
585         }
586
587         multi_threaded = PyObject_IsTrue(py_multi_threaded);
588         force_smb1 = PyObject_IsTrue(py_force_smb1);
589
590         if (force_smb1) {
591                 /*
592                  * As most of the cli_*_send() function
593                  * don't support SMB2 (it's only plugged
594                  * into the sync wrapper functions currently)
595                  * we have a way to force SMB1.
596                  */
597                 flags = CLI_FULL_CONNECTION_FORCE_SMB1;
598         }
599
600         use_ipc = PyObject_IsTrue(py_ipc);
601         if (use_ipc) {
602                 flags |= CLI_FULL_CONNECTION_IPC;
603         }
604
605         request_posix = PyObject_IsTrue(py_posix);
606         if (request_posix) {
607                 flags |= CLI_FULL_CONNECTION_REQUEST_POSIX;
608         }
609
610         if (py_negotiate_contexts != NULL) {
611                 negotiate_contexts = py_cli_get_negotiate_contexts(
612                         talloc_tos(), py_negotiate_contexts);
613                 if (negotiate_contexts == NULL) {
614                         return -1;
615                 }
616         }
617
618         if (multi_threaded) {
619 #ifdef HAVE_PTHREAD
620                 ret = py_cli_state_setup_mt_ev(self);
621                 if (!ret) {
622                         return -1;
623                 }
624 #else
625                 PyErr_SetString(PyExc_RuntimeError,
626                                 "No PTHREAD support available");
627                 return -1;
628 #endif
629         } else {
630                 ret = py_cli_state_setup_ev(self);
631                 if (!ret) {
632                         return -1;
633                 }
634         }
635
636         if (creds == NULL) {
637                 cli_creds = cli_credentials_init_anon(NULL);
638         } else {
639                 cli_creds = PyCredentials_AsCliCredentials(creds);
640         }
641
642         req = cli_full_connection_creds_send(
643                 NULL, self->ev, "myname", host, NULL, 0, share, "?????",
644                 cli_creds, flags,
645                 negotiate_contexts);
646         if (!py_tevent_req_wait_exc(self, req)) {
647                 return -1;
648         }
649         status = cli_full_connection_creds_recv(req, &self->cli);
650         TALLOC_FREE(req);
651
652         if (!NT_STATUS_IS_OK(status)) {
653                 PyErr_SetNTSTATUS(status);
654                 return -1;
655         }
656
657         /*
658          * Oplocks require a multi threaded connection
659          */
660         if (self->thread_state == NULL) {
661                 return 0;
662         }
663
664         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
665                 self->ev, self->ev, self->cli);
666         if (self->oplock_waiter == NULL) {
667                 PyErr_NoMemory();
668                 return -1;
669         }
670         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
671                                 self);
672         return 0;
673 }
674
675 static void py_cli_got_oplock_break(struct tevent_req *req)
676 {
677         struct py_cli_state *self = (struct py_cli_state *)
678                 tevent_req_callback_data_void(req);
679         struct py_cli_oplock_break b;
680         struct py_cli_oplock_break *tmp;
681         size_t num_breaks;
682         NTSTATUS status;
683
684         status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
685         TALLOC_FREE(req);
686         self->oplock_waiter = NULL;
687
688         if (!NT_STATUS_IS_OK(status)) {
689                 return;
690         }
691
692         num_breaks = talloc_array_length(self->oplock_breaks);
693         tmp = talloc_realloc(self->ev, self->oplock_breaks,
694                              struct py_cli_oplock_break, num_breaks+1);
695         if (tmp == NULL) {
696                 return;
697         }
698         self->oplock_breaks = tmp;
699         self->oplock_breaks[num_breaks] = b;
700
701         if (self->oplock_cond != NULL) {
702                 py_tevent_cond_signal(self->oplock_cond);
703         }
704
705         self->oplock_waiter = cli_smb_oplock_break_waiter_send(
706                 self->ev, self->ev, self->cli);
707         if (self->oplock_waiter == NULL) {
708                 return;
709         }
710         tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
711                                 self);
712 }
713
714 static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
715                                          PyObject *args)
716 {
717         size_t num_oplock_breaks;
718
719         if (!PyArg_ParseTuple(args, "")) {
720                 return NULL;
721         }
722
723         if (self->thread_state == NULL) {
724                 PyErr_SetString(PyExc_RuntimeError,
725                                 "get_oplock_break() only possible on "
726                                 "a multi_threaded connection");
727                 return NULL;
728         }
729
730         if (self->oplock_cond != NULL) {
731                 errno = EBUSY;
732                 PyErr_SetFromErrno(PyExc_RuntimeError);
733                 return NULL;
734         }
735
736         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
737
738         if (num_oplock_breaks == 0) {
739                 struct py_tevent_cond cond;
740                 int ret;
741
742                 self->oplock_cond = &cond;
743                 ret = py_tevent_cond_wait(&cond);
744                 self->oplock_cond = NULL;
745
746                 if (ret != 0) {
747                         errno = ret;
748                         PyErr_SetFromErrno(PyExc_RuntimeError);
749                         return NULL;
750                 }
751         }
752
753         num_oplock_breaks = talloc_array_length(self->oplock_breaks);
754         if (num_oplock_breaks > 0) {
755                 PyObject *result;
756
757                 result = Py_BuildValue(
758                         "{s:i,s:i}",
759                         "fnum", self->oplock_breaks[0].fnum,
760                         "level", self->oplock_breaks[0].level);
761
762                 memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
763                         sizeof(self->oplock_breaks[0]) *
764                         (num_oplock_breaks - 1));
765                 self->oplock_breaks = talloc_realloc(
766                         NULL, self->oplock_breaks, struct py_cli_oplock_break,
767                         num_oplock_breaks - 1);
768
769                 return result;
770         }
771         Py_RETURN_NONE;
772 }
773
774 static void py_cli_state_dealloc(struct py_cli_state *self)
775 {
776         TALLOC_FREE(self->thread_state);
777         TALLOC_FREE(self->oplock_waiter);
778         TALLOC_FREE(self->ev);
779
780         if (self->cli != NULL) {
781                 cli_shutdown(self->cli);
782                 self->cli = NULL;
783         }
784         Py_TYPE(self)->tp_free((PyObject *)self);
785 }
786
787 static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
788 {
789         unsigned int nmsecs = 0;
790         unsigned int omsecs = 0;
791
792         if (!PyArg_ParseTuple(args, "I", &nmsecs)) {
793                 return NULL;
794         }
795
796         omsecs = cli_set_timeout(self->cli, nmsecs);
797
798         return PyLong_FromLong(omsecs);
799 }
800
801 static PyObject *py_cli_echo(struct py_cli_state *self,
802                              PyObject *Py_UNUSED(ignored))
803 {
804         DATA_BLOB data = data_blob_string_const("keepalive");
805         struct tevent_req *req = NULL;
806         NTSTATUS status;
807
808         req = cli_echo_send(NULL, self->ev, self->cli, 1, data);
809         if (!py_tevent_req_wait_exc(self, req)) {
810                 return NULL;
811         }
812         status = cli_echo_recv(req);
813         TALLOC_FREE(req);
814         PyErr_NTSTATUS_NOT_OK_RAISE(status);
815
816         Py_RETURN_NONE;
817 }
818
819 static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
820                                PyObject *kwds)
821 {
822         char *fname;
823         unsigned CreateFlags = 0;
824         unsigned DesiredAccess = FILE_GENERIC_READ;
825         unsigned FileAttributes = 0;
826         unsigned ShareAccess = 0;
827         unsigned CreateDisposition = FILE_OPEN;
828         unsigned CreateOptions = 0;
829         unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
830         unsigned SecurityFlags = 0;
831         uint16_t fnum;
832         struct tevent_req *req;
833         NTSTATUS status;
834
835         static const char *kwlist[] = {
836                 "Name", "CreateFlags", "DesiredAccess", "FileAttributes",
837                 "ShareAccess", "CreateDisposition", "CreateOptions",
838                 "ImpersonationLevel", "SecurityFlags", NULL };
839
840         if (!ParseTupleAndKeywords(
841                     args, kwds, "s|IIIIIIII", kwlist,
842                     &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
843                     &ShareAccess, &CreateDisposition, &CreateOptions,
844                     &ImpersonationLevel, &SecurityFlags)) {
845                 return NULL;
846         }
847
848         req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
849                                 DesiredAccess, FileAttributes, ShareAccess,
850                                 CreateDisposition, CreateOptions,
851                                 ImpersonationLevel, SecurityFlags);
852         if (!py_tevent_req_wait_exc(self, req)) {
853                 return NULL;
854         }
855         status = cli_ntcreate_recv(req, &fnum, NULL);
856         TALLOC_FREE(req);
857
858         if (!NT_STATUS_IS_OK(status)) {
859                 PyErr_SetNTSTATUS(status);
860                 return NULL;
861         }
862         return Py_BuildValue("I", (unsigned)fnum);
863 }
864
865 static struct smb2_create_blobs *py_cli_get_create_contexts(
866         TALLOC_CTX *mem_ctx, PyObject *list)
867 {
868         struct smb2_create_blobs *ctxs = NULL;
869         Py_ssize_t i, len;
870         int ret;
871
872         ret = PyList_Check(list);
873         if (!ret) {
874                 goto fail;
875         }
876
877         len = PyList_Size(list);
878         if (len == 0) {
879                 goto fail;
880         }
881
882         ctxs = talloc_zero(mem_ctx, struct smb2_create_blobs);
883         if (ctxs == NULL) {
884                 goto fail;
885         }
886
887         for (i=0; i<len; i++) {
888                 NTSTATUS status;
889
890                 PyObject *t = NULL;
891                 Py_ssize_t tlen;
892
893                 PyObject *pname = NULL;
894                 char *name = NULL;
895
896                 PyObject *pdata = NULL;
897                 DATA_BLOB data = { .data = NULL, };
898
899                 t = PyList_GetItem(list, i);
900                 if (t == NULL) {
901                         goto fail;
902                 }
903
904                 ret = PyTuple_Check(t);
905                 if (!ret) {
906                         goto fail;
907                 }
908
909                 tlen = PyTuple_Size(t);
910                 if (tlen != 2) {
911                         goto fail;
912                 }
913
914                 pname = PyTuple_GetItem(t, 0);
915                 if (pname == NULL) {
916                         goto fail;
917                 }
918                 ret = PyBytes_Check(pname);
919                 if (!ret) {
920                         goto fail;
921                 }
922                 name = PyBytes_AsString(pname);
923
924                 pdata = PyTuple_GetItem(t, 1);
925                 if (pdata == NULL) {
926                         goto fail;
927                 }
928                 ret = PyBytes_Check(pdata);
929                 if (!ret) {
930                         goto fail;
931                 }
932                 data = (DATA_BLOB) {
933                         .data = (uint8_t *)PyBytes_AsString(pdata),
934                         .length = PyBytes_Size(pdata),
935                 };
936                 status = smb2_create_blob_add(ctxs, ctxs, name, data);
937                 if (!NT_STATUS_IS_OK(status)) {
938                         goto fail;
939                 }
940         }
941         return ctxs;
942
943 fail:
944         TALLOC_FREE(ctxs);
945         return NULL;
946 }
947
948 static PyObject *py_cli_create_contexts(const struct smb2_create_blobs *blobs)
949 {
950         PyObject *py_blobs = NULL;
951         uint32_t i;
952
953         if (blobs == NULL) {
954                 Py_RETURN_NONE;
955         }
956
957         py_blobs = PyList_New(blobs->num_blobs);
958         if (py_blobs == NULL) {
959                 return NULL;
960         }
961
962         for (i=0; i<blobs->num_blobs; i++) {
963                 struct smb2_create_blob *blob = &blobs->blobs[i];
964                 PyObject *py_blob = NULL;
965                 int ret;
966
967                 py_blob = Py_BuildValue(
968                         "(yy#)",
969                         blob->tag,
970                         blob->data.data,
971                         (int)blob->data.length);
972                 if (py_blob == NULL) {
973                         goto fail;
974                 }
975
976                 ret = PyList_SetItem(py_blobs, i, py_blob);
977                 if (ret == -1) {
978                         Py_XDECREF(py_blob);
979                         goto fail;
980                 }
981         }
982         return py_blobs;
983
984 fail:
985         Py_XDECREF(py_blobs);
986         return NULL;
987 }
988
989 static PyObject *py_cli_create_returns(const struct smb_create_returns *r)
990 {
991         PyObject *v = NULL;
992
993         v = Py_BuildValue(
994                 "{sLsLsLsLsLsLsLsLsL}",
995                 "oplock_level",
996                 (unsigned long long)r->oplock_level,
997                 "create_action",
998                 (unsigned long long)r->create_action,
999                 "creation_time",
1000                 (unsigned long long)r->creation_time,
1001                 "last_access_time",
1002                 (unsigned long long)r->last_access_time,
1003                 "last_write_time",
1004                 (unsigned long long)r->last_write_time,
1005                 "change_time",
1006                 (unsigned long long)r->change_time,
1007                 "allocation_size",
1008                 (unsigned long long)r->allocation_size,
1009                 "end_of_file",
1010                 (unsigned long long)r->end_of_file,
1011                 "file_attributes",
1012                 (unsigned long long)r->file_attributes);
1013         return v;
1014 }
1015
1016 static PyObject *py_cli_symlink_error(const struct symlink_reparse_struct *s)
1017 {
1018         char *subst_utf8 = NULL, *print_utf8 = NULL;
1019         size_t subst_utf8_len, print_utf8_len;
1020         PyObject *v = NULL;
1021         bool ok = true;
1022
1023         /*
1024          * Python wants utf-8, regardless of our unix charset (which
1025          * most likely is utf-8 these days, but you never know).
1026          */
1027
1028         ok = convert_string_talloc(
1029                 talloc_tos(),
1030                 CH_UNIX,
1031                 CH_UTF8,
1032                 s->substitute_name,
1033                 strlen(s->substitute_name),
1034                 &subst_utf8,
1035                 &subst_utf8_len);
1036         if (!ok) {
1037                 goto fail;
1038         }
1039
1040         ok = convert_string_talloc(
1041                 talloc_tos(),
1042                 CH_UNIX,
1043                 CH_UTF8,
1044                 s->print_name,
1045                 strlen(s->print_name),
1046                 &print_utf8,
1047                 &print_utf8_len);
1048         if (!ok) {
1049                 goto fail;
1050         }
1051
1052         v = Py_BuildValue(
1053                 "{sLsssssL}",
1054                 "unparsed_path_length",
1055                 (unsigned long long)s->unparsed_path_length,
1056                 "substitute_name",
1057                 subst_utf8,
1058                 "print_name",
1059                 print_utf8,
1060                 "flags",
1061                 (unsigned long long)s->flags);
1062
1063 fail:
1064         TALLOC_FREE(subst_utf8);
1065         TALLOC_FREE(print_utf8);
1066         return v;
1067 }
1068
1069 static PyObject *py_cli_create_ex(
1070         struct py_cli_state *self, PyObject *args, PyObject *kwds)
1071 {
1072         char *fname = NULL;
1073         unsigned CreateFlags = 0;
1074         unsigned DesiredAccess = FILE_GENERIC_READ;
1075         unsigned FileAttributes = 0;
1076         unsigned ShareAccess = 0;
1077         unsigned CreateDisposition = FILE_OPEN;
1078         unsigned CreateOptions = 0;
1079         unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
1080         unsigned SecurityFlags = 0;
1081         PyObject *py_create_contexts_in = NULL;
1082         PyObject *py_create_contexts_out = NULL;
1083         struct smb2_create_blobs *create_contexts_in = NULL;
1084         struct smb2_create_blobs create_contexts_out = { .num_blobs = 0 };
1085         struct smb_create_returns cr = { .create_action = 0, };
1086         struct symlink_reparse_struct *symlink = NULL;
1087         PyObject *py_cr = NULL;
1088         uint16_t fnum;
1089         struct tevent_req *req;
1090         NTSTATUS status;
1091         int ret;
1092         bool ok;
1093         PyObject *v = NULL;
1094
1095         static const char *kwlist[] = {
1096                 "Name",
1097                 "CreateFlags",
1098                 "DesiredAccess",
1099                 "FileAttributes",
1100                 "ShareAccess",
1101                 "CreateDisposition",
1102                 "CreateOptions",
1103                 "ImpersonationLevel",
1104                 "SecurityFlags",
1105                 "CreateContexts",
1106                 NULL };
1107
1108         ret = ParseTupleAndKeywords(
1109                 args,
1110                 kwds,
1111                 "s|IIIIIIIIO",
1112                 kwlist,
1113                 &fname,
1114                 &CreateFlags,
1115                 &DesiredAccess,
1116                 &FileAttributes,
1117                 &ShareAccess,
1118                 &CreateDisposition,
1119                 &CreateOptions,
1120                 &ImpersonationLevel,
1121                 &SecurityFlags,
1122                 &py_create_contexts_in);
1123         if (!ret) {
1124                 return NULL;
1125         }
1126
1127         if (py_create_contexts_in != NULL) {
1128                 create_contexts_in = py_cli_get_create_contexts(
1129                         NULL, py_create_contexts_in);
1130                 if (create_contexts_in == NULL) {
1131                         errno = EINVAL;
1132                         PyErr_SetFromErrno(PyExc_RuntimeError);
1133                         return NULL;
1134                 }
1135         }
1136
1137         if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1138                 req = cli_smb2_create_fnum_send(
1139                         NULL,
1140                         self->ev,
1141                         self->cli,
1142                         fname,
1143                         CreateFlags,
1144                         ImpersonationLevel,
1145                         DesiredAccess,
1146                         FileAttributes,
1147                         ShareAccess,
1148                         CreateDisposition,
1149                         CreateOptions,
1150                         create_contexts_in);
1151         } else {
1152                 req = cli_ntcreate_send(
1153                         NULL,
1154                         self->ev,
1155                         self->cli,
1156                         fname,
1157                         CreateFlags,
1158                         DesiredAccess,
1159                         FileAttributes,
1160                         ShareAccess,
1161                         CreateDisposition,
1162                         CreateOptions,
1163                         ImpersonationLevel,
1164                         SecurityFlags);
1165         }
1166
1167         TALLOC_FREE(create_contexts_in);
1168
1169         ok = py_tevent_req_wait_exc(self, req);
1170         if (!ok) {
1171                 return NULL;
1172         }
1173
1174         if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1175                 status = cli_smb2_create_fnum_recv(
1176                         req,
1177                         &fnum,
1178                         &cr,
1179                         NULL,
1180                         &create_contexts_out,
1181                         &symlink);
1182         } else {
1183                 status = cli_ntcreate_recv(req, &fnum, &cr);
1184         }
1185
1186         TALLOC_FREE(req);
1187
1188         if (!NT_STATUS_IS_OK(status)) {
1189                 goto fail;
1190         }
1191
1192         SMB_ASSERT(symlink == NULL);
1193
1194         py_create_contexts_out = py_cli_create_contexts(&create_contexts_out);
1195         TALLOC_FREE(create_contexts_out.blobs);
1196         if (py_create_contexts_out == NULL) {
1197                 goto nomem;
1198         }
1199
1200         py_cr = py_cli_create_returns(&cr);
1201         if (py_cr == NULL) {
1202                 goto nomem;
1203         }
1204
1205         v = PyTuple_New(3);
1206         if (v == NULL) {
1207                 goto nomem;
1208         }
1209         ret = PyTuple_SetItem(v, 0, Py_BuildValue("I", (unsigned)fnum));
1210         if (ret == -1) {
1211                 status = NT_STATUS_INTERNAL_ERROR;
1212                 goto fail;
1213         }
1214         ret = PyTuple_SetItem(v, 1, py_cr);
1215         if (ret == -1) {
1216                 status = NT_STATUS_INTERNAL_ERROR;
1217                 goto fail;
1218         }
1219         ret = PyTuple_SetItem(v, 2, py_create_contexts_out);
1220         if (ret == -1) {
1221                 status = NT_STATUS_INTERNAL_ERROR;
1222                 goto fail;
1223         }
1224
1225         return v;
1226 nomem:
1227         status = NT_STATUS_NO_MEMORY;
1228 fail:
1229         Py_XDECREF(py_create_contexts_out);
1230         Py_XDECREF(py_cr);
1231         Py_XDECREF(v);
1232
1233         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
1234             (symlink != NULL)) {
1235                 PyErr_SetObject(
1236                         PyObject_GetAttrString(
1237                                 PyImport_ImportModule("samba"),
1238                                 "NTSTATUSError"),
1239                         Py_BuildValue(
1240                                 "I,s,O",
1241                                 NT_STATUS_V(status),
1242                                 get_friendly_nt_error_msg(status),
1243                                 py_cli_symlink_error(symlink)));
1244         } else {
1245                 PyErr_SetNTSTATUS(status);
1246         }
1247         return NULL;
1248 }
1249
1250 static PyObject *py_cli_close(struct py_cli_state *self, PyObject *args)
1251 {
1252         struct tevent_req *req;
1253         int fnum;
1254         NTSTATUS status;
1255
1256         if (!PyArg_ParseTuple(args, "i", &fnum)) {
1257                 return NULL;
1258         }
1259
1260         req = cli_close_send(NULL, self->ev, self->cli, fnum);
1261         if (!py_tevent_req_wait_exc(self, req)) {
1262                 return NULL;
1263         }
1264         status = cli_close_recv(req);
1265         TALLOC_FREE(req);
1266
1267         if (!NT_STATUS_IS_OK(status)) {
1268                 PyErr_SetNTSTATUS(status);
1269                 return NULL;
1270         }
1271         Py_RETURN_NONE;
1272 }
1273
1274 static PyObject *py_cli_rename(
1275         struct py_cli_state *self, PyObject *args, PyObject *kwds)
1276 {
1277         char *fname_src = NULL, *fname_dst = NULL;
1278         int replace = false;
1279         struct tevent_req *req = NULL;
1280         NTSTATUS status;
1281         bool ok;
1282
1283         static const char *kwlist[] = { "src", "dst", "replace", NULL };
1284
1285         ok = ParseTupleAndKeywords(
1286                 args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
1287         if (!ok) {
1288                 return NULL;
1289         }
1290
1291         req = cli_rename_send(
1292                 NULL, self->ev, self->cli, fname_src, fname_dst, replace);
1293         if (!py_tevent_req_wait_exc(self, req)) {
1294                 return NULL;
1295         }
1296         status = cli_rename_recv(req);
1297         TALLOC_FREE(req);
1298
1299         if (!NT_STATUS_IS_OK(status)) {
1300                 PyErr_SetNTSTATUS(status);
1301                 return NULL;
1302         }
1303         Py_RETURN_NONE;
1304 }
1305
1306
1307 struct push_state {
1308         char *data;
1309         off_t nread;
1310         off_t total_data;
1311 };
1312
1313 /*
1314  * cli_push() helper to write a chunk of data to a remote file
1315  */
1316 static size_t push_data(uint8_t *buf, size_t n, void *priv)
1317 {
1318         struct push_state *state = (struct push_state *)priv;
1319         char *curr_ptr = NULL;
1320         off_t remaining;
1321         size_t copied_bytes;
1322
1323         if (state->nread >= state->total_data) {
1324                 return 0;
1325         }
1326
1327         curr_ptr = state->data + state->nread;
1328         remaining = state->total_data - state->nread;
1329         copied_bytes = MIN(remaining, n);
1330
1331         memcpy(buf, curr_ptr, copied_bytes);
1332         state->nread += copied_bytes;
1333         return copied_bytes;
1334 }
1335
1336 /*
1337  * Writes a file with the contents specified
1338  */
1339 static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
1340 {
1341         uint16_t fnum;
1342         const char *filename = NULL;
1343         char *data = NULL;
1344         Py_ssize_t size = 0;
1345         NTSTATUS status;
1346         struct tevent_req *req = NULL;
1347         struct push_state state;
1348
1349         if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
1350                               &data, &size)) {
1351                 return NULL;
1352         }
1353
1354         /* create a new file handle for writing to */
1355         req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1356                                 FILE_WRITE_DATA, FILE_ATTRIBUTE_NORMAL,
1357                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
1358                                 FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE,
1359                                 SMB2_IMPERSONATION_IMPERSONATION, 0);
1360         if (!py_tevent_req_wait_exc(self, req)) {
1361                 return NULL;
1362         }
1363         status = cli_ntcreate_recv(req, &fnum, NULL);
1364         TALLOC_FREE(req);
1365         PyErr_NTSTATUS_NOT_OK_RAISE(status);
1366
1367         /* write the new file contents */
1368         state.data = data;
1369         state.nread = 0;
1370         state.total_data = size;
1371
1372         req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
1373                             push_data, &state);
1374         if (!py_tevent_req_wait_exc(self, req)) {
1375                 return NULL;
1376         }
1377         status = cli_push_recv(req);
1378         TALLOC_FREE(req);
1379         PyErr_NTSTATUS_NOT_OK_RAISE(status);
1380
1381         /* close the file handle */
1382         req = cli_close_send(NULL, self->ev, self->cli, fnum);
1383         if (!py_tevent_req_wait_exc(self, req)) {
1384                 return NULL;
1385         }
1386         status = cli_close_recv(req);
1387         PyErr_NTSTATUS_NOT_OK_RAISE(status);
1388
1389         Py_RETURN_NONE;
1390 }
1391
1392 static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
1393                               PyObject *kwds)
1394 {
1395         int fnum;
1396         unsigned mode = 0;
1397         char *buf;
1398         Py_ssize_t buflen;
1399         unsigned long long offset;
1400         struct tevent_req *req;
1401         NTSTATUS status;
1402         size_t written;
1403
1404         static const char *kwlist[] = {
1405                 "fnum", "buffer", "offset", "mode", NULL };
1406
1407         if (!ParseTupleAndKeywords(
1408                     args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
1409                     &fnum, &buf, &buflen, &offset, &mode)) {
1410                 return NULL;
1411         }
1412
1413         req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
1414                              (uint8_t *)buf, offset, buflen);
1415         if (!py_tevent_req_wait_exc(self, req)) {
1416                 return NULL;
1417         }
1418         status = cli_write_recv(req, &written);
1419         TALLOC_FREE(req);
1420
1421         if (!NT_STATUS_IS_OK(status)) {
1422                 PyErr_SetNTSTATUS(status);
1423                 return NULL;
1424         }
1425         return Py_BuildValue("K", (unsigned long long)written);
1426 }
1427
1428 /*
1429  * Returns the size of the given file
1430  */
1431 static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
1432                                 off_t *size)
1433 {
1434         NTSTATUS status;
1435         struct tevent_req *req = NULL;
1436
1437         req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
1438         if (!py_tevent_req_wait_exc(self, req)) {
1439                 return NT_STATUS_INTERNAL_ERROR;
1440         }
1441         status = cli_qfileinfo_basic_recv(
1442                 req, NULL, size, NULL, NULL, NULL, NULL, NULL);
1443         TALLOC_FREE(req);
1444         return status;
1445 }
1446
1447 /*
1448  * Loads the specified file's contents and returns it
1449  */
1450 static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
1451 {
1452         NTSTATUS status;
1453         const char *filename = NULL;
1454         struct tevent_req *req = NULL;
1455         uint16_t fnum;
1456         off_t size;
1457         char *buf = NULL;
1458         off_t nread = 0;
1459         PyObject *result = NULL;
1460
1461         if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
1462                 return NULL;
1463         }
1464
1465         /* get a read file handle */
1466         req = cli_ntcreate_send(NULL, self->ev, self->cli, filename, 0,
1467                                 FILE_READ_DATA | FILE_READ_ATTRIBUTES,
1468                                 FILE_ATTRIBUTE_NORMAL,
1469                                 FILE_SHARE_READ, FILE_OPEN, 0,
1470                                 SMB2_IMPERSONATION_IMPERSONATION, 0);
1471         if (!py_tevent_req_wait_exc(self, req)) {
1472                 return NULL;
1473         }
1474         status = cli_ntcreate_recv(req, &fnum, NULL);
1475         TALLOC_FREE(req);
1476         PyErr_NTSTATUS_NOT_OK_RAISE(status);
1477
1478         /* get a buffer to hold the file contents */
1479         status = py_smb_filesize(self, fnum, &size);
1480         PyErr_NTSTATUS_NOT_OK_RAISE(status);
1481
1482         result = PyBytes_FromStringAndSize(NULL, size);
1483         if (result == NULL) {
1484                 return NULL;
1485         }
1486
1487         /* read the file contents */
1488         buf = PyBytes_AS_STRING(result);
1489         req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
1490                             size, cli_read_sink, &buf);
1491         if (!py_tevent_req_wait_exc(self, req)) {
1492                 Py_XDECREF(result);
1493                 return NULL;
1494         }
1495         status = cli_pull_recv(req, &nread);
1496         TALLOC_FREE(req);
1497         if (!NT_STATUS_IS_OK(status)) {
1498                 Py_XDECREF(result);
1499                 PyErr_SetNTSTATUS(status);
1500                 return NULL;
1501         }
1502
1503         /* close the file handle */
1504         req = cli_close_send(NULL, self->ev, self->cli, fnum);
1505         if (!py_tevent_req_wait_exc(self, req)) {
1506                 Py_XDECREF(result);
1507                 return NULL;
1508         }
1509         status = cli_close_recv(req);
1510         TALLOC_FREE(req);
1511         if (!NT_STATUS_IS_OK(status)) {
1512                 Py_XDECREF(result);
1513                 PyErr_SetNTSTATUS(status);
1514                 return NULL;
1515         }
1516
1517         /* sanity-check we read the expected number of bytes */
1518         if (nread > size) {
1519                 Py_XDECREF(result);
1520                 PyErr_Format(PyExc_IOError,
1521                              "read invalid - got %zu requested %zu",
1522                              nread, size);
1523                 return NULL;
1524         }
1525
1526         if (nread < size) {
1527                 if (_PyBytes_Resize(&result, nread) < 0) {
1528                         return NULL;
1529                 }
1530         }
1531
1532         return result;
1533 }
1534
1535 static PyObject *py_cli_read(struct py_cli_state *self, PyObject *args,
1536                              PyObject *kwds)
1537 {
1538         int fnum;
1539         unsigned long long offset;
1540         unsigned size;
1541         struct tevent_req *req;
1542         NTSTATUS status;
1543         char *buf;
1544         size_t received;
1545         PyObject *result;
1546
1547         static const char *kwlist[] = {
1548                 "fnum", "offset", "size", NULL };
1549
1550         if (!ParseTupleAndKeywords(
1551                     args, kwds, "iKI", kwlist, &fnum, &offset,
1552                     &size)) {
1553                 return NULL;
1554         }
1555
1556         result = PyBytes_FromStringAndSize(NULL, size);
1557         if (result == NULL) {
1558                 return NULL;
1559         }
1560         buf = PyBytes_AS_STRING(result);
1561
1562         req = cli_read_send(NULL, self->ev, self->cli, fnum,
1563                             buf, offset, size);
1564         if (!py_tevent_req_wait_exc(self, req)) {
1565                 Py_XDECREF(result);
1566                 return NULL;
1567         }
1568         status = cli_read_recv(req, &received);
1569         TALLOC_FREE(req);
1570
1571         if (!NT_STATUS_IS_OK(status)) {
1572                 Py_XDECREF(result);
1573                 PyErr_SetNTSTATUS(status);
1574                 return NULL;
1575         }
1576
1577         if (received > size) {
1578                 Py_XDECREF(result);
1579                 PyErr_Format(PyExc_IOError,
1580                              "read invalid - got %zu requested %u",
1581                              received, size);
1582                 return NULL;
1583         }
1584
1585         if (received < size) {
1586                 if (_PyBytes_Resize(&result, received) < 0) {
1587                         return NULL;
1588                 }
1589         }
1590
1591         return result;
1592 }
1593
1594 static PyObject *py_cli_ftruncate(struct py_cli_state *self, PyObject *args,
1595                                   PyObject *kwds)
1596 {
1597         int fnum;
1598         unsigned long long size;
1599         struct tevent_req *req;
1600         NTSTATUS status;
1601
1602         static const char *kwlist[] = {
1603                 "fnum", "size", NULL };
1604
1605         if (!ParseTupleAndKeywords(
1606                     args, kwds, "IK", kwlist, &fnum, &size)) {
1607                 return NULL;
1608         }
1609
1610         req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
1611         if (!py_tevent_req_wait_exc(self, req)) {
1612                 return NULL;
1613         }
1614         status = cli_ftruncate_recv(req);
1615         TALLOC_FREE(req);
1616
1617         if (!NT_STATUS_IS_OK(status)) {
1618                 PyErr_SetNTSTATUS(status);
1619                 return NULL;
1620         }
1621         Py_RETURN_NONE;
1622 }
1623
1624 static PyObject *py_cli_delete_on_close(struct py_cli_state *self,
1625                                         PyObject *args,
1626                                         PyObject *kwds)
1627 {
1628         unsigned fnum, flag;
1629         struct tevent_req *req;
1630         NTSTATUS status;
1631
1632         static const char *kwlist[] = {
1633                 "fnum", "flag", NULL };
1634
1635         if (!ParseTupleAndKeywords(
1636                     args, kwds, "II", kwlist, &fnum, &flag)) {
1637                 return NULL;
1638         }
1639
1640         req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
1641                                           flag);
1642         if (!py_tevent_req_wait_exc(self, req)) {
1643                 return NULL;
1644         }
1645         status = cli_nt_delete_on_close_recv(req);
1646         TALLOC_FREE(req);
1647
1648         if (!NT_STATUS_IS_OK(status)) {
1649                 PyErr_SetNTSTATUS(status);
1650                 return NULL;
1651         }
1652         Py_RETURN_NONE;
1653 }
1654
1655 struct py_cli_notify_state {
1656         PyObject_HEAD
1657         struct py_cli_state *py_cli_state;
1658         struct tevent_req *req;
1659 };
1660
1661 static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
1662 {
1663         TALLOC_FREE(self->req);
1664         if (self->py_cli_state != NULL) {
1665                 Py_DECREF(self->py_cli_state);
1666                 self->py_cli_state = NULL;
1667         }
1668         Py_TYPE(self)->tp_free(self);
1669 }
1670
1671 static PyTypeObject py_cli_notify_state_type;
1672
1673 static PyObject *py_cli_notify(struct py_cli_state *self,
1674                                PyObject *args,
1675                                PyObject *kwds)
1676 {
1677         static const char *kwlist[] = {
1678                 "fnum",
1679                 "buffer_size",
1680                 "completion_filter",
1681                 "recursive",
1682                 NULL
1683         };
1684         unsigned fnum = 0;
1685         unsigned buffer_size = 0;
1686         unsigned completion_filter = 0;
1687         PyObject *py_recursive = Py_False;
1688         bool recursive = false;
1689         struct tevent_req *req = NULL;
1690         struct tevent_queue *send_queue = NULL;
1691         struct tevent_req *flush_req = NULL;
1692         bool ok;
1693         struct py_cli_notify_state *py_notify_state = NULL;
1694         struct timeval endtime;
1695
1696         ok = ParseTupleAndKeywords(args,
1697                                    kwds,
1698                                    "IIIO",
1699                                    kwlist,
1700                                    &fnum,
1701                                    &buffer_size,
1702                                    &completion_filter,
1703                                    &py_recursive);
1704         if (!ok) {
1705                 return NULL;
1706         }
1707
1708         recursive = PyObject_IsTrue(py_recursive);
1709
1710         req = cli_notify_send(NULL,
1711                               self->ev,
1712                               self->cli,
1713                               fnum,
1714                               buffer_size,
1715                               completion_filter,
1716                               recursive);
1717         if (req == NULL) {
1718                 PyErr_NoMemory();
1719                 return NULL;
1720         }
1721
1722         /*
1723          * Just wait for the request being submitted to
1724          * the kernel/socket/wire.
1725          */
1726         send_queue = smbXcli_conn_send_queue(self->cli->conn);
1727         flush_req = tevent_queue_wait_send(req,
1728                                            self->ev,
1729                                            send_queue);
1730         endtime = timeval_current_ofs_msec(self->cli->timeout);
1731         ok = tevent_req_set_endtime(flush_req,
1732                                     self->ev,
1733                                     endtime);
1734         if (!ok) {
1735                 TALLOC_FREE(req);
1736                 PyErr_NoMemory();
1737                 return NULL;
1738         }
1739         ok = py_tevent_req_wait_exc(self, flush_req);
1740         if (!ok) {
1741                 TALLOC_FREE(req);
1742                 return NULL;
1743         }
1744         TALLOC_FREE(flush_req);
1745
1746         py_notify_state = (struct py_cli_notify_state *)
1747                 py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
1748         if (py_notify_state == NULL) {
1749                 TALLOC_FREE(req);
1750                 PyErr_NoMemory();
1751                 return NULL;
1752         }
1753         Py_INCREF(self);
1754         py_notify_state->py_cli_state = self;
1755         py_notify_state->req = req;
1756
1757         return (PyObject *)py_notify_state;
1758 }
1759
1760 static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
1761                                            PyObject *args,
1762                                            PyObject *kwds)
1763 {
1764         struct py_cli_state *py_cli_state = self->py_cli_state;
1765         struct tevent_req *req = self->req;
1766         uint32_t i;
1767         uint32_t num_changes = 0;
1768         struct notify_change *changes = NULL;
1769         PyObject *result = NULL;
1770         NTSTATUS status;
1771         bool ok;
1772         static const char *kwlist[] = {
1773                 "wait",
1774                 NULL
1775         };
1776         PyObject *py_wait = Py_False;
1777         bool wait = false;
1778         bool pending;
1779
1780         ok = ParseTupleAndKeywords(args,
1781                                    kwds,
1782                                    "O",
1783                                    kwlist,
1784                                    &py_wait);
1785         if (!ok) {
1786                 return NULL;
1787         }
1788
1789         wait = PyObject_IsTrue(py_wait);
1790
1791         if (req == NULL) {
1792                 PyErr_SetString(PyExc_RuntimeError,
1793                                 "TODO req == NULL "
1794                                 "- missing change notify request?");
1795                 return NULL;
1796         }
1797
1798         pending = tevent_req_is_in_progress(req);
1799         if (pending && !wait) {
1800                 Py_RETURN_NONE;
1801         }
1802
1803         if (pending) {
1804                 struct timeval endtime;
1805
1806                 endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
1807                 ok = tevent_req_set_endtime(req,
1808                                             py_cli_state->ev,
1809                                             endtime);
1810                 if (!ok) {
1811                         TALLOC_FREE(req);
1812                         PyErr_NoMemory();
1813                         return NULL;
1814                 }
1815         }
1816
1817         ok = py_tevent_req_wait_exc(py_cli_state, req);
1818         self->req = NULL;
1819         Py_DECREF(self->py_cli_state);
1820         self->py_cli_state = NULL;
1821         if (!ok) {
1822                 return NULL;
1823         }
1824
1825         status = cli_notify_recv(req, req, &num_changes, &changes);
1826         if (!NT_STATUS_IS_OK(status)) {
1827                 TALLOC_FREE(req);
1828                 PyErr_SetNTSTATUS(status);
1829                 return NULL;
1830         }
1831
1832         result = Py_BuildValue("[]");
1833         if (result == NULL) {
1834                 TALLOC_FREE(req);
1835                 return NULL;
1836         }
1837
1838         for (i = 0; i < num_changes; i++) {
1839                 PyObject *change = NULL;
1840                 int ret;
1841
1842                 change = Py_BuildValue("{s:s,s:I}",
1843                                        "name", changes[i].name,
1844                                        "action", changes[i].action);
1845                 if (change == NULL) {
1846                         Py_XDECREF(result);
1847                         TALLOC_FREE(req);
1848                         return NULL;
1849                 }
1850
1851                 ret = PyList_Append(result, change);
1852                 Py_DECREF(change);
1853                 if (ret == -1) {
1854                         Py_XDECREF(result);
1855                         TALLOC_FREE(req);
1856                         return NULL;
1857                 }
1858         }
1859
1860         TALLOC_FREE(req);
1861         return result;
1862 }
1863
1864 static PyMethodDef py_cli_notify_state_methods[] = {
1865         {
1866                 .ml_name = "get_changes",
1867                 .ml_meth = (PyCFunction)py_cli_notify_get_changes,
1868                 .ml_flags = METH_VARARGS|METH_KEYWORDS,
1869                 .ml_doc  = "Wait for change notifications: \n"
1870                            "N.get_changes(wait=BOOLEAN) -> "
1871                            "change notifications as a dictionary\n"
1872                            "\t\tList contents of a directory. The keys are, \n"
1873                            "\t\t\tname: name of changed object\n"
1874                            "\t\t\taction: type of the change\n"
1875                            "None is returned if there's no response jet and "
1876                            "wait=False is passed"
1877         },
1878         {
1879                 .ml_name = NULL
1880         }
1881 };
1882
1883 static PyTypeObject py_cli_notify_state_type = {
1884         PyVarObject_HEAD_INIT(NULL, 0)
1885         .tp_name = "libsmb_samba_cwrapper.Notify",
1886         .tp_basicsize = sizeof(struct py_cli_notify_state),
1887         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1888         .tp_doc = "notify request",
1889         .tp_dealloc = (destructor)py_cli_notify_state_dealloc,
1890         .tp_methods = py_cli_notify_state_methods,
1891 };
1892
1893 /*
1894  * Helper to add directory listing entries to an overall Python list
1895  */
1896 static NTSTATUS list_helper(struct file_info *finfo,
1897                             const char *mask, void *state)
1898 {
1899         PyObject *result = (PyObject *)state;
1900         PyObject *file = NULL;
1901         PyObject *size = NULL;
1902         int ret;
1903
1904         /* suppress '.' and '..' in the results we return */
1905         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1906                 return NT_STATUS_OK;
1907         }
1908         size = PyLong_FromUnsignedLongLong(finfo->size);
1909         /*
1910          * Build a dictionary representing the file info.
1911          * Note: Windows does not always return short_name (so it may be None)
1912          */
1913         file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l}",
1914                              "name", finfo->name,
1915                              "attrib", (int)finfo->attr,
1916                              "short_name", finfo->short_name,
1917                              "size", size,
1918                              "mtime",
1919                              convert_timespec_to_time_t(finfo->mtime_ts));
1920
1921         Py_CLEAR(size);
1922
1923         if (file == NULL) {
1924                 return NT_STATUS_NO_MEMORY;
1925         }
1926
1927         ret = PyList_Append(result, file);
1928         Py_CLEAR(file);
1929         if (ret == -1) {
1930                 return NT_STATUS_INTERNAL_ERROR;
1931         }
1932
1933         return NT_STATUS_OK;
1934 }
1935
1936 struct do_listing_state {
1937         const char *mask;
1938         NTSTATUS (*callback_fn)(
1939                 struct file_info *finfo,
1940                 const char *mask,
1941                 void *private_data);
1942         void *private_data;
1943         NTSTATUS status;
1944 };
1945
1946 static void do_listing_cb(struct tevent_req *subreq)
1947 {
1948         struct do_listing_state *state = tevent_req_callback_data_void(subreq);
1949         struct file_info *finfo = NULL;
1950
1951         state->status = cli_list_recv(subreq, NULL, &finfo);
1952         if (!NT_STATUS_IS_OK(state->status)) {
1953                 return;
1954         }
1955         state->callback_fn(finfo, state->mask, state->private_data);
1956         TALLOC_FREE(finfo);
1957 }
1958
1959 static NTSTATUS do_listing(struct py_cli_state *self,
1960                            const char *base_dir, const char *user_mask,
1961                            uint16_t attribute,
1962                            NTSTATUS (*callback_fn)(struct file_info *,
1963                                                    const char *, void *),
1964                            void *priv)
1965 {
1966         char *mask = NULL;
1967         unsigned int info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
1968         struct do_listing_state state = {
1969                 .mask = mask,
1970                 .callback_fn = callback_fn,
1971                 .private_data = priv,
1972         };
1973         struct tevent_req *req = NULL;
1974         NTSTATUS status;
1975
1976         if (user_mask == NULL) {
1977                 mask = talloc_asprintf(NULL, "%s\\*", base_dir);
1978         } else {
1979                 mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
1980         }
1981
1982         if (mask == NULL) {
1983                 return NT_STATUS_NO_MEMORY;
1984         }
1985         dos_format(mask);
1986
1987         req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
1988                             info_level);
1989         if (req == NULL) {
1990                 status = NT_STATUS_NO_MEMORY;
1991                 goto done;
1992         }
1993         tevent_req_set_callback(req, do_listing_cb, &state);
1994
1995         if (!py_tevent_req_wait_exc(self, req)) {
1996                 return NT_STATUS_INTERNAL_ERROR;
1997         }
1998         TALLOC_FREE(req);
1999
2000         status = state.status;
2001         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
2002                 status = NT_STATUS_OK;
2003         }
2004
2005 done:
2006         TALLOC_FREE(mask);
2007         return status;
2008 }
2009
2010 static PyObject *py_cli_list(struct py_cli_state *self,
2011                              PyObject *args,
2012                              PyObject *kwds)
2013 {
2014         char *base_dir;
2015         char *user_mask = NULL;
2016         unsigned int attribute = LIST_ATTRIBUTE_MASK;
2017         NTSTATUS status;
2018         PyObject *result = NULL;
2019         const char *kwlist[] = { "directory", "mask", "attribs", NULL };
2020
2021         if (!ParseTupleAndKeywords(args, kwds, "z|sI:list", kwlist,
2022                                    &base_dir, &user_mask, &attribute)) {
2023                 return NULL;
2024         }
2025
2026         result = Py_BuildValue("[]");
2027         if (result == NULL) {
2028                 return NULL;
2029         }
2030
2031         status = do_listing(self, base_dir, user_mask, attribute,
2032                             list_helper, result);
2033
2034         if (!NT_STATUS_IS_OK(status)) {
2035                 Py_XDECREF(result);
2036                 PyErr_SetNTSTATUS(status);
2037                 return NULL;
2038         }
2039
2040         return result;
2041 }
2042
2043 static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
2044 {
2045         NTSTATUS status;
2046         const char *filename = NULL;
2047         struct tevent_req *req = NULL;
2048         const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2049
2050         if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
2051                 return NULL;
2052         }
2053
2054         req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
2055         if (!py_tevent_req_wait_exc(self, req)) {
2056                 return NULL;
2057         }
2058         status = cli_unlink_recv(req);
2059         TALLOC_FREE(req);
2060         PyErr_NTSTATUS_NOT_OK_RAISE(status);
2061
2062         Py_RETURN_NONE;
2063 }
2064
2065 static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
2066 {
2067         NTSTATUS status;
2068         struct tevent_req *req = NULL;
2069         const char *dirname = NULL;
2070
2071         if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
2072                 return NULL;
2073         }
2074
2075         req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
2076         if (!py_tevent_req_wait_exc(self, req)) {
2077                 return NULL;
2078         }
2079         status = cli_rmdir_recv(req);
2080         TALLOC_FREE(req);
2081         PyErr_NTSTATUS_NOT_OK_RAISE(status);
2082
2083         Py_RETURN_NONE;
2084 }
2085
2086 /*
2087  * Create a directory
2088  */
2089 static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
2090 {
2091         NTSTATUS status;
2092         const char *dirname = NULL;
2093         struct tevent_req *req = NULL;
2094
2095         if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
2096                 return NULL;
2097         }
2098
2099         req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
2100         if (!py_tevent_req_wait_exc(self, req)) {
2101                 return NULL;
2102         }
2103         status = cli_mkdir_recv(req);
2104         TALLOC_FREE(req);
2105         PyErr_NTSTATUS_NOT_OK_RAISE(status);
2106
2107         Py_RETURN_NONE;
2108 }
2109
2110 /*
2111  * Does a whoami call
2112  */
2113 static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
2114                                      PyObject *Py_UNUSED(ignored))
2115 {
2116         TALLOC_CTX *frame = talloc_stackframe();
2117         NTSTATUS status;
2118         struct tevent_req *req = NULL;
2119         uint64_t uid;
2120         uint64_t gid;
2121         uint32_t num_gids;
2122         uint64_t *gids = NULL;
2123         uint32_t num_sids;
2124         struct dom_sid *sids = NULL;
2125         bool guest;
2126         PyObject *py_gids = NULL;
2127         PyObject *py_sids = NULL;
2128         PyObject *py_guest = NULL;
2129         PyObject *py_ret = NULL;
2130         Py_ssize_t i;
2131
2132         req = cli_posix_whoami_send(frame, self->ev, self->cli);
2133         if (!py_tevent_req_wait_exc(self, req)) {
2134                 goto fail;
2135         }
2136         status = cli_posix_whoami_recv(req,
2137                                 frame,
2138                                 &uid,
2139                                 &gid,
2140                                 &num_gids,
2141                                 &gids,
2142                                 &num_sids,
2143                                 &sids,
2144                                 &guest);
2145         if (!NT_STATUS_IS_OK(status)) {
2146                 PyErr_SetNTSTATUS(status);
2147                 goto fail;
2148         }
2149         if (num_gids > PY_SSIZE_T_MAX) {
2150                 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
2151                 goto fail;
2152         }
2153         if (num_sids > PY_SSIZE_T_MAX) {
2154                 PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
2155                 goto fail;
2156         }
2157
2158         py_gids = PyList_New(num_gids);
2159         if (!py_gids) {
2160                 goto fail;
2161         }
2162         for (i = 0; i < num_gids; ++i) {
2163                 int ret;
2164                 PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
2165                 if (!py_item) {
2166                         goto fail2;
2167                 }
2168
2169                 ret = PyList_SetItem(py_gids, i, py_item);
2170                 if (ret) {
2171                         goto fail2;
2172                 }
2173         }
2174         py_sids = PyList_New(num_sids);
2175         if (!py_sids) {
2176                 goto fail2;
2177         }
2178         for (i = 0; i < num_sids; ++i) {
2179                 int ret;
2180                 struct dom_sid *sid;
2181                 PyObject *py_item;
2182
2183                 sid = dom_sid_dup(frame, &sids[i]);
2184                 if (!sid) {
2185                         PyErr_NoMemory();
2186                         goto fail3;
2187                 }
2188
2189                 py_item = pytalloc_steal(dom_sid_Type, sid);
2190                 if (!py_item) {
2191                         PyErr_NoMemory();
2192                         goto fail3;
2193                 }
2194
2195                 ret = PyList_SetItem(py_sids, i, py_item);
2196                 if (ret) {
2197                         goto fail3;
2198                 }
2199         }
2200
2201         py_guest = guest ? Py_True : Py_False;
2202
2203         py_ret = Py_BuildValue("KKNNO",
2204                         uid,
2205                         gid,
2206                         py_gids,
2207                         py_sids,
2208                         py_guest);
2209         if (!py_ret) {
2210                 goto fail3;
2211         }
2212
2213         TALLOC_FREE(frame);
2214         return py_ret;
2215
2216 fail3:
2217         Py_CLEAR(py_sids);
2218
2219 fail2:
2220         Py_CLEAR(py_gids);
2221
2222 fail:
2223         TALLOC_FREE(frame);
2224         return NULL;
2225 }
2226
2227 /*
2228  * Checks existence of a directory
2229  */
2230 static bool check_dir_path(struct py_cli_state *self, const char *path)
2231 {
2232         NTSTATUS status;
2233         struct tevent_req *req = NULL;
2234
2235         req = cli_chkpath_send(NULL, self->ev, self->cli, path);
2236         if (!py_tevent_req_wait_exc(self, req)) {
2237                 return false;
2238         }
2239         status = cli_chkpath_recv(req);
2240         TALLOC_FREE(req);
2241
2242         return NT_STATUS_IS_OK(status);
2243 }
2244
2245 static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
2246 {
2247         const char *path = NULL;
2248         bool dir_exists;
2249
2250         if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
2251                 return NULL;
2252         }
2253
2254         dir_exists = check_dir_path(self, path);
2255         return PyBool_FromLong(dir_exists);
2256 }
2257
2258 static PyObject *py_smb_have_posix(struct py_cli_state *self,
2259                                    PyObject *Py_UNUSED(ignored))
2260 {
2261         bool posix = smbXcli_conn_have_posix(self->cli->conn);
2262
2263         if (posix) {
2264                 Py_RETURN_TRUE;
2265         }
2266         Py_RETURN_FALSE;
2267 }
2268
2269 static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
2270 {
2271         int fnum;
2272         unsigned sinfo;
2273         struct tevent_req *req = NULL;
2274         struct security_descriptor *sd = NULL;
2275         NTSTATUS status;
2276
2277         if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
2278                 return NULL;
2279         }
2280
2281         req = cli_query_security_descriptor_send(
2282                 NULL, self->ev, self->cli, fnum, sinfo);
2283         if (!py_tevent_req_wait_exc(self, req)) {
2284                 return NULL;
2285         }
2286         status = cli_query_security_descriptor_recv(req, NULL, &sd);
2287         PyErr_NTSTATUS_NOT_OK_RAISE(status);
2288
2289         return py_return_ndr_struct(
2290                 "samba.dcerpc.security", "descriptor", sd, sd);
2291 }
2292
2293 static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
2294 {
2295         PyObject *py_sd = NULL;
2296         struct tevent_req *req = NULL;
2297         struct security_descriptor *sd = NULL;
2298         uint16_t fnum;
2299         unsigned int sinfo;
2300         NTSTATUS status;
2301
2302         if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
2303                 return NULL;
2304         }
2305
2306         sd = pytalloc_get_type(py_sd, struct security_descriptor);
2307         if (!sd) {
2308                 PyErr_Format(PyExc_TypeError,
2309                         "Expected dcerpc.security.descriptor as argument, got %s",
2310                         pytalloc_get_name(py_sd));
2311                 return NULL;
2312         }
2313
2314         req = cli_set_security_descriptor_send(
2315                 NULL, self->ev, self->cli, fnum, sinfo, sd);
2316         if (!py_tevent_req_wait_exc(self, req)) {
2317                 return NULL;
2318         }
2319
2320         status = cli_set_security_descriptor_recv(req);
2321         PyErr_NTSTATUS_NOT_OK_RAISE(status);
2322
2323         Py_RETURN_NONE;
2324 }
2325
2326 static PyObject *py_smb_smb1_posix(
2327         struct py_cli_state *self, PyObject *Py_UNUSED(ignored))
2328 {
2329         NTSTATUS status;
2330         struct tevent_req *req = NULL;
2331         uint16_t major, minor;
2332         uint32_t caplow, caphigh;
2333         PyObject *result = NULL;
2334
2335         req = cli_unix_extensions_version_send(NULL, self->ev, self->cli);
2336         if (!py_tevent_req_wait_exc(self, req)) {
2337                 return NULL;
2338         }
2339         status = cli_unix_extensions_version_recv(
2340                 req, &major, &minor, &caplow, &caphigh);
2341         TALLOC_FREE(req);
2342         if (!NT_STATUS_IS_OK(status)) {
2343                 PyErr_SetNTSTATUS(status);
2344                 return NULL;
2345         }
2346
2347         req = cli_set_unix_extensions_capabilities_send(
2348                 NULL, self->ev, self->cli, major, minor, caplow, caphigh);
2349         if (!py_tevent_req_wait_exc(self, req)) {
2350                 return NULL;
2351         }
2352         status = cli_set_unix_extensions_capabilities_recv(req);
2353         TALLOC_FREE(req);
2354         if (!NT_STATUS_IS_OK(status)) {
2355                 PyErr_SetNTSTATUS(status);
2356                 return NULL;
2357         }
2358
2359         result = Py_BuildValue(
2360                 "[IIII]",
2361                 (unsigned)minor,
2362                 (unsigned)major,
2363                 (unsigned)caplow,
2364                 (unsigned)caphigh);
2365         return result;
2366 }
2367
2368 static PyObject *py_smb_smb1_readlink(
2369         struct py_cli_state *self, PyObject *args)
2370 {
2371         NTSTATUS status;
2372         const char *filename = NULL;
2373         struct tevent_req *req = NULL;
2374         char *target = NULL;
2375         PyObject *result = NULL;
2376
2377         if (!PyArg_ParseTuple(args, "s:smb1_readlink", &filename)) {
2378                 return NULL;
2379         }
2380
2381         req = cli_posix_readlink_send(NULL, self->ev, self->cli, filename);
2382         if (!py_tevent_req_wait_exc(self, req)) {
2383                 return NULL;
2384         }
2385         status = cli_posix_readlink_recv(req, NULL, &target);
2386         TALLOC_FREE(req);
2387         if (!NT_STATUS_IS_OK(status)) {
2388                 PyErr_SetNTSTATUS(status);
2389                 return NULL;
2390         }
2391
2392         result = PyBytes_FromString(target);
2393         TALLOC_FREE(target);
2394         return result;
2395 }
2396
2397 static PyObject *py_smb_smb1_symlink(
2398         struct py_cli_state *self, PyObject *args)
2399 {
2400         NTSTATUS status;
2401         const char *target = NULL, *newname = NULL;
2402         struct tevent_req *req = NULL;
2403
2404         if (!PyArg_ParseTuple(args, "ss:smb1_symlink", &target, &newname)) {
2405                 return NULL;
2406         }
2407
2408         req = cli_posix_symlink_send(
2409                 NULL, self->ev, self->cli, target, newname);
2410         if (!py_tevent_req_wait_exc(self, req)) {
2411                 return NULL;
2412         }
2413         status = cli_posix_symlink_recv(req);
2414         TALLOC_FREE(req);
2415         if (!NT_STATUS_IS_OK(status)) {
2416                 PyErr_SetNTSTATUS(status);
2417                 return NULL;
2418         }
2419
2420         Py_RETURN_NONE;
2421 }
2422
2423 static PyMethodDef py_cli_state_methods[] = {
2424         { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
2425           "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
2426         { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
2427           "Ping the server connection" },
2428         { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
2429                 METH_VARARGS|METH_KEYWORDS,
2430           "Open a file" },
2431         { "create_ex",
2432           PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create_ex),
2433           METH_VARARGS|METH_KEYWORDS,
2434           "Open a file, SMB2 version returning create contexts" },
2435         { "close", (PyCFunction)py_cli_close, METH_VARARGS,
2436           "Close a file handle" },
2437         { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
2438                 METH_VARARGS|METH_KEYWORDS,
2439           "Write to a file handle" },
2440         { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
2441                 METH_VARARGS|METH_KEYWORDS,
2442           "Read from a file handle" },
2443         { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
2444                         py_cli_ftruncate),
2445           METH_VARARGS|METH_KEYWORDS,
2446           "Truncate a file" },
2447         { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
2448                                          py_cli_delete_on_close),
2449           METH_VARARGS|METH_KEYWORDS,
2450           "Set/Reset the delete on close flag" },
2451         { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
2452           METH_VARARGS|METH_KEYWORDS,
2453           "Wait for change notifications: \n"
2454           "notify(fnum, buffer_size, completion_filter...) -> "
2455           "libsmb_samba_internal.Notify request handle\n" },
2456         { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
2457                 METH_VARARGS|METH_KEYWORDS,
2458           "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
2459           "directory contents as a dictionary\n"
2460           "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
2461           "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
2462           "\t\tList contents of a directory. The keys are, \n"
2463           "\t\t\tname: Long name of the directory item\n"
2464           "\t\t\tshort_name: Short name of the directory item\n"
2465           "\t\t\tsize: File size in bytes\n"
2466           "\t\t\tattrib: Attributes\n"
2467           "\t\t\tmtime: Modification time\n" },
2468         { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
2469           METH_VARARGS, "Wait for an oplock break" },
2470         { "unlink", (PyCFunction)py_smb_unlink,
2471           METH_VARARGS,
2472           "unlink(path) -> None\n\n \t\tDelete a file." },
2473         { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
2474           "mkdir(path) -> None\n\n \t\tCreate a directory." },
2475         { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
2476         "posix_whoami() -> (uid, gid, gids, sids, guest)" },
2477         { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
2478           "rmdir(path) -> None\n\n \t\tDelete a directory." },
2479         { "rename",
2480           PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
2481           METH_VARARGS|METH_KEYWORDS,
2482           "rename(src,dst) -> None\n\n \t\tRename a file." },
2483         { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
2484           "chkpath(dir_path) -> True or False\n\n"
2485           "\t\tReturn true if directory exists, false otherwise." },
2486         { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
2487           "savefile(path, bytes) -> None\n\n"
2488           "\t\tWrite bytes to file." },
2489         { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
2490           "loadfile(path) -> file contents as a bytes object"
2491           "\n\n\t\tRead contents of a file." },
2492         { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
2493           "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
2494           "\t\tGet security descriptor for opened file." },
2495         { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
2496           "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
2497           "\t\tSet security descriptor for opened file." },
2498         { "have_posix",
2499           (PyCFunction)py_smb_have_posix,
2500           METH_NOARGS,
2501           "have_posix() -> True/False\n\n"
2502           "\t\tReturn if the server has posix extensions"
2503         },
2504         { "smb1_posix",
2505           (PyCFunction)py_smb_smb1_posix,
2506           METH_NOARGS,
2507           "Negotiate SMB1 posix extensions",
2508         },
2509         { "smb1_readlink",
2510           (PyCFunction)py_smb_smb1_readlink,
2511           METH_VARARGS,
2512           "smb1_readlink(path) -> link target",
2513         },
2514         { "smb1_symlink",
2515           (PyCFunction)py_smb_smb1_symlink,
2516           METH_VARARGS,
2517           "smb1_symlink(target, newname) -> None",
2518         },
2519         { NULL, NULL, 0, NULL }
2520 };
2521
2522 static PyTypeObject py_cli_state_type = {
2523         PyVarObject_HEAD_INIT(NULL, 0)
2524         .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
2525         .tp_basicsize = sizeof(struct py_cli_state),
2526         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2527         .tp_doc = "libsmb cwrapper connection",
2528         .tp_new = py_cli_state_new,
2529         .tp_init = (initproc)py_cli_state_init,
2530         .tp_dealloc = (destructor)py_cli_state_dealloc,
2531         .tp_methods = py_cli_state_methods,
2532 };
2533
2534 static PyMethodDef py_libsmb_methods[] = {
2535         {0},
2536 };
2537
2538 void initlibsmb_samba_cwrapper(void);
2539
2540 static struct PyModuleDef moduledef = {
2541     PyModuleDef_HEAD_INIT,
2542     .m_name = "libsmb_samba_cwrapper",
2543     .m_doc = "libsmb wrapper",
2544     .m_size = -1,
2545     .m_methods = py_libsmb_methods,
2546 };
2547
2548 MODULE_INIT_FUNC(libsmb_samba_cwrapper)
2549 {
2550         PyObject *m = NULL;
2551         PyObject *mod = NULL;
2552
2553         talloc_stackframe();
2554
2555         if (PyType_Ready(&py_cli_state_type) < 0) {
2556                 return NULL;
2557         }
2558         if (PyType_Ready(&py_cli_notify_state_type) < 0) {
2559                 return NULL;
2560         }
2561
2562         m = PyModule_Create(&moduledef);
2563         if (m == NULL) {
2564                 return m;
2565         }
2566
2567         /* Import dom_sid type from dcerpc.security */
2568         mod = PyImport_ImportModule("samba.dcerpc.security");
2569         if (mod == NULL) {
2570                 return NULL;
2571         }
2572
2573         dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
2574         if (dom_sid_Type == NULL) {
2575                 Py_DECREF(mod);
2576                 return NULL;
2577         }
2578
2579         Py_INCREF(&py_cli_state_type);
2580         PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
2581
2582 #define ADD_FLAGS(val)  PyModule_AddObject(m, #val, PyLong_FromLong(val))
2583
2584         ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
2585         ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
2586         ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
2587         ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
2588         ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
2589         ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
2590         ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
2591         ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
2592         ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
2593         ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
2594         ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
2595         ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
2596         ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
2597         ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
2598         ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
2599         ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
2600
2601         ADD_FLAGS(FILE_SHARE_READ);
2602         ADD_FLAGS(FILE_SHARE_WRITE);
2603         ADD_FLAGS(FILE_SHARE_DELETE);
2604
2605         /* change notify completion filter flags */
2606         ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
2607         ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
2608         ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
2609         ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
2610         ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
2611         ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
2612         ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
2613         ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
2614         ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
2615         ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
2616         ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
2617         ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
2618         ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
2619         ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
2620
2621         /* change notify action results */
2622         ADD_FLAGS(NOTIFY_ACTION_ADDED);
2623         ADD_FLAGS(NOTIFY_ACTION_REMOVED);
2624         ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
2625         ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
2626         ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
2627         ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
2628         ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
2629         ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
2630
2631 #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
2632
2633         ADD_STRING(SMB2_CREATE_TAG_EXTA);
2634         ADD_STRING(SMB2_CREATE_TAG_MXAC);
2635         ADD_STRING(SMB2_CREATE_TAG_SECD);
2636         ADD_STRING(SMB2_CREATE_TAG_DHNQ);
2637         ADD_STRING(SMB2_CREATE_TAG_DHNC);
2638         ADD_STRING(SMB2_CREATE_TAG_ALSI);
2639         ADD_STRING(SMB2_CREATE_TAG_TWRP);
2640         ADD_STRING(SMB2_CREATE_TAG_QFID);
2641         ADD_STRING(SMB2_CREATE_TAG_RQLS);
2642         ADD_STRING(SMB2_CREATE_TAG_DH2Q);
2643         ADD_STRING(SMB2_CREATE_TAG_DH2C);
2644         ADD_STRING(SMB2_CREATE_TAG_AAPL);
2645         ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
2646         ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
2647         ADD_STRING(SMB2_CREATE_TAG_POSIX);
2648
2649         return m;
2650 }