Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * SMB client Python bindings used internally by Samba (for things like
5 : * samba-tool). These Python bindings may change without warning, and so
6 : * should not be used outside of the Samba codebase.
7 : *
8 : * Copyright (C) Volker Lendecke 2012
9 : *
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 3 of the License, or
13 : * (at your option) any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : /*
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 693 : static PyTypeObject *get_pytype(const char *module, const char *type)
70 : {
71 : PyObject *mod;
72 : PyTypeObject *result;
73 :
74 693 : mod = PyImport_ImportModule(module);
75 693 : if (mod == NULL) {
76 0 : PyErr_Format(PyExc_RuntimeError,
77 : "Unable to import %s to check type %s",
78 : module, type);
79 0 : return NULL;
80 : }
81 693 : result = (PyTypeObject *)PyObject_GetAttrString(mod, type);
82 693 : Py_DECREF(mod);
83 693 : if (result == NULL) {
84 0 : PyErr_Format(PyExc_RuntimeError,
85 : "Unable to find type %s in module %s",
86 : module, type);
87 0 : return NULL;
88 : }
89 693 : 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 3874 : static int ParseTupleAndKeywords(PyObject *args, PyObject *kw,
98 : const char *format, const char * const *keywords,
99 : ...)
100 : {
101 3874 : char **_keywords = discard_const_p(char *, keywords);
102 : va_list a;
103 : int ret;
104 3874 : va_start(a, keywords);
105 3874 : ret = PyArg_VaParseTupleAndKeywords(args, kw, format,
106 : _keywords, a);
107 3874 : va_end(a);
108 3874 : 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 0 : static void *py_cli_state_poll_thread(void *private_data)
153 : {
154 0 : struct py_cli_state *self = (struct py_cli_state *)private_data;
155 0 : struct py_cli_thread *t = self->thread_state;
156 : PyGILState_STATE gstate;
157 :
158 0 : gstate = PyGILState_Ensure();
159 :
160 0 : while (!t->do_shutdown) {
161 : int ret;
162 0 : ret = tevent_loop_once(self->ev);
163 0 : assert(ret == 0);
164 : }
165 0 : PyGILState_Release(gstate);
166 0 : return NULL;
167 : }
168 :
169 0 : static void py_cli_state_trace_callback(enum tevent_trace_point point,
170 : void *private_data)
171 : {
172 0 : struct py_cli_state *self = (struct py_cli_state *)private_data;
173 0 : struct py_cli_thread *t = self->thread_state;
174 :
175 0 : switch(point) {
176 0 : case TEVENT_TRACE_BEFORE_WAIT:
177 0 : assert(t->py_threadstate == NULL);
178 0 : t->py_threadstate = PyEval_SaveThread();
179 0 : break;
180 0 : case TEVENT_TRACE_AFTER_WAIT:
181 0 : assert(t->py_threadstate != NULL);
182 0 : PyEval_RestoreThread(t->py_threadstate);
183 0 : t->py_threadstate = NULL;
184 0 : break;
185 0 : default:
186 0 : break;
187 : }
188 0 : }
189 :
190 0 : 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 0 : struct py_cli_state *self = (struct py_cli_state *)private_data;
196 0 : struct py_cli_thread *t = self->thread_state;
197 :
198 0 : if ((flags & TEVENT_FD_READ) == 0) {
199 0 : return;
200 : }
201 0 : TALLOC_FREE(t->shutdown_fde);
202 0 : t->do_shutdown = true;
203 : }
204 :
205 0 : static int py_cli_thread_destructor(struct py_cli_thread *t)
206 : {
207 0 : 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 0 : written = write(t->shutdown_pipe[1], &c, 1);
216 0 : } while ((written == -1) && (errno == EINTR));
217 :
218 : /*
219 : * Allow the poll thread to do its own cleanup under the GIL
220 : */
221 0 : Py_BEGIN_ALLOW_THREADS
222 0 : ret = pthread_join(t->id, NULL);
223 0 : Py_END_ALLOW_THREADS
224 0 : assert(ret == 0);
225 :
226 0 : if (t->shutdown_pipe[0] != -1) {
227 0 : close(t->shutdown_pipe[0]);
228 0 : t->shutdown_pipe[0] = -1;
229 : }
230 0 : if (t->shutdown_pipe[1] != -1) {
231 0 : close(t->shutdown_pipe[1]);
232 0 : t->shutdown_pipe[1] = -1;
233 : }
234 0 : return 0;
235 : }
236 :
237 : static int py_tevent_cond_req_wait(struct tevent_context *ev,
238 : struct tevent_req *req);
239 :
240 0 : static bool py_cli_state_setup_mt_ev(struct py_cli_state *self)
241 : {
242 0 : struct py_cli_thread *t = NULL;
243 : int ret;
244 :
245 0 : self->ev = tevent_context_init_byname(NULL, "poll_mt");
246 0 : if (self->ev == NULL) {
247 0 : goto fail;
248 : }
249 0 : samba_tevent_set_debug(self->ev, "pylibsmb_tevent_mt");
250 0 : tevent_set_trace_callback(self->ev, py_cli_state_trace_callback, self);
251 :
252 0 : self->req_wait_fn = py_tevent_cond_req_wait;
253 :
254 0 : self->thread_state = talloc_zero(NULL, struct py_cli_thread);
255 0 : if (self->thread_state == NULL) {
256 0 : goto fail;
257 : }
258 0 : t = self->thread_state;
259 :
260 0 : ret = pipe(t->shutdown_pipe);
261 0 : if (ret == -1) {
262 0 : goto fail;
263 : }
264 0 : 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 0 : if (t->shutdown_fde == NULL) {
268 0 : goto fail;
269 : }
270 :
271 0 : PyEval_InitThreads();
272 :
273 0 : ret = pthread_create(&t->id, NULL, py_cli_state_poll_thread, self);
274 0 : if (ret != 0) {
275 0 : goto fail;
276 : }
277 0 : talloc_set_destructor(self->thread_state, py_cli_thread_destructor);
278 0 : return true;
279 :
280 0 : fail:
281 0 : if (t != NULL) {
282 0 : TALLOC_FREE(t->shutdown_fde);
283 :
284 0 : if (t->shutdown_pipe[0] != -1) {
285 0 : close(t->shutdown_pipe[0]);
286 0 : t->shutdown_pipe[0] = -1;
287 : }
288 0 : if (t->shutdown_pipe[1] != -1) {
289 0 : close(t->shutdown_pipe[1]);
290 0 : t->shutdown_pipe[1] = -1;
291 : }
292 : }
293 :
294 0 : TALLOC_FREE(self->thread_state);
295 0 : TALLOC_FREE(self->ev);
296 0 : 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 0 : static int py_tevent_cond_wait(struct py_tevent_cond *cond)
308 : {
309 : int ret, result;
310 :
311 0 : result = pthread_mutex_init(&cond->mutex, NULL);
312 0 : if (result != 0) {
313 0 : goto fail;
314 : }
315 0 : result = pthread_cond_init(&cond->cond, NULL);
316 0 : if (result != 0) {
317 0 : goto fail_mutex;
318 : }
319 :
320 0 : result = pthread_mutex_lock(&cond->mutex);
321 0 : if (result != 0) {
322 0 : goto fail_cond;
323 : }
324 :
325 0 : cond->is_done = false;
326 :
327 0 : while (!cond->is_done) {
328 :
329 0 : Py_BEGIN_ALLOW_THREADS
330 0 : result = pthread_cond_wait(&cond->cond, &cond->mutex);
331 0 : Py_END_ALLOW_THREADS
332 :
333 0 : if (result != 0) {
334 0 : goto fail_unlock;
335 : }
336 : }
337 :
338 0 : fail_unlock:
339 0 : ret = pthread_mutex_unlock(&cond->mutex);
340 0 : assert(ret == 0);
341 0 : fail_cond:
342 0 : ret = pthread_cond_destroy(&cond->cond);
343 0 : assert(ret == 0);
344 0 : fail_mutex:
345 0 : ret = pthread_mutex_destroy(&cond->mutex);
346 0 : assert(ret == 0);
347 0 : fail:
348 0 : return result;
349 : }
350 :
351 0 : static int py_tevent_cond_req_wait(struct tevent_context *ev,
352 : struct tevent_req *req)
353 : {
354 : struct py_tevent_cond cond;
355 0 : tevent_req_set_callback(req, py_tevent_signalme, &cond);
356 0 : return py_tevent_cond_wait(&cond);
357 : }
358 :
359 0 : static void py_tevent_cond_signal(struct py_tevent_cond *cond)
360 : {
361 : int ret;
362 :
363 0 : ret = pthread_mutex_lock(&cond->mutex);
364 0 : assert(ret == 0);
365 :
366 0 : cond->is_done = true;
367 :
368 0 : ret = pthread_cond_signal(&cond->cond);
369 0 : assert(ret == 0);
370 0 : ret = pthread_mutex_unlock(&cond->mutex);
371 0 : assert(ret == 0);
372 0 : }
373 :
374 0 : static void py_tevent_signalme(struct tevent_req *req)
375 : {
376 : struct py_tevent_cond *cond = (struct py_tevent_cond *)
377 0 : tevent_req_callback_data_void(req);
378 :
379 0 : py_tevent_cond_signal(cond);
380 0 : }
381 :
382 : #endif
383 :
384 : static int py_tevent_req_wait(struct tevent_context *ev,
385 : struct tevent_req *req);
386 :
387 693 : static bool py_cli_state_setup_ev(struct py_cli_state *self)
388 : {
389 693 : self->ev = tevent_context_init(NULL);
390 693 : if (self->ev == NULL) {
391 0 : return false;
392 : }
393 :
394 693 : samba_tevent_set_debug(self->ev, "pylibsmb_tevent");
395 :
396 693 : self->req_wait_fn = py_tevent_req_wait;
397 :
398 693 : return true;
399 : }
400 :
401 13883 : static int py_tevent_req_wait(struct tevent_context *ev,
402 : struct tevent_req *req)
403 : {
404 138524 : while (tevent_req_is_in_progress(req)) {
405 : int ret;
406 :
407 124641 : ret = tevent_loop_once(ev);
408 124641 : if (ret != 0) {
409 0 : return ret;
410 : }
411 : }
412 13883 : return 0;
413 : }
414 :
415 13883 : static bool py_tevent_req_wait_exc(struct py_cli_state *self,
416 : struct tevent_req *req)
417 : {
418 : int ret;
419 :
420 13883 : if (req == NULL) {
421 0 : PyErr_NoMemory();
422 0 : return false;
423 : }
424 13883 : ret = self->req_wait_fn(self->ev, req);
425 13883 : if (ret != 0) {
426 0 : TALLOC_FREE(req);
427 0 : errno = ret;
428 0 : PyErr_SetFromErrno(PyExc_RuntimeError);
429 0 : return false;
430 : }
431 13883 : return true;
432 : }
433 :
434 693 : static PyObject *py_cli_state_new(PyTypeObject *type, PyObject *args,
435 : PyObject *kwds)
436 : {
437 : struct py_cli_state *self;
438 :
439 693 : self = (struct py_cli_state *)type->tp_alloc(type, 0);
440 693 : if (self == NULL) {
441 0 : return NULL;
442 : }
443 693 : self->cli = NULL;
444 693 : self->ev = NULL;
445 693 : self->thread_state = NULL;
446 693 : self->oplock_waiter = NULL;
447 693 : self->oplock_cond = NULL;
448 693 : self->oplock_breaks = NULL;
449 693 : return (PyObject *)self;
450 : }
451 :
452 0 : static struct smb2_negotiate_contexts *py_cli_get_negotiate_contexts(
453 : TALLOC_CTX *mem_ctx, PyObject *list)
454 : {
455 0 : struct smb2_negotiate_contexts *ctxs = NULL;
456 : Py_ssize_t i, len;
457 : int ret;
458 :
459 0 : ret = PyList_Check(list);
460 0 : if (!ret) {
461 0 : goto fail;
462 : }
463 :
464 0 : len = PyList_Size(list);
465 0 : if (len == 0) {
466 0 : goto fail;
467 : }
468 :
469 0 : ctxs = talloc_zero(mem_ctx, struct smb2_negotiate_contexts);
470 0 : if (ctxs == NULL) {
471 0 : goto fail;
472 : }
473 :
474 0 : for (i=0; i<len; i++) {
475 : NTSTATUS status;
476 :
477 0 : PyObject *t = PyList_GetItem(list, i);
478 : Py_ssize_t tlen;
479 :
480 0 : PyObject *ptype = NULL;
481 : long type;
482 :
483 0 : PyObject *pdata = NULL;
484 0 : DATA_BLOB data = { .data = NULL, };
485 :
486 0 : if (t == NULL) {
487 0 : goto fail;
488 : }
489 :
490 0 : ret = PyTuple_Check(t);
491 0 : if (!ret) {
492 0 : goto fail;
493 : }
494 :
495 0 : tlen = PyTuple_Size(t);
496 0 : if (tlen != 2) {
497 0 : goto fail;
498 : }
499 :
500 0 : ptype = PyTuple_GetItem(t, 0);
501 0 : if (ptype == NULL) {
502 0 : goto fail;
503 : }
504 0 : type = PyLong_AsLong(ptype);
505 0 : if ((type < 0) || (type > UINT16_MAX)) {
506 0 : goto fail;
507 : }
508 :
509 0 : pdata = PyTuple_GetItem(t, 1);
510 :
511 0 : ret = PyBytes_Check(pdata);
512 0 : if (!ret) {
513 0 : goto fail;
514 : }
515 :
516 0 : data.data = (uint8_t *)PyBytes_AsString(pdata);
517 0 : data.length = PyBytes_Size(pdata);
518 :
519 0 : status = smb2_negotiate_context_add(
520 0 : ctxs, ctxs, type, data.data, data.length);
521 0 : if (!NT_STATUS_IS_OK(status)) {
522 0 : goto fail;
523 : }
524 : }
525 0 : return ctxs;
526 :
527 0 : fail:
528 0 : TALLOC_FREE(ctxs);
529 0 : return NULL;
530 : }
531 :
532 : static void py_cli_got_oplock_break(struct tevent_req *req);
533 :
534 693 : 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 693 : PyObject *creds = NULL;
540 : struct cli_credentials *cli_creds;
541 693 : PyObject *py_lp = Py_None;
542 693 : PyObject *py_multi_threaded = Py_False;
543 693 : bool multi_threaded = false;
544 693 : PyObject *py_force_smb1 = Py_False;
545 693 : bool force_smb1 = false;
546 693 : PyObject *py_ipc = Py_False;
547 693 : PyObject *py_posix = Py_False;
548 693 : PyObject *py_negotiate_contexts = NULL;
549 693 : struct smb2_negotiate_contexts *negotiate_contexts = NULL;
550 693 : bool use_ipc = false;
551 693 : bool request_posix = false;
552 : struct tevent_req *req;
553 : bool ret;
554 693 : 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 693 : PyTypeObject *py_type_Credentials = get_pytype(
566 : "samba.credentials", "Credentials");
567 693 : if (py_type_Credentials == NULL) {
568 0 : return -1;
569 : }
570 :
571 693 : 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 693 : Py_DECREF(py_type_Credentials);
582 :
583 693 : if (!ret) {
584 0 : return -1;
585 : }
586 :
587 693 : multi_threaded = PyObject_IsTrue(py_multi_threaded);
588 693 : force_smb1 = PyObject_IsTrue(py_force_smb1);
589 :
590 693 : 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 3 : flags = CLI_FULL_CONNECTION_FORCE_SMB1;
598 : }
599 :
600 693 : use_ipc = PyObject_IsTrue(py_ipc);
601 693 : if (use_ipc) {
602 39 : flags |= CLI_FULL_CONNECTION_IPC;
603 : }
604 :
605 693 : request_posix = PyObject_IsTrue(py_posix);
606 693 : if (request_posix) {
607 0 : flags |= CLI_FULL_CONNECTION_REQUEST_POSIX;
608 : }
609 :
610 693 : if (py_negotiate_contexts != NULL) {
611 0 : negotiate_contexts = py_cli_get_negotiate_contexts(
612 : talloc_tos(), py_negotiate_contexts);
613 0 : if (negotiate_contexts == NULL) {
614 0 : return -1;
615 : }
616 : }
617 :
618 693 : if (multi_threaded) {
619 : #ifdef HAVE_PTHREAD
620 0 : ret = py_cli_state_setup_mt_ev(self);
621 0 : if (!ret) {
622 0 : return -1;
623 : }
624 : #else
625 : PyErr_SetString(PyExc_RuntimeError,
626 : "No PTHREAD support available");
627 : return -1;
628 : #endif
629 : } else {
630 693 : ret = py_cli_state_setup_ev(self);
631 693 : if (!ret) {
632 0 : return -1;
633 : }
634 : }
635 :
636 693 : if (creds == NULL) {
637 0 : cli_creds = cli_credentials_init_anon(NULL);
638 : } else {
639 693 : cli_creds = PyCredentials_AsCliCredentials(creds);
640 : }
641 :
642 693 : req = cli_full_connection_creds_send(
643 : NULL, self->ev, "myname", host, NULL, 0, share, "?????",
644 : cli_creds, flags,
645 : negotiate_contexts);
646 693 : if (!py_tevent_req_wait_exc(self, req)) {
647 0 : return -1;
648 : }
649 693 : status = cli_full_connection_creds_recv(req, &self->cli);
650 693 : TALLOC_FREE(req);
651 :
652 693 : if (!NT_STATUS_IS_OK(status)) {
653 20 : PyErr_SetNTSTATUS(status);
654 20 : return -1;
655 : }
656 :
657 : /*
658 : * Oplocks require a multi threaded connection
659 : */
660 673 : if (self->thread_state == NULL) {
661 673 : return 0;
662 : }
663 :
664 0 : self->oplock_waiter = cli_smb_oplock_break_waiter_send(
665 0 : self->ev, self->ev, self->cli);
666 0 : if (self->oplock_waiter == NULL) {
667 0 : PyErr_NoMemory();
668 0 : return -1;
669 : }
670 0 : tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
671 : self);
672 0 : return 0;
673 : }
674 :
675 0 : static void py_cli_got_oplock_break(struct tevent_req *req)
676 : {
677 : struct py_cli_state *self = (struct py_cli_state *)
678 0 : 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 0 : status = cli_smb_oplock_break_waiter_recv(req, &b.fnum, &b.level);
685 0 : TALLOC_FREE(req);
686 0 : self->oplock_waiter = NULL;
687 :
688 0 : if (!NT_STATUS_IS_OK(status)) {
689 0 : return;
690 : }
691 :
692 0 : num_breaks = talloc_array_length(self->oplock_breaks);
693 0 : tmp = talloc_realloc(self->ev, self->oplock_breaks,
694 : struct py_cli_oplock_break, num_breaks+1);
695 0 : if (tmp == NULL) {
696 0 : return;
697 : }
698 0 : self->oplock_breaks = tmp;
699 0 : self->oplock_breaks[num_breaks] = b;
700 :
701 0 : if (self->oplock_cond != NULL) {
702 0 : py_tevent_cond_signal(self->oplock_cond);
703 : }
704 :
705 0 : self->oplock_waiter = cli_smb_oplock_break_waiter_send(
706 0 : self->ev, self->ev, self->cli);
707 0 : if (self->oplock_waiter == NULL) {
708 0 : return;
709 : }
710 0 : tevent_req_set_callback(self->oplock_waiter, py_cli_got_oplock_break,
711 : self);
712 : }
713 :
714 0 : static PyObject *py_cli_get_oplock_break(struct py_cli_state *self,
715 : PyObject *args)
716 : {
717 : size_t num_oplock_breaks;
718 :
719 0 : if (!PyArg_ParseTuple(args, "")) {
720 0 : return NULL;
721 : }
722 :
723 0 : if (self->thread_state == NULL) {
724 0 : PyErr_SetString(PyExc_RuntimeError,
725 : "get_oplock_break() only possible on "
726 : "a multi_threaded connection");
727 0 : return NULL;
728 : }
729 :
730 0 : if (self->oplock_cond != NULL) {
731 0 : errno = EBUSY;
732 0 : PyErr_SetFromErrno(PyExc_RuntimeError);
733 0 : return NULL;
734 : }
735 :
736 0 : num_oplock_breaks = talloc_array_length(self->oplock_breaks);
737 :
738 0 : if (num_oplock_breaks == 0) {
739 : struct py_tevent_cond cond;
740 : int ret;
741 :
742 0 : self->oplock_cond = &cond;
743 0 : ret = py_tevent_cond_wait(&cond);
744 0 : self->oplock_cond = NULL;
745 :
746 0 : if (ret != 0) {
747 0 : errno = ret;
748 0 : PyErr_SetFromErrno(PyExc_RuntimeError);
749 0 : return NULL;
750 : }
751 : }
752 :
753 0 : num_oplock_breaks = talloc_array_length(self->oplock_breaks);
754 0 : if (num_oplock_breaks > 0) {
755 : PyObject *result;
756 :
757 0 : result = Py_BuildValue(
758 : "{s:i,s:i}",
759 0 : "fnum", self->oplock_breaks[0].fnum,
760 0 : "level", self->oplock_breaks[0].level);
761 :
762 0 : memmove(&self->oplock_breaks[0], &self->oplock_breaks[1],
763 : sizeof(self->oplock_breaks[0]) *
764 0 : (num_oplock_breaks - 1));
765 0 : self->oplock_breaks = talloc_realloc(
766 : NULL, self->oplock_breaks, struct py_cli_oplock_break,
767 : num_oplock_breaks - 1);
768 :
769 0 : return result;
770 : }
771 0 : Py_RETURN_NONE;
772 : }
773 :
774 693 : static void py_cli_state_dealloc(struct py_cli_state *self)
775 : {
776 693 : TALLOC_FREE(self->thread_state);
777 693 : TALLOC_FREE(self->oplock_waiter);
778 693 : TALLOC_FREE(self->ev);
779 :
780 693 : if (self->cli != NULL) {
781 673 : cli_shutdown(self->cli);
782 673 : self->cli = NULL;
783 : }
784 693 : Py_TYPE(self)->tp_free((PyObject *)self);
785 693 : }
786 :
787 495 : static PyObject *py_cli_settimeout(struct py_cli_state *self, PyObject *args)
788 : {
789 495 : unsigned int nmsecs = 0;
790 495 : unsigned int omsecs = 0;
791 :
792 495 : if (!PyArg_ParseTuple(args, "I", &nmsecs)) {
793 0 : return NULL;
794 : }
795 :
796 495 : omsecs = cli_set_timeout(self->cli, nmsecs);
797 :
798 495 : return PyLong_FromLong(omsecs);
799 : }
800 :
801 48 : static PyObject *py_cli_echo(struct py_cli_state *self,
802 : PyObject *Py_UNUSED(ignored))
803 : {
804 48 : DATA_BLOB data = data_blob_string_const("keepalive");
805 48 : struct tevent_req *req = NULL;
806 : NTSTATUS status;
807 :
808 48 : req = cli_echo_send(NULL, self->ev, self->cli, 1, data);
809 48 : if (!py_tevent_req_wait_exc(self, req)) {
810 0 : return NULL;
811 : }
812 48 : status = cli_echo_recv(req);
813 48 : TALLOC_FREE(req);
814 48 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
815 :
816 48 : Py_RETURN_NONE;
817 : }
818 :
819 523 : static PyObject *py_cli_create(struct py_cli_state *self, PyObject *args,
820 : PyObject *kwds)
821 : {
822 : char *fname;
823 523 : unsigned CreateFlags = 0;
824 523 : unsigned DesiredAccess = FILE_GENERIC_READ;
825 523 : unsigned FileAttributes = 0;
826 523 : unsigned ShareAccess = 0;
827 523 : unsigned CreateDisposition = FILE_OPEN;
828 523 : unsigned CreateOptions = 0;
829 523 : unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
830 523 : 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 523 : if (!ParseTupleAndKeywords(
841 : args, kwds, "s|IIIIIIII", kwlist,
842 : &fname, &CreateFlags, &DesiredAccess, &FileAttributes,
843 : &ShareAccess, &CreateDisposition, &CreateOptions,
844 : &ImpersonationLevel, &SecurityFlags)) {
845 0 : return NULL;
846 : }
847 :
848 523 : req = cli_ntcreate_send(NULL, self->ev, self->cli, fname, CreateFlags,
849 : DesiredAccess, FileAttributes, ShareAccess,
850 : CreateDisposition, CreateOptions,
851 : ImpersonationLevel, SecurityFlags);
852 523 : if (!py_tevent_req_wait_exc(self, req)) {
853 0 : return NULL;
854 : }
855 523 : status = cli_ntcreate_recv(req, &fnum, NULL);
856 523 : TALLOC_FREE(req);
857 :
858 523 : if (!NT_STATUS_IS_OK(status)) {
859 0 : PyErr_SetNTSTATUS(status);
860 0 : return NULL;
861 : }
862 523 : return Py_BuildValue("I", (unsigned)fnum);
863 : }
864 :
865 0 : static struct smb2_create_blobs *py_cli_get_create_contexts(
866 : TALLOC_CTX *mem_ctx, PyObject *list)
867 : {
868 0 : struct smb2_create_blobs *ctxs = NULL;
869 : Py_ssize_t i, len;
870 : int ret;
871 :
872 0 : ret = PyList_Check(list);
873 0 : if (!ret) {
874 0 : goto fail;
875 : }
876 :
877 0 : len = PyList_Size(list);
878 0 : if (len == 0) {
879 0 : goto fail;
880 : }
881 :
882 0 : ctxs = talloc_zero(mem_ctx, struct smb2_create_blobs);
883 0 : if (ctxs == NULL) {
884 0 : goto fail;
885 : }
886 :
887 0 : for (i=0; i<len; i++) {
888 : NTSTATUS status;
889 :
890 0 : PyObject *t = NULL;
891 : Py_ssize_t tlen;
892 :
893 0 : PyObject *pname = NULL;
894 0 : char *name = NULL;
895 :
896 0 : PyObject *pdata = NULL;
897 0 : DATA_BLOB data = { .data = NULL, };
898 :
899 0 : t = PyList_GetItem(list, i);
900 0 : if (t == NULL) {
901 0 : goto fail;
902 : }
903 :
904 0 : ret = PyTuple_Check(t);
905 0 : if (!ret) {
906 0 : goto fail;
907 : }
908 :
909 0 : tlen = PyTuple_Size(t);
910 0 : if (tlen != 2) {
911 0 : goto fail;
912 : }
913 :
914 0 : pname = PyTuple_GetItem(t, 0);
915 0 : if (pname == NULL) {
916 0 : goto fail;
917 : }
918 0 : ret = PyBytes_Check(pname);
919 0 : if (!ret) {
920 0 : goto fail;
921 : }
922 0 : name = PyBytes_AsString(pname);
923 :
924 0 : pdata = PyTuple_GetItem(t, 1);
925 0 : if (pdata == NULL) {
926 0 : goto fail;
927 : }
928 0 : ret = PyBytes_Check(pdata);
929 0 : if (!ret) {
930 0 : goto fail;
931 : }
932 0 : data = (DATA_BLOB) {
933 0 : .data = (uint8_t *)PyBytes_AsString(pdata),
934 0 : .length = PyBytes_Size(pdata),
935 : };
936 0 : status = smb2_create_blob_add(ctxs, ctxs, name, data);
937 0 : if (!NT_STATUS_IS_OK(status)) {
938 0 : goto fail;
939 : }
940 : }
941 0 : return ctxs;
942 :
943 0 : fail:
944 0 : TALLOC_FREE(ctxs);
945 0 : return NULL;
946 : }
947 :
948 0 : static PyObject *py_cli_create_contexts(const struct smb2_create_blobs *blobs)
949 : {
950 0 : PyObject *py_blobs = NULL;
951 : uint32_t i;
952 :
953 0 : if (blobs == NULL) {
954 0 : Py_RETURN_NONE;
955 : }
956 :
957 0 : py_blobs = PyList_New(blobs->num_blobs);
958 0 : if (py_blobs == NULL) {
959 0 : return NULL;
960 : }
961 :
962 0 : for (i=0; i<blobs->num_blobs; i++) {
963 0 : struct smb2_create_blob *blob = &blobs->blobs[i];
964 0 : PyObject *py_blob = NULL;
965 : int ret;
966 :
967 0 : py_blob = Py_BuildValue(
968 : "(yy#)",
969 : blob->tag,
970 : blob->data.data,
971 0 : (int)blob->data.length);
972 0 : if (py_blob == NULL) {
973 0 : goto fail;
974 : }
975 :
976 0 : ret = PyList_SetItem(py_blobs, i, py_blob);
977 0 : if (ret == -1) {
978 0 : Py_XDECREF(py_blob);
979 0 : goto fail;
980 : }
981 : }
982 0 : return py_blobs;
983 :
984 0 : fail:
985 0 : Py_XDECREF(py_blobs);
986 0 : return NULL;
987 : }
988 :
989 0 : static PyObject *py_cli_create_returns(const struct smb_create_returns *r)
990 : {
991 0 : PyObject *v = NULL;
992 :
993 0 : v = Py_BuildValue(
994 : "{sLsLsLsLsLsLsLsLsL}",
995 : "oplock_level",
996 0 : (unsigned long long)r->oplock_level,
997 : "create_action",
998 0 : (unsigned long long)r->create_action,
999 : "creation_time",
1000 0 : (unsigned long long)r->creation_time,
1001 : "last_access_time",
1002 0 : (unsigned long long)r->last_access_time,
1003 : "last_write_time",
1004 0 : (unsigned long long)r->last_write_time,
1005 : "change_time",
1006 0 : (unsigned long long)r->change_time,
1007 : "allocation_size",
1008 0 : (unsigned long long)r->allocation_size,
1009 : "end_of_file",
1010 0 : (unsigned long long)r->end_of_file,
1011 : "file_attributes",
1012 0 : (unsigned long long)r->file_attributes);
1013 0 : return v;
1014 : }
1015 :
1016 0 : static PyObject *py_cli_symlink_error(const struct symlink_reparse_struct *s)
1017 : {
1018 0 : char *subst_utf8 = NULL, *print_utf8 = NULL;
1019 : size_t subst_utf8_len, print_utf8_len;
1020 0 : PyObject *v = NULL;
1021 0 : 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 0 : ok = convert_string_talloc(
1029 : talloc_tos(),
1030 : CH_UNIX,
1031 : CH_UTF8,
1032 0 : s->substitute_name,
1033 0 : strlen(s->substitute_name),
1034 : &subst_utf8,
1035 : &subst_utf8_len);
1036 0 : if (!ok) {
1037 0 : goto fail;
1038 : }
1039 :
1040 0 : ok = convert_string_talloc(
1041 : talloc_tos(),
1042 : CH_UNIX,
1043 : CH_UTF8,
1044 0 : s->print_name,
1045 0 : strlen(s->print_name),
1046 : &print_utf8,
1047 : &print_utf8_len);
1048 0 : if (!ok) {
1049 0 : goto fail;
1050 : }
1051 :
1052 0 : v = Py_BuildValue(
1053 : "{sLsssssL}",
1054 : "unparsed_path_length",
1055 0 : (unsigned long long)s->unparsed_path_length,
1056 : "substitute_name",
1057 : subst_utf8,
1058 : "print_name",
1059 : print_utf8,
1060 : "flags",
1061 0 : (unsigned long long)s->flags);
1062 :
1063 0 : fail:
1064 0 : TALLOC_FREE(subst_utf8);
1065 0 : TALLOC_FREE(print_utf8);
1066 0 : return v;
1067 : }
1068 :
1069 0 : static PyObject *py_cli_create_ex(
1070 : struct py_cli_state *self, PyObject *args, PyObject *kwds)
1071 : {
1072 0 : char *fname = NULL;
1073 0 : unsigned CreateFlags = 0;
1074 0 : unsigned DesiredAccess = FILE_GENERIC_READ;
1075 0 : unsigned FileAttributes = 0;
1076 0 : unsigned ShareAccess = 0;
1077 0 : unsigned CreateDisposition = FILE_OPEN;
1078 0 : unsigned CreateOptions = 0;
1079 0 : unsigned ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
1080 0 : unsigned SecurityFlags = 0;
1081 0 : PyObject *py_create_contexts_in = NULL;
1082 0 : PyObject *py_create_contexts_out = NULL;
1083 0 : struct smb2_create_blobs *create_contexts_in = NULL;
1084 0 : struct smb2_create_blobs create_contexts_out = { .num_blobs = 0 };
1085 0 : struct smb_create_returns cr = { .create_action = 0, };
1086 0 : struct symlink_reparse_struct *symlink = NULL;
1087 0 : PyObject *py_cr = NULL;
1088 : uint16_t fnum;
1089 : struct tevent_req *req;
1090 : NTSTATUS status;
1091 : int ret;
1092 : bool ok;
1093 0 : 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 0 : 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 0 : if (!ret) {
1124 0 : return NULL;
1125 : }
1126 :
1127 0 : if (py_create_contexts_in != NULL) {
1128 0 : create_contexts_in = py_cli_get_create_contexts(
1129 : NULL, py_create_contexts_in);
1130 0 : if (create_contexts_in == NULL) {
1131 0 : errno = EINVAL;
1132 0 : PyErr_SetFromErrno(PyExc_RuntimeError);
1133 0 : return NULL;
1134 : }
1135 : }
1136 :
1137 0 : if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1138 0 : 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 0 : 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 0 : TALLOC_FREE(create_contexts_in);
1168 :
1169 0 : ok = py_tevent_req_wait_exc(self, req);
1170 0 : if (!ok) {
1171 0 : return NULL;
1172 : }
1173 :
1174 0 : if (smbXcli_conn_protocol(self->cli->conn) >= PROTOCOL_SMB2_02) {
1175 0 : status = cli_smb2_create_fnum_recv(
1176 : req,
1177 : &fnum,
1178 : &cr,
1179 : NULL,
1180 : &create_contexts_out,
1181 : &symlink);
1182 : } else {
1183 0 : status = cli_ntcreate_recv(req, &fnum, &cr);
1184 : }
1185 :
1186 0 : TALLOC_FREE(req);
1187 :
1188 0 : if (!NT_STATUS_IS_OK(status)) {
1189 0 : goto fail;
1190 : }
1191 :
1192 0 : SMB_ASSERT(symlink == NULL);
1193 :
1194 0 : py_create_contexts_out = py_cli_create_contexts(&create_contexts_out);
1195 0 : TALLOC_FREE(create_contexts_out.blobs);
1196 0 : if (py_create_contexts_out == NULL) {
1197 0 : goto nomem;
1198 : }
1199 :
1200 0 : py_cr = py_cli_create_returns(&cr);
1201 0 : if (py_cr == NULL) {
1202 0 : goto nomem;
1203 : }
1204 :
1205 0 : v = PyTuple_New(3);
1206 0 : if (v == NULL) {
1207 0 : goto nomem;
1208 : }
1209 0 : ret = PyTuple_SetItem(v, 0, Py_BuildValue("I", (unsigned)fnum));
1210 0 : if (ret == -1) {
1211 0 : status = NT_STATUS_INTERNAL_ERROR;
1212 0 : goto fail;
1213 : }
1214 0 : ret = PyTuple_SetItem(v, 1, py_cr);
1215 0 : if (ret == -1) {
1216 0 : status = NT_STATUS_INTERNAL_ERROR;
1217 0 : goto fail;
1218 : }
1219 0 : ret = PyTuple_SetItem(v, 2, py_create_contexts_out);
1220 0 : if (ret == -1) {
1221 0 : status = NT_STATUS_INTERNAL_ERROR;
1222 0 : goto fail;
1223 : }
1224 :
1225 0 : return v;
1226 0 : nomem:
1227 0 : status = NT_STATUS_NO_MEMORY;
1228 0 : fail:
1229 0 : Py_XDECREF(py_create_contexts_out);
1230 0 : Py_XDECREF(py_cr);
1231 0 : Py_XDECREF(v);
1232 :
1233 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
1234 0 : (symlink != NULL)) {
1235 0 : 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 0 : PyErr_SetNTSTATUS(status);
1246 : }
1247 0 : return NULL;
1248 : }
1249 :
1250 523 : 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 523 : if (!PyArg_ParseTuple(args, "i", &fnum)) {
1257 0 : return NULL;
1258 : }
1259 :
1260 523 : req = cli_close_send(NULL, self->ev, self->cli, fnum);
1261 523 : if (!py_tevent_req_wait_exc(self, req)) {
1262 0 : return NULL;
1263 : }
1264 523 : status = cli_close_recv(req);
1265 523 : TALLOC_FREE(req);
1266 :
1267 523 : if (!NT_STATUS_IS_OK(status)) {
1268 0 : PyErr_SetNTSTATUS(status);
1269 0 : return NULL;
1270 : }
1271 523 : Py_RETURN_NONE;
1272 : }
1273 :
1274 0 : static PyObject *py_cli_rename(
1275 : struct py_cli_state *self, PyObject *args, PyObject *kwds)
1276 : {
1277 0 : char *fname_src = NULL, *fname_dst = NULL;
1278 0 : int replace = false;
1279 0 : struct tevent_req *req = NULL;
1280 : NTSTATUS status;
1281 : bool ok;
1282 :
1283 : static const char *kwlist[] = { "src", "dst", "replace", NULL };
1284 :
1285 0 : ok = ParseTupleAndKeywords(
1286 : args, kwds, "ss|p", kwlist, &fname_src, &fname_dst, &replace);
1287 0 : if (!ok) {
1288 0 : return NULL;
1289 : }
1290 :
1291 0 : req = cli_rename_send(
1292 : NULL, self->ev, self->cli, fname_src, fname_dst, replace);
1293 0 : if (!py_tevent_req_wait_exc(self, req)) {
1294 0 : return NULL;
1295 : }
1296 0 : status = cli_rename_recv(req);
1297 0 : TALLOC_FREE(req);
1298 :
1299 0 : if (!NT_STATUS_IS_OK(status)) {
1300 0 : PyErr_SetNTSTATUS(status);
1301 0 : return NULL;
1302 : }
1303 0 : 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 1076 : static size_t push_data(uint8_t *buf, size_t n, void *priv)
1317 : {
1318 1076 : struct push_state *state = (struct push_state *)priv;
1319 1076 : char *curr_ptr = NULL;
1320 : off_t remaining;
1321 : size_t copied_bytes;
1322 :
1323 1076 : if (state->nread >= state->total_data) {
1324 560 : return 0;
1325 : }
1326 :
1327 516 : curr_ptr = state->data + state->nread;
1328 516 : remaining = state->total_data - state->nread;
1329 516 : copied_bytes = MIN(remaining, n);
1330 :
1331 516 : memcpy(buf, curr_ptr, copied_bytes);
1332 516 : state->nread += copied_bytes;
1333 516 : return copied_bytes;
1334 : }
1335 :
1336 : /*
1337 : * Writes a file with the contents specified
1338 : */
1339 560 : static PyObject *py_smb_savefile(struct py_cli_state *self, PyObject *args)
1340 : {
1341 : uint16_t fnum;
1342 560 : const char *filename = NULL;
1343 560 : char *data = NULL;
1344 560 : Py_ssize_t size = 0;
1345 : NTSTATUS status;
1346 560 : struct tevent_req *req = NULL;
1347 : struct push_state state;
1348 :
1349 560 : if (!PyArg_ParseTuple(args, "s"PYARG_BYTES_LEN":savefile", &filename,
1350 : &data, &size)) {
1351 0 : return NULL;
1352 : }
1353 :
1354 : /* create a new file handle for writing to */
1355 560 : 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 560 : if (!py_tevent_req_wait_exc(self, req)) {
1361 0 : return NULL;
1362 : }
1363 560 : status = cli_ntcreate_recv(req, &fnum, NULL);
1364 560 : TALLOC_FREE(req);
1365 560 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1366 :
1367 : /* write the new file contents */
1368 560 : state.data = data;
1369 560 : state.nread = 0;
1370 560 : state.total_data = size;
1371 :
1372 560 : req = cli_push_send(NULL, self->ev, self->cli, fnum, 0, 0, 0,
1373 : push_data, &state);
1374 560 : if (!py_tevent_req_wait_exc(self, req)) {
1375 0 : return NULL;
1376 : }
1377 560 : status = cli_push_recv(req);
1378 560 : TALLOC_FREE(req);
1379 560 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1380 :
1381 : /* close the file handle */
1382 560 : req = cli_close_send(NULL, self->ev, self->cli, fnum);
1383 560 : if (!py_tevent_req_wait_exc(self, req)) {
1384 0 : return NULL;
1385 : }
1386 560 : status = cli_close_recv(req);
1387 560 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1388 :
1389 560 : Py_RETURN_NONE;
1390 : }
1391 :
1392 492 : static PyObject *py_cli_write(struct py_cli_state *self, PyObject *args,
1393 : PyObject *kwds)
1394 : {
1395 : int fnum;
1396 492 : 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 492 : if (!ParseTupleAndKeywords(
1408 : args, kwds, "i" PYARG_BYTES_LEN "K|I", kwlist,
1409 : &fnum, &buf, &buflen, &offset, &mode)) {
1410 0 : return NULL;
1411 : }
1412 :
1413 492 : req = cli_write_send(NULL, self->ev, self->cli, fnum, mode,
1414 : (uint8_t *)buf, offset, buflen);
1415 492 : if (!py_tevent_req_wait_exc(self, req)) {
1416 0 : return NULL;
1417 : }
1418 492 : status = cli_write_recv(req, &written);
1419 492 : TALLOC_FREE(req);
1420 :
1421 492 : if (!NT_STATUS_IS_OK(status)) {
1422 0 : PyErr_SetNTSTATUS(status);
1423 0 : return NULL;
1424 : }
1425 492 : return Py_BuildValue("K", (unsigned long long)written);
1426 : }
1427 :
1428 : /*
1429 : * Returns the size of the given file
1430 : */
1431 504 : static NTSTATUS py_smb_filesize(struct py_cli_state *self, uint16_t fnum,
1432 : off_t *size)
1433 : {
1434 : NTSTATUS status;
1435 504 : struct tevent_req *req = NULL;
1436 :
1437 504 : req = cli_qfileinfo_basic_send(NULL, self->ev, self->cli, fnum);
1438 504 : if (!py_tevent_req_wait_exc(self, req)) {
1439 0 : return NT_STATUS_INTERNAL_ERROR;
1440 : }
1441 504 : status = cli_qfileinfo_basic_recv(
1442 : req, NULL, size, NULL, NULL, NULL, NULL, NULL);
1443 504 : TALLOC_FREE(req);
1444 504 : return status;
1445 : }
1446 :
1447 : /*
1448 : * Loads the specified file's contents and returns it
1449 : */
1450 570 : static PyObject *py_smb_loadfile(struct py_cli_state *self, PyObject *args)
1451 : {
1452 : NTSTATUS status;
1453 570 : const char *filename = NULL;
1454 570 : struct tevent_req *req = NULL;
1455 : uint16_t fnum;
1456 : off_t size;
1457 570 : char *buf = NULL;
1458 570 : off_t nread = 0;
1459 570 : PyObject *result = NULL;
1460 :
1461 570 : if (!PyArg_ParseTuple(args, "s:loadfile", &filename)) {
1462 0 : return NULL;
1463 : }
1464 :
1465 : /* get a read file handle */
1466 570 : 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 570 : if (!py_tevent_req_wait_exc(self, req)) {
1472 0 : return NULL;
1473 : }
1474 570 : status = cli_ntcreate_recv(req, &fnum, NULL);
1475 570 : TALLOC_FREE(req);
1476 570 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1477 :
1478 : /* get a buffer to hold the file contents */
1479 504 : status = py_smb_filesize(self, fnum, &size);
1480 504 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1481 :
1482 504 : result = PyBytes_FromStringAndSize(NULL, size);
1483 504 : if (result == NULL) {
1484 0 : return NULL;
1485 : }
1486 :
1487 : /* read the file contents */
1488 504 : buf = PyBytes_AS_STRING(result);
1489 504 : req = cli_pull_send(NULL, self->ev, self->cli, fnum, 0, size,
1490 : size, cli_read_sink, &buf);
1491 504 : if (!py_tevent_req_wait_exc(self, req)) {
1492 0 : Py_XDECREF(result);
1493 0 : return NULL;
1494 : }
1495 504 : status = cli_pull_recv(req, &nread);
1496 504 : TALLOC_FREE(req);
1497 504 : if (!NT_STATUS_IS_OK(status)) {
1498 0 : Py_XDECREF(result);
1499 0 : PyErr_SetNTSTATUS(status);
1500 0 : return NULL;
1501 : }
1502 :
1503 : /* close the file handle */
1504 504 : req = cli_close_send(NULL, self->ev, self->cli, fnum);
1505 504 : if (!py_tevent_req_wait_exc(self, req)) {
1506 0 : Py_XDECREF(result);
1507 0 : return NULL;
1508 : }
1509 504 : status = cli_close_recv(req);
1510 504 : TALLOC_FREE(req);
1511 504 : if (!NT_STATUS_IS_OK(status)) {
1512 0 : Py_XDECREF(result);
1513 0 : PyErr_SetNTSTATUS(status);
1514 0 : return NULL;
1515 : }
1516 :
1517 : /* sanity-check we read the expected number of bytes */
1518 504 : if (nread > size) {
1519 0 : Py_XDECREF(result);
1520 0 : PyErr_Format(PyExc_IOError,
1521 : "read invalid - got %zu requested %zu",
1522 : nread, size);
1523 0 : return NULL;
1524 : }
1525 :
1526 504 : if (nread < size) {
1527 0 : if (_PyBytes_Resize(&result, nread) < 0) {
1528 0 : return NULL;
1529 : }
1530 : }
1531 :
1532 504 : return result;
1533 : }
1534 :
1535 495 : 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 495 : if (!ParseTupleAndKeywords(
1551 : args, kwds, "iKI", kwlist, &fnum, &offset,
1552 : &size)) {
1553 0 : return NULL;
1554 : }
1555 :
1556 495 : result = PyBytes_FromStringAndSize(NULL, size);
1557 495 : if (result == NULL) {
1558 0 : return NULL;
1559 : }
1560 495 : buf = PyBytes_AS_STRING(result);
1561 :
1562 495 : req = cli_read_send(NULL, self->ev, self->cli, fnum,
1563 : buf, offset, size);
1564 495 : if (!py_tevent_req_wait_exc(self, req)) {
1565 0 : Py_XDECREF(result);
1566 0 : return NULL;
1567 : }
1568 495 : status = cli_read_recv(req, &received);
1569 495 : TALLOC_FREE(req);
1570 :
1571 495 : if (!NT_STATUS_IS_OK(status)) {
1572 3 : Py_XDECREF(result);
1573 3 : PyErr_SetNTSTATUS(status);
1574 3 : return NULL;
1575 : }
1576 :
1577 492 : if (received > size) {
1578 0 : Py_XDECREF(result);
1579 0 : PyErr_Format(PyExc_IOError,
1580 : "read invalid - got %zu requested %u",
1581 : received, size);
1582 0 : return NULL;
1583 : }
1584 :
1585 492 : if (received < size) {
1586 492 : if (_PyBytes_Resize(&result, received) < 0) {
1587 0 : return NULL;
1588 : }
1589 : }
1590 :
1591 492 : return result;
1592 : }
1593 :
1594 0 : 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 0 : if (!ParseTupleAndKeywords(
1606 : args, kwds, "IK", kwlist, &fnum, &size)) {
1607 0 : return NULL;
1608 : }
1609 :
1610 0 : req = cli_ftruncate_send(NULL, self->ev, self->cli, fnum, size);
1611 0 : if (!py_tevent_req_wait_exc(self, req)) {
1612 0 : return NULL;
1613 : }
1614 0 : status = cli_ftruncate_recv(req);
1615 0 : TALLOC_FREE(req);
1616 :
1617 0 : if (!NT_STATUS_IS_OK(status)) {
1618 0 : PyErr_SetNTSTATUS(status);
1619 0 : return NULL;
1620 : }
1621 0 : Py_RETURN_NONE;
1622 : }
1623 :
1624 0 : 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 0 : if (!ParseTupleAndKeywords(
1636 : args, kwds, "II", kwlist, &fnum, &flag)) {
1637 0 : return NULL;
1638 : }
1639 :
1640 0 : req = cli_nt_delete_on_close_send(NULL, self->ev, self->cli, fnum,
1641 : flag);
1642 0 : if (!py_tevent_req_wait_exc(self, req)) {
1643 0 : return NULL;
1644 : }
1645 0 : status = cli_nt_delete_on_close_recv(req);
1646 0 : TALLOC_FREE(req);
1647 :
1648 0 : if (!NT_STATUS_IS_OK(status)) {
1649 0 : PyErr_SetNTSTATUS(status);
1650 0 : return NULL;
1651 : }
1652 0 : 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 42 : static void py_cli_notify_state_dealloc(struct py_cli_notify_state *self)
1662 : {
1663 42 : TALLOC_FREE(self->req);
1664 42 : if (self->py_cli_state != NULL) {
1665 0 : Py_DECREF(self->py_cli_state);
1666 0 : self->py_cli_state = NULL;
1667 : }
1668 42 : Py_TYPE(self)->tp_free(self);
1669 42 : }
1670 :
1671 : static PyTypeObject py_cli_notify_state_type;
1672 :
1673 42 : 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 42 : unsigned fnum = 0;
1685 42 : unsigned buffer_size = 0;
1686 42 : unsigned completion_filter = 0;
1687 42 : PyObject *py_recursive = Py_False;
1688 42 : bool recursive = false;
1689 42 : struct tevent_req *req = NULL;
1690 42 : struct tevent_queue *send_queue = NULL;
1691 42 : struct tevent_req *flush_req = NULL;
1692 : bool ok;
1693 42 : struct py_cli_notify_state *py_notify_state = NULL;
1694 : struct timeval endtime;
1695 :
1696 42 : ok = ParseTupleAndKeywords(args,
1697 : kwds,
1698 : "IIIO",
1699 : kwlist,
1700 : &fnum,
1701 : &buffer_size,
1702 : &completion_filter,
1703 : &py_recursive);
1704 42 : if (!ok) {
1705 0 : return NULL;
1706 : }
1707 :
1708 42 : recursive = PyObject_IsTrue(py_recursive);
1709 :
1710 42 : req = cli_notify_send(NULL,
1711 : self->ev,
1712 : self->cli,
1713 : fnum,
1714 : buffer_size,
1715 : completion_filter,
1716 : recursive);
1717 42 : if (req == NULL) {
1718 0 : PyErr_NoMemory();
1719 0 : return NULL;
1720 : }
1721 :
1722 : /*
1723 : * Just wait for the request being submitted to
1724 : * the kernel/socket/wire.
1725 : */
1726 42 : send_queue = smbXcli_conn_send_queue(self->cli->conn);
1727 42 : flush_req = tevent_queue_wait_send(req,
1728 : self->ev,
1729 : send_queue);
1730 42 : endtime = timeval_current_ofs_msec(self->cli->timeout);
1731 42 : ok = tevent_req_set_endtime(flush_req,
1732 : self->ev,
1733 : endtime);
1734 42 : if (!ok) {
1735 0 : TALLOC_FREE(req);
1736 0 : PyErr_NoMemory();
1737 0 : return NULL;
1738 : }
1739 42 : ok = py_tevent_req_wait_exc(self, flush_req);
1740 42 : if (!ok) {
1741 0 : TALLOC_FREE(req);
1742 0 : return NULL;
1743 : }
1744 42 : TALLOC_FREE(flush_req);
1745 :
1746 : py_notify_state = (struct py_cli_notify_state *)
1747 42 : py_cli_notify_state_type.tp_alloc(&py_cli_notify_state_type, 0);
1748 42 : if (py_notify_state == NULL) {
1749 0 : TALLOC_FREE(req);
1750 0 : PyErr_NoMemory();
1751 0 : return NULL;
1752 : }
1753 42 : Py_INCREF(self);
1754 42 : py_notify_state->py_cli_state = self;
1755 42 : py_notify_state->req = req;
1756 :
1757 42 : return (PyObject *)py_notify_state;
1758 : }
1759 :
1760 98 : static PyObject *py_cli_notify_get_changes(struct py_cli_notify_state *self,
1761 : PyObject *args,
1762 : PyObject *kwds)
1763 : {
1764 98 : struct py_cli_state *py_cli_state = self->py_cli_state;
1765 98 : struct tevent_req *req = self->req;
1766 : uint32_t i;
1767 98 : uint32_t num_changes = 0;
1768 98 : struct notify_change *changes = NULL;
1769 98 : PyObject *result = NULL;
1770 : NTSTATUS status;
1771 : bool ok;
1772 : static const char *kwlist[] = {
1773 : "wait",
1774 : NULL
1775 : };
1776 98 : PyObject *py_wait = Py_False;
1777 98 : bool wait = false;
1778 : bool pending;
1779 :
1780 98 : ok = ParseTupleAndKeywords(args,
1781 : kwds,
1782 : "O",
1783 : kwlist,
1784 : &py_wait);
1785 98 : if (!ok) {
1786 0 : return NULL;
1787 : }
1788 :
1789 98 : wait = PyObject_IsTrue(py_wait);
1790 :
1791 98 : if (req == NULL) {
1792 0 : PyErr_SetString(PyExc_RuntimeError,
1793 : "TODO req == NULL "
1794 : "- missing change notify request?");
1795 0 : return NULL;
1796 : }
1797 :
1798 98 : pending = tevent_req_is_in_progress(req);
1799 98 : if (pending && !wait) {
1800 56 : Py_RETURN_NONE;
1801 : }
1802 :
1803 42 : if (pending) {
1804 : struct timeval endtime;
1805 :
1806 30 : endtime = timeval_current_ofs_msec(py_cli_state->cli->timeout);
1807 30 : ok = tevent_req_set_endtime(req,
1808 : py_cli_state->ev,
1809 : endtime);
1810 30 : if (!ok) {
1811 0 : TALLOC_FREE(req);
1812 0 : PyErr_NoMemory();
1813 0 : return NULL;
1814 : }
1815 : }
1816 :
1817 42 : ok = py_tevent_req_wait_exc(py_cli_state, req);
1818 42 : self->req = NULL;
1819 42 : Py_DECREF(self->py_cli_state);
1820 42 : self->py_cli_state = NULL;
1821 42 : if (!ok) {
1822 0 : return NULL;
1823 : }
1824 :
1825 42 : status = cli_notify_recv(req, req, &num_changes, &changes);
1826 42 : if (!NT_STATUS_IS_OK(status)) {
1827 12 : TALLOC_FREE(req);
1828 12 : PyErr_SetNTSTATUS(status);
1829 12 : return NULL;
1830 : }
1831 :
1832 30 : result = Py_BuildValue("[]");
1833 30 : if (result == NULL) {
1834 0 : TALLOC_FREE(req);
1835 0 : return NULL;
1836 : }
1837 :
1838 60 : for (i = 0; i < num_changes; i++) {
1839 30 : PyObject *change = NULL;
1840 : int ret;
1841 :
1842 30 : change = Py_BuildValue("{s:s,s:I}",
1843 30 : "name", changes[i].name,
1844 30 : "action", changes[i].action);
1845 30 : if (change == NULL) {
1846 0 : Py_XDECREF(result);
1847 0 : TALLOC_FREE(req);
1848 0 : return NULL;
1849 : }
1850 :
1851 30 : ret = PyList_Append(result, change);
1852 30 : Py_DECREF(change);
1853 30 : if (ret == -1) {
1854 0 : Py_XDECREF(result);
1855 0 : TALLOC_FREE(req);
1856 0 : return NULL;
1857 : }
1858 : }
1859 :
1860 30 : TALLOC_FREE(req);
1861 30 : 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 posix directory listing entries to an overall Python list
1895 : */
1896 0 : static NTSTATUS list_posix_helper(struct file_info *finfo,
1897 : const char *mask, void *state)
1898 : {
1899 0 : PyObject *result = (PyObject *)state;
1900 0 : PyObject *file = NULL;
1901 0 : PyObject *size = NULL;
1902 : int ret;
1903 :
1904 0 : size = PyLong_FromUnsignedLongLong(finfo->size);
1905 : /*
1906 : * Build a dictionary representing the file info.
1907 : * Note: Windows does not always return short_name (so it may be None)
1908 : */
1909 0 : file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l,s:i,s:i,s:i,s:s,s:s}",
1910 : "name", finfo->name,
1911 0 : "attrib", (int)finfo->attr,
1912 : "short_name", finfo->short_name,
1913 : "size", size,
1914 : "mtime",
1915 : convert_timespec_to_time_t(finfo->mtime_ts),
1916 : "perms", finfo->st_ex_mode,
1917 : "ino", finfo->ino,
1918 : "dev", finfo->st_ex_dev,
1919 : "owner_sid",
1920 0 : dom_sid_string(finfo, &finfo->owner_sid),
1921 : "group_sid",
1922 0 : dom_sid_string(finfo, &finfo->group_sid));
1923 :
1924 0 : Py_CLEAR(size);
1925 :
1926 0 : if (file == NULL) {
1927 0 : return NT_STATUS_NO_MEMORY;
1928 : }
1929 :
1930 0 : ret = PyList_Append(result, file);
1931 0 : Py_CLEAR(file);
1932 0 : if (ret == -1) {
1933 0 : return NT_STATUS_INTERNAL_ERROR;
1934 : }
1935 :
1936 0 : return NT_STATUS_OK;
1937 : }
1938 :
1939 : /*
1940 : * Helper to add directory listing entries to an overall Python list
1941 : */
1942 5111 : static NTSTATUS list_helper(struct file_info *finfo,
1943 : const char *mask, void *state)
1944 : {
1945 5111 : PyObject *result = (PyObject *)state;
1946 5111 : PyObject *file = NULL;
1947 5111 : PyObject *size = NULL;
1948 : int ret;
1949 :
1950 : /* suppress '.' and '..' in the results we return */
1951 5111 : if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1952 3060 : return NT_STATUS_OK;
1953 : }
1954 2051 : size = PyLong_FromUnsignedLongLong(finfo->size);
1955 : /*
1956 : * Build a dictionary representing the file info.
1957 : * Note: Windows does not always return short_name (so it may be None)
1958 : */
1959 2051 : file = Py_BuildValue("{s:s,s:i,s:s,s:O,s:l}",
1960 : "name", finfo->name,
1961 2051 : "attrib", (int)finfo->attr,
1962 : "short_name", finfo->short_name,
1963 : "size", size,
1964 : "mtime",
1965 : convert_timespec_to_time_t(finfo->mtime_ts));
1966 :
1967 2051 : Py_CLEAR(size);
1968 :
1969 2051 : if (file == NULL) {
1970 0 : return NT_STATUS_NO_MEMORY;
1971 : }
1972 :
1973 2051 : if (finfo->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
1974 0 : unsigned long tag = finfo->reparse_tag;
1975 :
1976 0 : ret = PyDict_SetItemString(
1977 : file,
1978 : "reparse_tag",
1979 : PyLong_FromUnsignedLong(tag));
1980 0 : if (ret == -1) {
1981 0 : return NT_STATUS_INTERNAL_ERROR;
1982 : }
1983 : }
1984 :
1985 2051 : ret = PyList_Append(result, file);
1986 2051 : Py_CLEAR(file);
1987 2051 : if (ret == -1) {
1988 0 : return NT_STATUS_INTERNAL_ERROR;
1989 : }
1990 :
1991 2051 : return NT_STATUS_OK;
1992 : }
1993 :
1994 : struct do_listing_state {
1995 : const char *mask;
1996 : NTSTATUS (*callback_fn)(
1997 : struct file_info *finfo,
1998 : const char *mask,
1999 : void *private_data);
2000 : void *private_data;
2001 : NTSTATUS status;
2002 : };
2003 :
2004 8173 : static void do_listing_cb(struct tevent_req *subreq)
2005 : {
2006 8173 : struct do_listing_state *state = tevent_req_callback_data_void(subreq);
2007 8173 : struct file_info *finfo = NULL;
2008 :
2009 8173 : state->status = cli_list_recv(subreq, NULL, &finfo);
2010 8173 : if (!NT_STATUS_IS_OK(state->status)) {
2011 3062 : return;
2012 : }
2013 5111 : state->callback_fn(finfo, state->mask, state->private_data);
2014 5111 : TALLOC_FREE(finfo);
2015 : }
2016 :
2017 1531 : static NTSTATUS do_listing(struct py_cli_state *self,
2018 : const char *base_dir, const char *user_mask,
2019 : uint16_t attribute,
2020 : unsigned int info_level,
2021 : bool posix,
2022 : NTSTATUS (*callback_fn)(struct file_info *,
2023 : const char *, void *),
2024 : void *priv)
2025 : {
2026 1531 : char *mask = NULL;
2027 1531 : struct do_listing_state state = {
2028 : .mask = mask,
2029 : .callback_fn = callback_fn,
2030 : .private_data = priv,
2031 : };
2032 1531 : struct tevent_req *req = NULL;
2033 : NTSTATUS status;
2034 :
2035 1531 : if (user_mask == NULL) {
2036 1529 : mask = talloc_asprintf(NULL, "%s\\*", base_dir);
2037 : } else {
2038 2 : mask = talloc_asprintf(NULL, "%s\\%s", base_dir, user_mask);
2039 : }
2040 :
2041 1531 : if (mask == NULL) {
2042 0 : return NT_STATUS_NO_MEMORY;
2043 : }
2044 1531 : dos_format(mask);
2045 :
2046 1531 : req = cli_list_send(NULL, self->ev, self->cli, mask, attribute,
2047 : info_level, posix);
2048 1531 : if (req == NULL) {
2049 0 : status = NT_STATUS_NO_MEMORY;
2050 0 : goto done;
2051 : }
2052 1531 : tevent_req_set_callback(req, do_listing_cb, &state);
2053 :
2054 1531 : if (!py_tevent_req_wait_exc(self, req)) {
2055 0 : return NT_STATUS_INTERNAL_ERROR;
2056 : }
2057 1531 : TALLOC_FREE(req);
2058 :
2059 1531 : status = state.status;
2060 1531 : if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_FILES)) {
2061 1531 : status = NT_STATUS_OK;
2062 : }
2063 :
2064 1531 : done:
2065 1531 : TALLOC_FREE(mask);
2066 1531 : return status;
2067 : }
2068 :
2069 1531 : static PyObject *py_cli_list(struct py_cli_state *self,
2070 : PyObject *args,
2071 : PyObject *kwds)
2072 : {
2073 : char *base_dir;
2074 1531 : char *user_mask = NULL;
2075 1531 : unsigned int attribute = LIST_ATTRIBUTE_MASK;
2076 1531 : unsigned int info_level = 0;
2077 1531 : bool posix = false;
2078 : NTSTATUS status;
2079 1531 : enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2080 1531 : PyObject *result = NULL;
2081 1531 : const char *kwlist[] = { "directory", "mask", "attribs", "posix",
2082 : "info_level", NULL };
2083 1531 : NTSTATUS (*callback_fn)(struct file_info *, const char *, void *) =
2084 : &list_helper;
2085 :
2086 1531 : if (!ParseTupleAndKeywords(args, kwds, "z|sIpI:list", kwlist,
2087 : &base_dir, &user_mask, &attribute,
2088 : &posix, &info_level)) {
2089 0 : return NULL;
2090 : }
2091 :
2092 1531 : result = Py_BuildValue("[]");
2093 1531 : if (result == NULL) {
2094 0 : return NULL;
2095 : }
2096 :
2097 1531 : if (!info_level) {
2098 1531 : if (proto >= PROTOCOL_SMB2_02) {
2099 1531 : info_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
2100 : } else {
2101 0 : info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO;
2102 : }
2103 : }
2104 :
2105 1531 : if (posix) {
2106 0 : callback_fn = &list_posix_helper;
2107 : }
2108 1531 : status = do_listing(self, base_dir, user_mask, attribute,
2109 : info_level, posix, callback_fn, result);
2110 :
2111 1531 : if (!NT_STATUS_IS_OK(status)) {
2112 0 : Py_XDECREF(result);
2113 0 : PyErr_SetNTSTATUS(status);
2114 0 : return NULL;
2115 : }
2116 :
2117 1531 : return result;
2118 : }
2119 :
2120 464 : static PyObject *py_smb_unlink(struct py_cli_state *self, PyObject *args)
2121 : {
2122 : NTSTATUS status;
2123 464 : const char *filename = NULL;
2124 464 : struct tevent_req *req = NULL;
2125 464 : const uint32_t attrs = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2126 :
2127 464 : if (!PyArg_ParseTuple(args, "s:unlink", &filename)) {
2128 0 : return NULL;
2129 : }
2130 :
2131 464 : req = cli_unlink_send(NULL, self->ev, self->cli, filename, attrs);
2132 464 : if (!py_tevent_req_wait_exc(self, req)) {
2133 0 : return NULL;
2134 : }
2135 464 : status = cli_unlink_recv(req);
2136 464 : TALLOC_FREE(req);
2137 464 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
2138 :
2139 457 : Py_RETURN_NONE;
2140 : }
2141 :
2142 969 : static PyObject *py_smb_rmdir(struct py_cli_state *self, PyObject *args)
2143 : {
2144 : NTSTATUS status;
2145 969 : struct tevent_req *req = NULL;
2146 969 : const char *dirname = NULL;
2147 :
2148 969 : if (!PyArg_ParseTuple(args, "s:rmdir", &dirname)) {
2149 0 : return NULL;
2150 : }
2151 :
2152 969 : req = cli_rmdir_send(NULL, self->ev, self->cli, dirname);
2153 969 : if (!py_tevent_req_wait_exc(self, req)) {
2154 0 : return NULL;
2155 : }
2156 969 : status = cli_rmdir_recv(req);
2157 969 : TALLOC_FREE(req);
2158 969 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
2159 :
2160 969 : Py_RETURN_NONE;
2161 : }
2162 :
2163 : /*
2164 : * Create a directory
2165 : */
2166 912 : static PyObject *py_smb_mkdir(struct py_cli_state *self, PyObject *args)
2167 : {
2168 : NTSTATUS status;
2169 912 : const char *dirname = NULL;
2170 912 : struct tevent_req *req = NULL;
2171 :
2172 912 : if (!PyArg_ParseTuple(args, "s:mkdir", &dirname)) {
2173 0 : return NULL;
2174 : }
2175 :
2176 912 : req = cli_mkdir_send(NULL, self->ev, self->cli, dirname);
2177 912 : if (!py_tevent_req_wait_exc(self, req)) {
2178 0 : return NULL;
2179 : }
2180 912 : status = cli_mkdir_recv(req);
2181 912 : TALLOC_FREE(req);
2182 912 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
2183 :
2184 856 : Py_RETURN_NONE;
2185 : }
2186 :
2187 : /*
2188 : * Does a whoami call
2189 : */
2190 8 : static PyObject *py_smb_posix_whoami(struct py_cli_state *self,
2191 : PyObject *Py_UNUSED(ignored))
2192 : {
2193 8 : TALLOC_CTX *frame = talloc_stackframe();
2194 : NTSTATUS status;
2195 8 : struct tevent_req *req = NULL;
2196 : uint64_t uid;
2197 : uint64_t gid;
2198 : uint32_t num_gids;
2199 8 : uint64_t *gids = NULL;
2200 : uint32_t num_sids;
2201 8 : struct dom_sid *sids = NULL;
2202 : bool guest;
2203 8 : PyObject *py_gids = NULL;
2204 8 : PyObject *py_sids = NULL;
2205 8 : PyObject *py_guest = NULL;
2206 8 : PyObject *py_ret = NULL;
2207 : Py_ssize_t i;
2208 :
2209 8 : req = cli_posix_whoami_send(frame, self->ev, self->cli);
2210 8 : if (!py_tevent_req_wait_exc(self, req)) {
2211 0 : goto fail;
2212 : }
2213 8 : status = cli_posix_whoami_recv(req,
2214 : frame,
2215 : &uid,
2216 : &gid,
2217 : &num_gids,
2218 : &gids,
2219 : &num_sids,
2220 : &sids,
2221 : &guest);
2222 8 : if (!NT_STATUS_IS_OK(status)) {
2223 0 : PyErr_SetNTSTATUS(status);
2224 0 : goto fail;
2225 : }
2226 : if (num_gids > PY_SSIZE_T_MAX) {
2227 : PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many GIDs");
2228 : goto fail;
2229 : }
2230 : if (num_sids > PY_SSIZE_T_MAX) {
2231 : PyErr_SetString(PyExc_OverflowError, "posix_whoami: Too many SIDs");
2232 : goto fail;
2233 : }
2234 :
2235 8 : py_gids = PyList_New(num_gids);
2236 8 : if (!py_gids) {
2237 0 : goto fail;
2238 : }
2239 44 : for (i = 0; i < num_gids; ++i) {
2240 : int ret;
2241 36 : PyObject *py_item = PyLong_FromUnsignedLongLong(gids[i]);
2242 36 : if (!py_item) {
2243 0 : goto fail2;
2244 : }
2245 :
2246 36 : ret = PyList_SetItem(py_gids, i, py_item);
2247 36 : if (ret) {
2248 0 : goto fail2;
2249 : }
2250 : }
2251 8 : py_sids = PyList_New(num_sids);
2252 8 : if (!py_sids) {
2253 0 : goto fail2;
2254 : }
2255 98 : for (i = 0; i < num_sids; ++i) {
2256 : int ret;
2257 : struct dom_sid *sid;
2258 : PyObject *py_item;
2259 :
2260 90 : sid = dom_sid_dup(frame, &sids[i]);
2261 90 : if (!sid) {
2262 0 : PyErr_NoMemory();
2263 0 : goto fail3;
2264 : }
2265 :
2266 90 : py_item = pytalloc_steal(dom_sid_Type, sid);
2267 90 : if (!py_item) {
2268 0 : PyErr_NoMemory();
2269 0 : goto fail3;
2270 : }
2271 :
2272 90 : ret = PyList_SetItem(py_sids, i, py_item);
2273 90 : if (ret) {
2274 0 : goto fail3;
2275 : }
2276 : }
2277 :
2278 8 : py_guest = guest ? Py_True : Py_False;
2279 :
2280 8 : py_ret = Py_BuildValue("KKNNO",
2281 : uid,
2282 : gid,
2283 : py_gids,
2284 : py_sids,
2285 : py_guest);
2286 8 : if (!py_ret) {
2287 0 : goto fail3;
2288 : }
2289 :
2290 8 : TALLOC_FREE(frame);
2291 8 : return py_ret;
2292 :
2293 0 : fail3:
2294 0 : Py_CLEAR(py_sids);
2295 :
2296 0 : fail2:
2297 0 : Py_CLEAR(py_gids);
2298 :
2299 0 : fail:
2300 0 : TALLOC_FREE(frame);
2301 0 : return NULL;
2302 : }
2303 :
2304 : /*
2305 : * Checks existence of a directory
2306 : */
2307 2907 : static bool check_dir_path(struct py_cli_state *self, const char *path)
2308 : {
2309 : NTSTATUS status;
2310 2907 : struct tevent_req *req = NULL;
2311 :
2312 2907 : req = cli_chkpath_send(NULL, self->ev, self->cli, path);
2313 2907 : if (!py_tevent_req_wait_exc(self, req)) {
2314 0 : return false;
2315 : }
2316 2907 : status = cli_chkpath_recv(req);
2317 2907 : TALLOC_FREE(req);
2318 :
2319 2907 : return NT_STATUS_IS_OK(status);
2320 : }
2321 :
2322 2907 : static PyObject *py_smb_chkpath(struct py_cli_state *self, PyObject *args)
2323 : {
2324 2907 : const char *path = NULL;
2325 : bool dir_exists;
2326 :
2327 2907 : if (!PyArg_ParseTuple(args, "s:chkpath", &path)) {
2328 0 : return NULL;
2329 : }
2330 :
2331 2907 : dir_exists = check_dir_path(self, path);
2332 2907 : return PyBool_FromLong(dir_exists);
2333 : }
2334 :
2335 0 : static PyObject *py_smb_have_posix(struct py_cli_state *self,
2336 : PyObject *Py_UNUSED(ignored))
2337 : {
2338 0 : bool posix = smbXcli_conn_have_posix(self->cli->conn);
2339 :
2340 0 : if (posix) {
2341 0 : Py_RETURN_TRUE;
2342 : }
2343 0 : Py_RETURN_FALSE;
2344 : }
2345 :
2346 0 : static PyObject *py_smb_protocol(struct py_cli_state *self,
2347 : PyObject *Py_UNUSED(ignored))
2348 : {
2349 0 : enum protocol_types proto = smbXcli_conn_protocol(self->cli->conn);
2350 0 : PyObject *result = PyLong_FromLong(proto);
2351 0 : return result;
2352 : }
2353 :
2354 310 : static PyObject *py_smb_get_sd(struct py_cli_state *self, PyObject *args)
2355 : {
2356 : int fnum;
2357 : unsigned sinfo;
2358 310 : struct tevent_req *req = NULL;
2359 310 : struct security_descriptor *sd = NULL;
2360 : NTSTATUS status;
2361 :
2362 310 : if (!PyArg_ParseTuple(args, "iI:get_acl", &fnum, &sinfo)) {
2363 0 : return NULL;
2364 : }
2365 :
2366 310 : req = cli_query_security_descriptor_send(
2367 : NULL, self->ev, self->cli, fnum, sinfo);
2368 310 : if (!py_tevent_req_wait_exc(self, req)) {
2369 0 : return NULL;
2370 : }
2371 310 : status = cli_query_security_descriptor_recv(req, NULL, &sd);
2372 310 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
2373 :
2374 310 : return py_return_ndr_struct(
2375 : "samba.dcerpc.security", "descriptor", sd, sd);
2376 : }
2377 :
2378 162 : static PyObject *py_smb_set_sd(struct py_cli_state *self, PyObject *args)
2379 : {
2380 162 : PyObject *py_sd = NULL;
2381 162 : struct tevent_req *req = NULL;
2382 162 : struct security_descriptor *sd = NULL;
2383 : uint16_t fnum;
2384 : unsigned int sinfo;
2385 : NTSTATUS status;
2386 :
2387 162 : if (!PyArg_ParseTuple(args, "iOI:set_sd", &fnum, &py_sd, &sinfo)) {
2388 0 : return NULL;
2389 : }
2390 :
2391 162 : sd = pytalloc_get_type(py_sd, struct security_descriptor);
2392 162 : if (!sd) {
2393 0 : PyErr_Format(PyExc_TypeError,
2394 : "Expected dcerpc.security.descriptor as argument, got %s",
2395 : pytalloc_get_name(py_sd));
2396 0 : return NULL;
2397 : }
2398 :
2399 162 : req = cli_set_security_descriptor_send(
2400 : NULL, self->ev, self->cli, fnum, sinfo, sd);
2401 162 : if (!py_tevent_req_wait_exc(self, req)) {
2402 0 : return NULL;
2403 : }
2404 :
2405 162 : status = cli_set_security_descriptor_recv(req);
2406 162 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
2407 :
2408 162 : Py_RETURN_NONE;
2409 : }
2410 :
2411 0 : static PyObject *py_smb_smb1_posix(
2412 : struct py_cli_state *self, PyObject *Py_UNUSED(ignored))
2413 : {
2414 : NTSTATUS status;
2415 0 : struct tevent_req *req = NULL;
2416 : uint16_t major, minor;
2417 : uint32_t caplow, caphigh;
2418 0 : PyObject *result = NULL;
2419 :
2420 0 : req = cli_unix_extensions_version_send(NULL, self->ev, self->cli);
2421 0 : if (!py_tevent_req_wait_exc(self, req)) {
2422 0 : return NULL;
2423 : }
2424 0 : status = cli_unix_extensions_version_recv(
2425 : req, &major, &minor, &caplow, &caphigh);
2426 0 : TALLOC_FREE(req);
2427 0 : if (!NT_STATUS_IS_OK(status)) {
2428 0 : PyErr_SetNTSTATUS(status);
2429 0 : return NULL;
2430 : }
2431 :
2432 0 : req = cli_set_unix_extensions_capabilities_send(
2433 : NULL, self->ev, self->cli, major, minor, caplow, caphigh);
2434 0 : if (!py_tevent_req_wait_exc(self, req)) {
2435 0 : return NULL;
2436 : }
2437 0 : status = cli_set_unix_extensions_capabilities_recv(req);
2438 0 : TALLOC_FREE(req);
2439 0 : if (!NT_STATUS_IS_OK(status)) {
2440 0 : PyErr_SetNTSTATUS(status);
2441 0 : return NULL;
2442 : }
2443 :
2444 0 : result = Py_BuildValue(
2445 : "[IIII]",
2446 : (unsigned)minor,
2447 : (unsigned)major,
2448 : (unsigned)caplow,
2449 : (unsigned)caphigh);
2450 0 : return result;
2451 : }
2452 :
2453 0 : static PyObject *py_smb_smb1_readlink(
2454 : struct py_cli_state *self, PyObject *args)
2455 : {
2456 : NTSTATUS status;
2457 0 : const char *filename = NULL;
2458 0 : struct tevent_req *req = NULL;
2459 0 : char *target = NULL;
2460 0 : PyObject *result = NULL;
2461 :
2462 0 : if (!PyArg_ParseTuple(args, "s:smb1_readlink", &filename)) {
2463 0 : return NULL;
2464 : }
2465 :
2466 0 : req = cli_posix_readlink_send(NULL, self->ev, self->cli, filename);
2467 0 : if (!py_tevent_req_wait_exc(self, req)) {
2468 0 : return NULL;
2469 : }
2470 0 : status = cli_posix_readlink_recv(req, NULL, &target);
2471 0 : TALLOC_FREE(req);
2472 0 : if (!NT_STATUS_IS_OK(status)) {
2473 0 : PyErr_SetNTSTATUS(status);
2474 0 : return NULL;
2475 : }
2476 :
2477 0 : result = PyBytes_FromString(target);
2478 0 : TALLOC_FREE(target);
2479 0 : return result;
2480 : }
2481 :
2482 0 : static PyObject *py_smb_smb1_symlink(
2483 : struct py_cli_state *self, PyObject *args)
2484 : {
2485 : NTSTATUS status;
2486 0 : const char *target = NULL, *newname = NULL;
2487 0 : struct tevent_req *req = NULL;
2488 :
2489 0 : if (!PyArg_ParseTuple(args, "ss:smb1_symlink", &target, &newname)) {
2490 0 : return NULL;
2491 : }
2492 :
2493 0 : req = cli_posix_symlink_send(
2494 : NULL, self->ev, self->cli, target, newname);
2495 0 : if (!py_tevent_req_wait_exc(self, req)) {
2496 0 : return NULL;
2497 : }
2498 0 : status = cli_posix_symlink_recv(req);
2499 0 : TALLOC_FREE(req);
2500 0 : if (!NT_STATUS_IS_OK(status)) {
2501 0 : PyErr_SetNTSTATUS(status);
2502 0 : return NULL;
2503 : }
2504 :
2505 0 : Py_RETURN_NONE;
2506 : }
2507 :
2508 0 : static PyObject *py_cli_fsctl(
2509 : struct py_cli_state *self, PyObject *args, PyObject *kwds)
2510 : {
2511 : int fnum, ctl_code;
2512 0 : int max_out = 0;
2513 0 : char *buf = NULL;
2514 : Py_ssize_t buflen;
2515 0 : DATA_BLOB in = { .data = NULL, };
2516 0 : DATA_BLOB out = { .data = NULL, };
2517 0 : struct tevent_req *req = NULL;
2518 0 : PyObject *result = NULL;
2519 : static const char *kwlist[] = {
2520 : "fnum", "ctl_code", "in", "max_out", NULL,
2521 : };
2522 : NTSTATUS status;
2523 : bool ok;
2524 :
2525 0 : ok = ParseTupleAndKeywords(
2526 : args,
2527 : kwds,
2528 : "ii" PYARG_BYTES_LEN "i",
2529 : kwlist,
2530 : &fnum,
2531 : &ctl_code,
2532 : &buf,
2533 : &buflen,
2534 : &max_out);
2535 0 : if (!ok) {
2536 0 : return NULL;
2537 : }
2538 :
2539 0 : in = (DATA_BLOB) { .data = (uint8_t *)buf, .length = buflen, };
2540 :
2541 0 : req = cli_fsctl_send(
2542 : NULL, self->ev, self->cli, fnum, ctl_code, &in, max_out);
2543 :
2544 0 : if (!py_tevent_req_wait_exc(self, req)) {
2545 0 : return NULL;
2546 : }
2547 :
2548 0 : status = cli_fsctl_recv(req, NULL, &out);
2549 0 : if (!NT_STATUS_IS_OK(status)) {
2550 0 : PyErr_SetNTSTATUS(status);
2551 0 : return NULL;
2552 : }
2553 :
2554 0 : result = PyBytes_FromStringAndSize((char *)out.data, out.length);
2555 0 : data_blob_free(&out);
2556 0 : return result;
2557 : }
2558 :
2559 : static PyMethodDef py_cli_state_methods[] = {
2560 : { "settimeout", (PyCFunction)py_cli_settimeout, METH_VARARGS,
2561 : "settimeout(new_timeout_msecs) => return old_timeout_msecs" },
2562 : { "echo", (PyCFunction)py_cli_echo, METH_NOARGS,
2563 : "Ping the server connection" },
2564 : { "create", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create),
2565 : METH_VARARGS|METH_KEYWORDS,
2566 : "Open a file" },
2567 : { "create_ex",
2568 : PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_create_ex),
2569 : METH_VARARGS|METH_KEYWORDS,
2570 : "Open a file, SMB2 version returning create contexts" },
2571 : { "close", (PyCFunction)py_cli_close, METH_VARARGS,
2572 : "Close a file handle" },
2573 : { "write", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_write),
2574 : METH_VARARGS|METH_KEYWORDS,
2575 : "Write to a file handle" },
2576 : { "read", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_read),
2577 : METH_VARARGS|METH_KEYWORDS,
2578 : "Read from a file handle" },
2579 : { "truncate", PY_DISCARD_FUNC_SIG(PyCFunction,
2580 : py_cli_ftruncate),
2581 : METH_VARARGS|METH_KEYWORDS,
2582 : "Truncate a file" },
2583 : { "delete_on_close", PY_DISCARD_FUNC_SIG(PyCFunction,
2584 : py_cli_delete_on_close),
2585 : METH_VARARGS|METH_KEYWORDS,
2586 : "Set/Reset the delete on close flag" },
2587 : { "notify", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_notify),
2588 : METH_VARARGS|METH_KEYWORDS,
2589 : "Wait for change notifications: \n"
2590 : "notify(fnum, buffer_size, completion_filter...) -> "
2591 : "libsmb_samba_internal.Notify request handle\n" },
2592 : { "list", PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_list),
2593 : METH_VARARGS|METH_KEYWORDS,
2594 : "list(directory, mask='*', attribs=DEFAULT_ATTRS) -> "
2595 : "directory contents as a dictionary\n"
2596 : "\t\tDEFAULT_ATTRS: FILE_ATTRIBUTE_SYSTEM | "
2597 : "FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE\n\n"
2598 : "\t\tList contents of a directory. The keys are, \n"
2599 : "\t\t\tname: Long name of the directory item\n"
2600 : "\t\t\tshort_name: Short name of the directory item\n"
2601 : "\t\t\tsize: File size in bytes\n"
2602 : "\t\t\tattrib: Attributes\n"
2603 : "\t\t\tmtime: Modification time\n" },
2604 : { "get_oplock_break", (PyCFunction)py_cli_get_oplock_break,
2605 : METH_VARARGS, "Wait for an oplock break" },
2606 : { "unlink", (PyCFunction)py_smb_unlink,
2607 : METH_VARARGS,
2608 : "unlink(path) -> None\n\n \t\tDelete a file." },
2609 : { "mkdir", (PyCFunction)py_smb_mkdir, METH_VARARGS,
2610 : "mkdir(path) -> None\n\n \t\tCreate a directory." },
2611 : { "posix_whoami", (PyCFunction)py_smb_posix_whoami, METH_NOARGS,
2612 : "posix_whoami() -> (uid, gid, gids, sids, guest)" },
2613 : { "rmdir", (PyCFunction)py_smb_rmdir, METH_VARARGS,
2614 : "rmdir(path) -> None\n\n \t\tDelete a directory." },
2615 : { "rename",
2616 : PY_DISCARD_FUNC_SIG(PyCFunction, py_cli_rename),
2617 : METH_VARARGS|METH_KEYWORDS,
2618 : "rename(src,dst) -> None\n\n \t\tRename a file." },
2619 : { "chkpath", (PyCFunction)py_smb_chkpath, METH_VARARGS,
2620 : "chkpath(dir_path) -> True or False\n\n"
2621 : "\t\tReturn true if directory exists, false otherwise." },
2622 : { "savefile", (PyCFunction)py_smb_savefile, METH_VARARGS,
2623 : "savefile(path, bytes) -> None\n\n"
2624 : "\t\tWrite bytes to file." },
2625 : { "loadfile", (PyCFunction)py_smb_loadfile, METH_VARARGS,
2626 : "loadfile(path) -> file contents as a bytes object"
2627 : "\n\n\t\tRead contents of a file." },
2628 : { "get_sd", (PyCFunction)py_smb_get_sd, METH_VARARGS,
2629 : "get_sd(fnum[, security_info=0]) -> security_descriptor object\n\n"
2630 : "\t\tGet security descriptor for opened file." },
2631 : { "set_sd", (PyCFunction)py_smb_set_sd, METH_VARARGS,
2632 : "set_sd(fnum, security_descriptor[, security_info=0]) -> None\n\n"
2633 : "\t\tSet security descriptor for opened file." },
2634 : { "protocol",
2635 : (PyCFunction)py_smb_protocol,
2636 : METH_NOARGS,
2637 : "protocol() -> Number"
2638 : },
2639 : { "have_posix",
2640 : (PyCFunction)py_smb_have_posix,
2641 : METH_NOARGS,
2642 : "have_posix() -> True/False\n\n"
2643 : "\t\tReturn if the server has posix extensions"
2644 : },
2645 : { "smb1_posix",
2646 : (PyCFunction)py_smb_smb1_posix,
2647 : METH_NOARGS,
2648 : "Negotiate SMB1 posix extensions",
2649 : },
2650 : { "smb1_readlink",
2651 : (PyCFunction)py_smb_smb1_readlink,
2652 : METH_VARARGS,
2653 : "smb1_readlink(path) -> link target",
2654 : },
2655 : { "smb1_symlink",
2656 : (PyCFunction)py_smb_smb1_symlink,
2657 : METH_VARARGS,
2658 : "smb1_symlink(target, newname) -> None",
2659 : },
2660 : { "fsctl",
2661 : (PyCFunction)py_cli_fsctl,
2662 : METH_VARARGS|METH_KEYWORDS,
2663 : "fsctl(fnum, ctl_code, in_bytes, max_out) -> out_bytes",
2664 : },
2665 : { NULL, NULL, 0, NULL }
2666 : };
2667 :
2668 : static PyTypeObject py_cli_state_type = {
2669 : PyVarObject_HEAD_INIT(NULL, 0)
2670 : .tp_name = "libsmb_samba_cwrapper.LibsmbCConn",
2671 : .tp_basicsize = sizeof(struct py_cli_state),
2672 : .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
2673 : .tp_doc = "libsmb cwrapper connection",
2674 : .tp_new = py_cli_state_new,
2675 : .tp_init = (initproc)py_cli_state_init,
2676 : .tp_dealloc = (destructor)py_cli_state_dealloc,
2677 : .tp_methods = py_cli_state_methods,
2678 : };
2679 :
2680 : static PyMethodDef py_libsmb_methods[] = {
2681 : {0},
2682 : };
2683 :
2684 : void initlibsmb_samba_cwrapper(void);
2685 :
2686 : static struct PyModuleDef moduledef = {
2687 : PyModuleDef_HEAD_INIT,
2688 : .m_name = "libsmb_samba_cwrapper",
2689 : .m_doc = "libsmb wrapper",
2690 : .m_size = -1,
2691 : .m_methods = py_libsmb_methods,
2692 : };
2693 :
2694 1212 : MODULE_INIT_FUNC(libsmb_samba_cwrapper)
2695 : {
2696 1212 : PyObject *m = NULL;
2697 1212 : PyObject *mod = NULL;
2698 :
2699 1212 : talloc_stackframe();
2700 :
2701 1212 : if (PyType_Ready(&py_cli_state_type) < 0) {
2702 0 : return NULL;
2703 : }
2704 1212 : if (PyType_Ready(&py_cli_notify_state_type) < 0) {
2705 0 : return NULL;
2706 : }
2707 :
2708 1212 : m = PyModule_Create(&moduledef);
2709 1212 : if (m == NULL) {
2710 0 : return m;
2711 : }
2712 :
2713 : /* Import dom_sid type from dcerpc.security */
2714 1212 : mod = PyImport_ImportModule("samba.dcerpc.security");
2715 1212 : if (mod == NULL) {
2716 0 : return NULL;
2717 : }
2718 :
2719 1212 : dom_sid_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "dom_sid");
2720 1212 : if (dom_sid_Type == NULL) {
2721 0 : Py_DECREF(mod);
2722 0 : return NULL;
2723 : }
2724 :
2725 1212 : Py_INCREF(&py_cli_state_type);
2726 1212 : PyModule_AddObject(m, "LibsmbCConn", (PyObject *)&py_cli_state_type);
2727 :
2728 : #define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
2729 :
2730 1212 : ADD_FLAGS(PROTOCOL_NONE);
2731 1212 : ADD_FLAGS(PROTOCOL_CORE);
2732 1212 : ADD_FLAGS(PROTOCOL_COREPLUS);
2733 1212 : ADD_FLAGS(PROTOCOL_LANMAN1);
2734 1212 : ADD_FLAGS(PROTOCOL_LANMAN2);
2735 1212 : ADD_FLAGS(PROTOCOL_NT1);
2736 1212 : ADD_FLAGS(PROTOCOL_SMB2_02);
2737 1212 : ADD_FLAGS(PROTOCOL_SMB2_10);
2738 1212 : ADD_FLAGS(PROTOCOL_SMB3_00);
2739 1212 : ADD_FLAGS(PROTOCOL_SMB3_02);
2740 1212 : ADD_FLAGS(PROTOCOL_SMB3_11);
2741 :
2742 1212 : ADD_FLAGS(FILE_ATTRIBUTE_READONLY);
2743 1212 : ADD_FLAGS(FILE_ATTRIBUTE_HIDDEN);
2744 1212 : ADD_FLAGS(FILE_ATTRIBUTE_SYSTEM);
2745 1212 : ADD_FLAGS(FILE_ATTRIBUTE_VOLUME);
2746 1212 : ADD_FLAGS(FILE_ATTRIBUTE_DIRECTORY);
2747 1212 : ADD_FLAGS(FILE_ATTRIBUTE_ARCHIVE);
2748 1212 : ADD_FLAGS(FILE_ATTRIBUTE_DEVICE);
2749 1212 : ADD_FLAGS(FILE_ATTRIBUTE_NORMAL);
2750 1212 : ADD_FLAGS(FILE_ATTRIBUTE_TEMPORARY);
2751 1212 : ADD_FLAGS(FILE_ATTRIBUTE_SPARSE);
2752 1212 : ADD_FLAGS(FILE_ATTRIBUTE_REPARSE_POINT);
2753 1212 : ADD_FLAGS(FILE_ATTRIBUTE_COMPRESSED);
2754 1212 : ADD_FLAGS(FILE_ATTRIBUTE_OFFLINE);
2755 1212 : ADD_FLAGS(FILE_ATTRIBUTE_NONINDEXED);
2756 1212 : ADD_FLAGS(FILE_ATTRIBUTE_ENCRYPTED);
2757 1212 : ADD_FLAGS(FILE_ATTRIBUTE_ALL_MASK);
2758 :
2759 1212 : ADD_FLAGS(FILE_DIRECTORY_FILE);
2760 1212 : ADD_FLAGS(FILE_WRITE_THROUGH);
2761 1212 : ADD_FLAGS(FILE_SEQUENTIAL_ONLY);
2762 1212 : ADD_FLAGS(FILE_NO_INTERMEDIATE_BUFFERING);
2763 1212 : ADD_FLAGS(FILE_SYNCHRONOUS_IO_ALERT);
2764 1212 : ADD_FLAGS(FILE_SYNCHRONOUS_IO_NONALERT);
2765 1212 : ADD_FLAGS(FILE_NON_DIRECTORY_FILE);
2766 1212 : ADD_FLAGS(FILE_CREATE_TREE_CONNECTION);
2767 1212 : ADD_FLAGS(FILE_COMPLETE_IF_OPLOCKED);
2768 1212 : ADD_FLAGS(FILE_NO_EA_KNOWLEDGE);
2769 1212 : ADD_FLAGS(FILE_EIGHT_DOT_THREE_ONLY);
2770 1212 : ADD_FLAGS(FILE_RANDOM_ACCESS);
2771 1212 : ADD_FLAGS(FILE_DELETE_ON_CLOSE);
2772 1212 : ADD_FLAGS(FILE_OPEN_BY_FILE_ID);
2773 1212 : ADD_FLAGS(FILE_OPEN_FOR_BACKUP_INTENT);
2774 1212 : ADD_FLAGS(FILE_NO_COMPRESSION);
2775 1212 : ADD_FLAGS(FILE_RESERVER_OPFILTER);
2776 1212 : ADD_FLAGS(FILE_OPEN_REPARSE_POINT);
2777 1212 : ADD_FLAGS(FILE_OPEN_NO_RECALL);
2778 1212 : ADD_FLAGS(FILE_OPEN_FOR_FREE_SPACE_QUERY);
2779 :
2780 1212 : ADD_FLAGS(FILE_SHARE_READ);
2781 1212 : ADD_FLAGS(FILE_SHARE_WRITE);
2782 1212 : ADD_FLAGS(FILE_SHARE_DELETE);
2783 :
2784 : /* change notify completion filter flags */
2785 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_FILE_NAME);
2786 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_DIR_NAME);
2787 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_ATTRIBUTES);
2788 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_SIZE);
2789 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_WRITE);
2790 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_LAST_ACCESS);
2791 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_CREATION);
2792 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_EA);
2793 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_SECURITY);
2794 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_NAME);
2795 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_SIZE);
2796 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_STREAM_WRITE);
2797 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_NAME);
2798 1212 : ADD_FLAGS(FILE_NOTIFY_CHANGE_ALL);
2799 :
2800 : /* change notify action results */
2801 1212 : ADD_FLAGS(NOTIFY_ACTION_ADDED);
2802 1212 : ADD_FLAGS(NOTIFY_ACTION_REMOVED);
2803 1212 : ADD_FLAGS(NOTIFY_ACTION_MODIFIED);
2804 1212 : ADD_FLAGS(NOTIFY_ACTION_OLD_NAME);
2805 1212 : ADD_FLAGS(NOTIFY_ACTION_NEW_NAME);
2806 1212 : ADD_FLAGS(NOTIFY_ACTION_ADDED_STREAM);
2807 1212 : ADD_FLAGS(NOTIFY_ACTION_REMOVED_STREAM);
2808 1212 : ADD_FLAGS(NOTIFY_ACTION_MODIFIED_STREAM);
2809 :
2810 : /* CreateDisposition values */
2811 1212 : ADD_FLAGS(FILE_SUPERSEDE);
2812 1212 : ADD_FLAGS(FILE_OPEN);
2813 1212 : ADD_FLAGS(FILE_CREATE);
2814 1212 : ADD_FLAGS(FILE_OPEN_IF);
2815 1212 : ADD_FLAGS(FILE_OVERWRITE);
2816 1212 : ADD_FLAGS(FILE_OVERWRITE_IF);
2817 :
2818 1212 : ADD_FLAGS(FSCTL_DFS_GET_REFERRALS);
2819 1212 : ADD_FLAGS(FSCTL_DFS_GET_REFERRALS_EX);
2820 1212 : ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_1);
2821 1212 : ADD_FLAGS(FSCTL_REQUEST_OPLOCK_LEVEL_2);
2822 1212 : ADD_FLAGS(FSCTL_REQUEST_BATCH_OPLOCK);
2823 1212 : ADD_FLAGS(FSCTL_OPLOCK_BREAK_ACKNOWLEDGE);
2824 1212 : ADD_FLAGS(FSCTL_OPBATCH_ACK_CLOSE_PENDING);
2825 1212 : ADD_FLAGS(FSCTL_OPLOCK_BREAK_NOTIFY);
2826 1212 : ADD_FLAGS(FSCTL_GET_COMPRESSION);
2827 1212 : ADD_FLAGS(FSCTL_FILESYS_GET_STATISTICS);
2828 1212 : ADD_FLAGS(FSCTL_GET_NTFS_VOLUME_DATA);
2829 1212 : ADD_FLAGS(FSCTL_IS_VOLUME_DIRTY);
2830 1212 : ADD_FLAGS(FSCTL_FIND_FILES_BY_SID);
2831 1212 : ADD_FLAGS(FSCTL_SET_OBJECT_ID);
2832 1212 : ADD_FLAGS(FSCTL_GET_OBJECT_ID);
2833 1212 : ADD_FLAGS(FSCTL_DELETE_OBJECT_ID);
2834 1212 : ADD_FLAGS(FSCTL_SET_REPARSE_POINT);
2835 1212 : ADD_FLAGS(FSCTL_GET_REPARSE_POINT);
2836 1212 : ADD_FLAGS(FSCTL_DELETE_REPARSE_POINT);
2837 1212 : ADD_FLAGS(FSCTL_SET_OBJECT_ID_EXTENDED);
2838 1212 : ADD_FLAGS(FSCTL_CREATE_OR_GET_OBJECT_ID);
2839 1212 : ADD_FLAGS(FSCTL_SET_SPARSE);
2840 1212 : ADD_FLAGS(FSCTL_SET_ZERO_DATA);
2841 1212 : ADD_FLAGS(FSCTL_SET_ZERO_ON_DEALLOCATION);
2842 1212 : ADD_FLAGS(FSCTL_READ_FILE_USN_DATA);
2843 1212 : ADD_FLAGS(FSCTL_WRITE_USN_CLOSE_RECORD);
2844 1212 : ADD_FLAGS(FSCTL_QUERY_ALLOCATED_RANGES);
2845 1212 : ADD_FLAGS(FSCTL_QUERY_ON_DISK_VOLUME_INFO);
2846 1212 : ADD_FLAGS(FSCTL_QUERY_SPARING_INFO);
2847 1212 : ADD_FLAGS(FSCTL_FILE_LEVEL_TRIM);
2848 1212 : ADD_FLAGS(FSCTL_OFFLOAD_READ);
2849 1212 : ADD_FLAGS(FSCTL_OFFLOAD_WRITE);
2850 1212 : ADD_FLAGS(FSCTL_SET_INTEGRITY_INFORMATION);
2851 1212 : ADD_FLAGS(FSCTL_DUP_EXTENTS_TO_FILE);
2852 1212 : ADD_FLAGS(FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX);
2853 1212 : ADD_FLAGS(FSCTL_STORAGE_QOS_CONTROL);
2854 1212 : ADD_FLAGS(FSCTL_SVHDX_SYNC_TUNNEL_REQUEST);
2855 1212 : ADD_FLAGS(FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT);
2856 1212 : ADD_FLAGS(FSCTL_PIPE_PEEK);
2857 1212 : ADD_FLAGS(FSCTL_NAMED_PIPE_READ_WRITE);
2858 1212 : ADD_FLAGS(FSCTL_PIPE_TRANSCEIVE);
2859 1212 : ADD_FLAGS(FSCTL_PIPE_WAIT);
2860 1212 : ADD_FLAGS(FSCTL_GET_SHADOW_COPY_DATA);
2861 1212 : ADD_FLAGS(FSCTL_SRV_ENUM_SNAPS);
2862 1212 : ADD_FLAGS(FSCTL_SRV_REQUEST_RESUME_KEY);
2863 1212 : ADD_FLAGS(FSCTL_SRV_COPYCHUNK);
2864 1212 : ADD_FLAGS(FSCTL_SRV_COPYCHUNK_WRITE);
2865 1212 : ADD_FLAGS(FSCTL_SRV_READ_HASH);
2866 1212 : ADD_FLAGS(FSCTL_LMR_REQ_RESILIENCY);
2867 1212 : ADD_FLAGS(FSCTL_LMR_SET_LINK_TRACKING_INFORMATION);
2868 1212 : ADD_FLAGS(FSCTL_QUERY_NETWORK_INTERFACE_INFO);
2869 :
2870 1212 : ADD_FLAGS(SYMLINK_ERROR_TAG);
2871 1212 : ADD_FLAGS(SYMLINK_FLAG_RELATIVE);
2872 1212 : ADD_FLAGS(SYMLINK_ADMIN);
2873 1212 : ADD_FLAGS(SYMLINK_UNTRUSTED);
2874 1212 : ADD_FLAGS(SYMLINK_TRUST_UNKNOWN);
2875 1212 : ADD_FLAGS(SYMLINK_TRUST_MASK);
2876 :
2877 1212 : ADD_FLAGS(IO_REPARSE_TAG_SYMLINK);
2878 1212 : ADD_FLAGS(IO_REPARSE_TAG_MOUNT_POINT);
2879 1212 : ADD_FLAGS(IO_REPARSE_TAG_HSM);
2880 1212 : ADD_FLAGS(IO_REPARSE_TAG_SIS);
2881 1212 : ADD_FLAGS(IO_REPARSE_TAG_DFS);
2882 1212 : ADD_FLAGS(IO_REPARSE_TAG_NFS);
2883 :
2884 : #define ADD_STRING(val) PyModule_AddObject(m, #val, PyBytes_FromString(val))
2885 :
2886 1212 : ADD_STRING(SMB2_CREATE_TAG_EXTA);
2887 1212 : ADD_STRING(SMB2_CREATE_TAG_MXAC);
2888 1212 : ADD_STRING(SMB2_CREATE_TAG_SECD);
2889 1212 : ADD_STRING(SMB2_CREATE_TAG_DHNQ);
2890 1212 : ADD_STRING(SMB2_CREATE_TAG_DHNC);
2891 1212 : ADD_STRING(SMB2_CREATE_TAG_ALSI);
2892 1212 : ADD_STRING(SMB2_CREATE_TAG_TWRP);
2893 1212 : ADD_STRING(SMB2_CREATE_TAG_QFID);
2894 1212 : ADD_STRING(SMB2_CREATE_TAG_RQLS);
2895 1212 : ADD_STRING(SMB2_CREATE_TAG_DH2Q);
2896 1212 : ADD_STRING(SMB2_CREATE_TAG_DH2C);
2897 1212 : ADD_STRING(SMB2_CREATE_TAG_AAPL);
2898 1212 : ADD_STRING(SMB2_CREATE_TAG_APP_INSTANCE_ID);
2899 1212 : ADD_STRING(SVHDX_OPEN_DEVICE_CONTEXT);
2900 1212 : ADD_STRING(SMB2_CREATE_TAG_POSIX);
2901 1212 : ADD_FLAGS(SMB2_FIND_POSIX_INFORMATION);
2902 1212 : ADD_FLAGS(FILE_SUPERSEDE);
2903 1212 : ADD_FLAGS(FILE_OPEN);
2904 1212 : ADD_FLAGS(FILE_CREATE);
2905 1212 : ADD_FLAGS(FILE_OPEN_IF);
2906 1212 : ADD_FLAGS(FILE_OVERWRITE);
2907 1212 : ADD_FLAGS(FILE_OVERWRITE_IF);
2908 1212 : ADD_FLAGS(FILE_DIRECTORY_FILE);
2909 :
2910 1212 : return m;
2911 : }
|