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