Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Set NT and POSIX ACLs and other VFS operations from Python
4 :
5 : Copyrigyt (C) Andrew Bartlett 2012
6 : Copyright (C) Jeremy Allison 1994-2009.
7 : Copyright (C) Andreas Gruenbacher 2002.
8 : Copyright (C) Simo Sorce <idra@samba.org> 2009.
9 : Copyright (C) Simo Sorce 2002
10 : Copyright (C) Eric Lorimer 2002
11 :
12 : This program is free software; you can redistribute it and/or modify
13 : it under the terms of the GNU General Public License as published by
14 : the Free Software Foundation; either version 3 of the License, or
15 : (at your option) any later version.
16 :
17 : This program is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : GNU General Public License for more details.
21 :
22 : You should have received a copy of the GNU General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include <Python.h>
27 : #include "includes.h"
28 : #include "python/py3compat.h"
29 : #include "python/modules.h"
30 : #include "smbd/smbd.h"
31 : #include "libcli/util/pyerrors.h"
32 : #include "librpc/rpc/pyrpc_util.h"
33 : #include <pytalloc.h>
34 : #include "system/filesys.h"
35 : #include "passdb.h"
36 : #include "secrets.h"
37 : #include "auth.h"
38 :
39 : extern const struct generic_mapping file_generic_mapping;
40 :
41 : #undef DBGC_CLASS
42 : #define DBGC_CLASS DBGC_ACLS
43 :
44 : #ifdef O_DIRECTORY
45 : #define DIRECTORY_FLAGS O_RDONLY|O_DIRECTORY
46 : #else
47 : /* POSIX allows us to open a directory with O_RDONLY. */
48 : #define DIRECTORY_FLAGS O_RDONLY
49 : #endif
50 :
51 :
52 1519 : static connection_struct *get_conn_tos(
53 : const char *service,
54 : const struct auth_session_info *session_info)
55 : {
56 1519 : struct conn_struct_tos *c = NULL;
57 1519 : int snum = -1;
58 : NTSTATUS status;
59 1519 : char *cwd = NULL;
60 1519 : struct smb_filename cwd_fname = {0};
61 : int ret;
62 :
63 1519 : if (!posix_locking_init(false)) {
64 0 : PyErr_NoMemory();
65 0 : return NULL;
66 : }
67 :
68 1519 : if (service) {
69 1141 : snum = lp_servicenumber(service);
70 1141 : if (snum == -1) {
71 0 : PyErr_SetString(PyExc_RuntimeError, "unknown service");
72 0 : return NULL;
73 : }
74 : }
75 :
76 : /*
77 : * Make sure that session unix info is filled,
78 : * which is required by vfs operations.
79 : */
80 1519 : if (session_info->unix_info == NULL) {
81 0 : PyErr_SetString(PyExc_RuntimeError,
82 : "Session unix info not initialized");
83 0 : return NULL;
84 : }
85 1519 : if (session_info->unix_info->unix_name == NULL) {
86 0 : PyErr_SetString(PyExc_RuntimeError,
87 : "Session unix info not available");
88 0 : return NULL;
89 : }
90 :
91 1519 : status = create_conn_struct_tos(NULL,
92 : snum,
93 : "/",
94 : session_info,
95 : &c);
96 1519 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
97 :
98 : /* Ignore read-only and share restrictions */
99 1519 : c->conn->read_only = false;
100 1519 : c->conn->share_access = SEC_RIGHTS_FILE_ALL;
101 :
102 : /* Provided by libreplace if not present. Always mallocs. */
103 1519 : cwd = get_current_dir_name();
104 1519 : if (cwd == NULL) {
105 0 : PyErr_NoMemory();
106 0 : return NULL;
107 : }
108 :
109 1519 : cwd_fname.base_name = cwd;
110 : /*
111 : * We need to call vfs_ChDir() to initialize
112 : * conn->cwd_fsp correctly. Change directory
113 : * to current directory (so no change for process).
114 : */
115 1519 : ret = vfs_ChDir(c->conn, &cwd_fname);
116 1519 : if (ret != 0) {
117 0 : status = map_nt_error_from_unix(errno);
118 0 : SAFE_FREE(cwd);
119 0 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
120 : }
121 :
122 1519 : SAFE_FREE(cwd);
123 :
124 1519 : return c->conn;
125 : }
126 :
127 29 : static int set_sys_acl_conn(const char *fname,
128 : SMB_ACL_TYPE_T acltype,
129 : SMB_ACL_T theacl, connection_struct *conn)
130 : {
131 : int ret;
132 29 : struct smb_filename *smb_fname = NULL;
133 29 : TALLOC_CTX *frame = talloc_stackframe();
134 : NTSTATUS status;
135 :
136 29 : smb_fname = synthetic_smb_fname_split(frame,
137 : fname,
138 29 : lp_posix_pathnames());
139 29 : if (smb_fname == NULL) {
140 0 : TALLOC_FREE(frame);
141 0 : return -1;
142 : }
143 :
144 29 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
145 29 : if (!NT_STATUS_IS_OK(status)) {
146 0 : TALLOC_FREE(frame);
147 0 : errno = map_errno_from_nt_status(status);
148 0 : return -1;
149 : }
150 :
151 29 : ret = SMB_VFS_SYS_ACL_SET_FD(smb_fname->fsp, acltype, theacl);
152 :
153 29 : status = fd_close(smb_fname->fsp);
154 29 : if (!NT_STATUS_IS_OK(status)) {
155 0 : TALLOC_FREE(frame);
156 0 : errno = map_errno_from_nt_status(status);
157 0 : return -1;
158 : }
159 :
160 29 : TALLOC_FREE(frame);
161 29 : return ret;
162 : }
163 :
164 :
165 1788 : static NTSTATUS init_files_struct(TALLOC_CTX *mem_ctx,
166 : const char *fname,
167 : struct connection_struct *conn,
168 : int flags,
169 : struct files_struct **_fsp)
170 : {
171 1788 : struct vfs_open_how how = { .flags = flags, .mode = 0644 };
172 1788 : struct smb_filename *smb_fname = NULL;
173 : int fd;
174 : mode_t saved_umask;
175 : struct files_struct *fsp;
176 1788 : struct files_struct *fspcwd = NULL;
177 : NTSTATUS status;
178 :
179 1788 : fsp = talloc_zero(mem_ctx, struct files_struct);
180 1788 : if (fsp == NULL) {
181 0 : return NT_STATUS_NO_MEMORY;
182 : }
183 1788 : fsp->fh = fd_handle_create(fsp);
184 1788 : if (fsp->fh == NULL) {
185 0 : return NT_STATUS_NO_MEMORY;
186 : }
187 1788 : fsp->conn = conn;
188 :
189 1788 : smb_fname = synthetic_smb_fname_split(fsp,
190 : fname,
191 1788 : lp_posix_pathnames());
192 1788 : if (smb_fname == NULL) {
193 0 : return NT_STATUS_NO_MEMORY;
194 : }
195 :
196 1788 : fsp->fsp_name = smb_fname;
197 :
198 1788 : status = vfs_at_fspcwd(fsp, conn, &fspcwd);
199 1788 : if (!NT_STATUS_IS_OK(status)) {
200 0 : return status;
201 : }
202 :
203 : /*
204 : * we want total control over the permissions on created files,
205 : * so set our umask to 0 (this matters if flags contains O_CREAT)
206 : */
207 1788 : saved_umask = umask(0);
208 :
209 1788 : fd = SMB_VFS_OPENAT(conn,
210 : fspcwd,
211 : smb_fname,
212 : fsp,
213 : &how);
214 :
215 1788 : umask(saved_umask);
216 :
217 1788 : if (fd == -1) {
218 749 : int err = errno;
219 749 : if (err == ENOENT) {
220 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
221 : }
222 749 : return NT_STATUS_INVALID_PARAMETER;
223 : }
224 1039 : fsp_set_fd(fsp, fd);
225 :
226 1039 : status = vfs_stat_fsp(fsp);
227 1039 : if (!NT_STATUS_IS_OK(status)) {
228 : /* If we have an fd, this stat should succeed. */
229 0 : DEBUG(0,("Error doing fstat on open file %s (%s)\n",
230 : smb_fname_str_dbg(smb_fname),
231 : nt_errstr(status) ));
232 0 : return status;
233 : }
234 :
235 1039 : fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
236 1039 : fsp->vuid = UID_FIELD_INVALID;
237 1039 : fsp->file_pid = 0;
238 1039 : fsp->fsp_flags.can_lock = true;
239 1039 : fsp->fsp_flags.can_read = true;
240 1039 : fsp->fsp_flags.can_write = true;
241 1039 : fsp->print_file = NULL;
242 1039 : fsp->fsp_flags.modified = false;
243 1039 : fsp->sent_oplock_break = NO_BREAK_SENT;
244 1039 : fsp->fsp_flags.is_directory = S_ISDIR(smb_fname->st.st_ex_mode);
245 :
246 1039 : *_fsp = fsp;
247 :
248 1039 : return NT_STATUS_OK;
249 : }
250 :
251 929 : static NTSTATUS set_nt_acl_conn(const char *fname,
252 : uint32_t security_info_sent, const struct security_descriptor *sd,
253 : connection_struct *conn)
254 : {
255 929 : TALLOC_CTX *frame = talloc_stackframe();
256 929 : struct files_struct *fsp = NULL;
257 929 : NTSTATUS status = NT_STATUS_OK;
258 :
259 : /* first, try to open it as a file with flag O_RDWR */
260 929 : status = init_files_struct(frame,
261 : fname,
262 : conn,
263 : O_RDWR,
264 : &fsp);
265 929 : if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
266 : /* if fail, try to open as dir */
267 749 : status = init_files_struct(frame,
268 : fname,
269 : conn,
270 : DIRECTORY_FLAGS,
271 : &fsp);
272 : }
273 :
274 929 : if (!NT_STATUS_IS_OK(status)) {
275 0 : DBG_ERR("init_files_struct failed: %s\n",
276 : nt_errstr(status));
277 0 : if (fsp != NULL) {
278 0 : fd_close(fsp);
279 : }
280 0 : TALLOC_FREE(frame);
281 0 : return status;
282 : }
283 :
284 929 : status = SMB_VFS_FSET_NT_ACL(metadata_fsp(fsp), security_info_sent, sd);
285 929 : if (!NT_STATUS_IS_OK(status)) {
286 0 : DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned %s.\n", nt_errstr(status)));
287 : }
288 :
289 929 : fd_close(fsp);
290 :
291 929 : TALLOC_FREE(frame);
292 929 : return status;
293 : }
294 :
295 110 : static NTSTATUS get_nt_acl_conn(TALLOC_CTX *mem_ctx,
296 : const char *fname,
297 : connection_struct *conn,
298 : uint32_t security_info_wanted,
299 : struct security_descriptor **sd)
300 : {
301 110 : TALLOC_CTX *frame = talloc_stackframe();
302 : NTSTATUS status;
303 110 : struct smb_filename *smb_fname = NULL;
304 :
305 110 : smb_fname = synthetic_smb_fname_split(frame,
306 : fname,
307 110 : lp_posix_pathnames());
308 :
309 110 : if (smb_fname == NULL) {
310 0 : TALLOC_FREE(frame);
311 0 : return NT_STATUS_NO_MEMORY;
312 : }
313 :
314 110 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
315 110 : if (!NT_STATUS_IS_OK(status)) {
316 0 : TALLOC_FREE(frame);
317 0 : return status;
318 : }
319 :
320 110 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(smb_fname->fsp),
321 : security_info_wanted,
322 : mem_ctx,
323 : sd);
324 110 : if (!NT_STATUS_IS_OK(status)) {
325 0 : DBG_ERR("fget_nt_acl_at returned %s.\n",
326 : nt_errstr(status));
327 : }
328 :
329 110 : status = fd_close(smb_fname->fsp);
330 110 : if (!NT_STATUS_IS_OK(status)) {
331 0 : TALLOC_FREE(frame);
332 0 : return status;
333 : }
334 :
335 110 : TALLOC_FREE(frame);
336 :
337 110 : return status;
338 : }
339 :
340 145 : static int set_acl_entry_perms(SMB_ACL_ENTRY_T entry, mode_t perm_mask)
341 : {
342 145 : SMB_ACL_PERMSET_T perms = NULL;
343 :
344 145 : if (sys_acl_get_permset(entry, &perms) != 0) {
345 0 : return -1;
346 : }
347 :
348 145 : if (sys_acl_clear_perms(perms) != 0) {
349 0 : return -1;
350 : }
351 :
352 290 : if ((perm_mask & SMB_ACL_READ) != 0 &&
353 145 : sys_acl_add_perm(perms, SMB_ACL_READ) != 0) {
354 0 : return -1;
355 : }
356 :
357 203 : if ((perm_mask & SMB_ACL_WRITE) != 0 &&
358 58 : sys_acl_add_perm(perms, SMB_ACL_WRITE) != 0) {
359 0 : return -1;
360 : }
361 :
362 290 : if ((perm_mask & SMB_ACL_EXECUTE) != 0 &&
363 145 : sys_acl_add_perm(perms, SMB_ACL_EXECUTE) != 0) {
364 0 : return -1;
365 : }
366 :
367 145 : if (sys_acl_set_permset(entry, perms) != 0) {
368 0 : return -1;
369 : }
370 :
371 145 : return 0;
372 : }
373 :
374 29 : static SMB_ACL_T make_simple_acl(TALLOC_CTX *mem_ctx,
375 : gid_t gid,
376 : mode_t chmod_mode)
377 : {
378 29 : mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE;
379 :
380 29 : mode_t mode_user = (chmod_mode & 0700) >> 6;
381 29 : mode_t mode_group = (chmod_mode & 070) >> 3;
382 29 : mode_t mode_other = chmod_mode & 07;
383 : SMB_ACL_ENTRY_T entry;
384 29 : SMB_ACL_T acl = sys_acl_init(mem_ctx);
385 :
386 29 : if (!acl) {
387 0 : return NULL;
388 : }
389 :
390 29 : if (sys_acl_create_entry(&acl, &entry) != 0) {
391 0 : TALLOC_FREE(acl);
392 0 : return NULL;
393 : }
394 :
395 29 : if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
396 0 : TALLOC_FREE(acl);
397 0 : return NULL;
398 : }
399 :
400 29 : if (set_acl_entry_perms(entry, mode_user) != 0) {
401 0 : TALLOC_FREE(acl);
402 0 : return NULL;
403 : }
404 :
405 29 : if (sys_acl_create_entry(&acl, &entry) != 0) {
406 0 : TALLOC_FREE(acl);
407 0 : return NULL;
408 : }
409 :
410 29 : if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
411 0 : TALLOC_FREE(acl);
412 0 : return NULL;
413 : }
414 :
415 29 : if (set_acl_entry_perms(entry, mode_group) != 0) {
416 0 : TALLOC_FREE(acl);
417 0 : return NULL;
418 : }
419 :
420 29 : if (sys_acl_create_entry(&acl, &entry) != 0) {
421 0 : TALLOC_FREE(acl);
422 0 : return NULL;
423 : }
424 :
425 29 : if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
426 0 : TALLOC_FREE(acl);
427 0 : return NULL;
428 : }
429 :
430 29 : if (set_acl_entry_perms(entry, mode_other) != 0) {
431 0 : TALLOC_FREE(acl);
432 0 : return NULL;
433 : }
434 :
435 29 : if (gid != -1) {
436 29 : if (sys_acl_create_entry(&acl, &entry) != 0) {
437 0 : TALLOC_FREE(acl);
438 0 : return NULL;
439 : }
440 :
441 29 : if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
442 0 : TALLOC_FREE(acl);
443 0 : return NULL;
444 : }
445 :
446 29 : if (sys_acl_set_qualifier(entry, &gid) != 0) {
447 0 : TALLOC_FREE(acl);
448 0 : return NULL;
449 : }
450 :
451 29 : if (set_acl_entry_perms(entry, mode_group) != 0) {
452 0 : TALLOC_FREE(acl);
453 0 : return NULL;
454 : }
455 : }
456 :
457 29 : if (sys_acl_create_entry(&acl, &entry) != 0) {
458 0 : TALLOC_FREE(acl);
459 0 : return NULL;
460 : }
461 :
462 29 : if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
463 0 : TALLOC_FREE(acl);
464 0 : return NULL;
465 : }
466 :
467 29 : if (set_acl_entry_perms(entry, mode) != 0) {
468 0 : TALLOC_FREE(acl);
469 0 : return NULL;
470 : }
471 :
472 29 : return acl;
473 : }
474 :
475 : /*
476 : set a simple ACL on a file, as a test
477 : */
478 29 : static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args, PyObject *kwargs)
479 : {
480 29 : const char * const kwnames[] = {
481 : "fname",
482 : "mode",
483 : "session_info",
484 : "gid",
485 : "service",
486 : NULL
487 : };
488 29 : char *fname, *service = NULL;
489 29 : PyObject *py_session = Py_None;
490 29 : struct auth_session_info *session_info = NULL;
491 : int ret;
492 29 : int mode, gid = -1;
493 : SMB_ACL_T acl;
494 : TALLOC_CTX *frame;
495 : connection_struct *conn;
496 :
497 29 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|iz",
498 : discard_const_p(char *, kwnames),
499 : &fname,
500 : &mode,
501 : &py_session,
502 : &gid,
503 : &service))
504 0 : return NULL;
505 :
506 29 : if (!py_check_dcerpc_type(py_session,
507 : "samba.dcerpc.auth",
508 : "session_info")) {
509 0 : return NULL;
510 : }
511 29 : session_info = pytalloc_get_type(py_session,
512 : struct auth_session_info);
513 29 : if (session_info == NULL) {
514 0 : PyErr_Format(PyExc_TypeError,
515 : "Expected auth_session_info for session_info argument got %s",
516 : pytalloc_get_name(py_session));
517 0 : return NULL;
518 : }
519 :
520 29 : frame = talloc_stackframe();
521 :
522 29 : acl = make_simple_acl(frame, gid, mode);
523 29 : if (acl == NULL) {
524 0 : TALLOC_FREE(frame);
525 0 : return NULL;
526 : }
527 :
528 29 : conn = get_conn_tos(service, session_info);
529 29 : if (!conn) {
530 0 : TALLOC_FREE(frame);
531 0 : return NULL;
532 : }
533 :
534 29 : ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn);
535 :
536 29 : if (ret != 0) {
537 0 : TALLOC_FREE(frame);
538 0 : errno = ret;
539 0 : return PyErr_SetFromErrno(PyExc_OSError);
540 : }
541 :
542 29 : TALLOC_FREE(frame);
543 :
544 29 : Py_RETURN_NONE;
545 : }
546 :
547 : /*
548 : chown a file
549 : */
550 29 : static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs)
551 : {
552 29 : const char * const kwnames[] = {
553 : "fname",
554 : "uid",
555 : "gid",
556 : "session_info",
557 : "service",
558 : NULL
559 : };
560 : connection_struct *conn;
561 : int ret;
562 : NTSTATUS status;
563 29 : char *fname, *service = NULL;
564 29 : PyObject *py_session = Py_None;
565 29 : struct auth_session_info *session_info = NULL;
566 : int uid, gid;
567 : TALLOC_CTX *frame;
568 29 : struct files_struct *fsp = NULL;
569 :
570 29 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siiO|z",
571 : discard_const_p(char *, kwnames),
572 : &fname,
573 : &uid,
574 : &gid,
575 : &py_session,
576 : &service))
577 0 : return NULL;
578 :
579 29 : if (!py_check_dcerpc_type(py_session,
580 : "samba.dcerpc.auth",
581 : "session_info")) {
582 0 : return NULL;
583 : }
584 29 : session_info = pytalloc_get_type(py_session,
585 : struct auth_session_info);
586 29 : if (session_info == NULL) {
587 0 : PyErr_Format(PyExc_TypeError,
588 : "Expected auth_session_info for session_info argument got %s",
589 : pytalloc_get_name(py_session));
590 0 : return NULL;
591 : }
592 :
593 29 : frame = talloc_stackframe();
594 :
595 29 : conn = get_conn_tos(service, session_info);
596 29 : if (!conn) {
597 0 : TALLOC_FREE(frame);
598 0 : return NULL;
599 : }
600 :
601 : /* first, try to open it as a file with flag O_RDWR */
602 29 : status = init_files_struct(frame,
603 : fname,
604 : conn,
605 : O_RDWR,
606 : &fsp);
607 29 : if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
608 : /* if fail, try to open as dir */
609 0 : status = init_files_struct(frame,
610 : fname,
611 : conn,
612 : DIRECTORY_FLAGS,
613 : &fsp);
614 : }
615 :
616 29 : if (!NT_STATUS_IS_OK(status)) {
617 0 : DBG_ERR("init_files_struct failed: %s\n",
618 : nt_errstr(status));
619 0 : if (fsp != NULL) {
620 0 : fd_close(fsp);
621 : }
622 0 : TALLOC_FREE(frame);
623 : /*
624 : * The following macro raises a python
625 : * error then returns NULL.
626 : */
627 0 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
628 : }
629 :
630 29 : ret = SMB_VFS_FCHOWN(fsp, uid, gid);
631 29 : if (ret != 0) {
632 0 : int saved_errno = errno;
633 0 : fd_close(fsp);
634 0 : TALLOC_FREE(frame);
635 0 : errno = saved_errno;
636 0 : return PyErr_SetFromErrno(PyExc_OSError);
637 : }
638 :
639 29 : fd_close(fsp);
640 29 : TALLOC_FREE(frame);
641 :
642 29 : Py_RETURN_NONE;
643 : }
644 :
645 : /*
646 : unlink a file
647 : */
648 1 : static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
649 : {
650 1 : const char * const kwnames[] = {
651 : "fname",
652 : "session_info",
653 : "service",
654 : NULL
655 : };
656 : connection_struct *conn;
657 : int ret;
658 1 : struct smb_filename *smb_fname = NULL;
659 1 : struct smb_filename *parent_fname = NULL;
660 1 : struct smb_filename *at_fname = NULL;
661 1 : PyObject *py_session = Py_None;
662 1 : struct auth_session_info *session_info = NULL;
663 1 : char *fname, *service = NULL;
664 : TALLOC_CTX *frame;
665 : NTSTATUS status;
666 :
667 1 : frame = talloc_stackframe();
668 :
669 1 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|z",
670 : discard_const_p(char *, kwnames),
671 : &fname,
672 : &py_session ,
673 : &service)) {
674 0 : TALLOC_FREE(frame);
675 0 : return NULL;
676 : }
677 :
678 1 : if (!py_check_dcerpc_type(py_session,
679 : "samba.dcerpc.auth",
680 : "session_info")) {
681 0 : TALLOC_FREE(frame);
682 0 : return NULL;
683 : }
684 1 : session_info = pytalloc_get_type(py_session,
685 : struct auth_session_info);
686 1 : if (session_info == NULL) {
687 0 : PyErr_Format(PyExc_TypeError,
688 : "Expected auth_session_info for session_info argument got %s",
689 : pytalloc_get_name(py_session));
690 0 : TALLOC_FREE(frame);
691 0 : return NULL;
692 : }
693 :
694 1 : conn = get_conn_tos(service, session_info);
695 1 : if (!conn) {
696 0 : TALLOC_FREE(frame);
697 0 : return NULL;
698 : }
699 :
700 1 : smb_fname = synthetic_smb_fname_split(frame,
701 : fname,
702 1 : lp_posix_pathnames());
703 1 : if (smb_fname == NULL) {
704 0 : TALLOC_FREE(frame);
705 0 : return PyErr_NoMemory();
706 : }
707 :
708 1 : status = parent_pathref(frame,
709 : conn->cwd_fsp,
710 : smb_fname,
711 : &parent_fname,
712 : &at_fname);
713 1 : if (!NT_STATUS_IS_OK(status)) {
714 0 : TALLOC_FREE(frame);
715 0 : return PyErr_NoMemory();
716 : }
717 :
718 1 : ret = SMB_VFS_UNLINKAT(conn,
719 : parent_fname->fsp,
720 : at_fname,
721 : 0);
722 1 : if (ret != 0) {
723 0 : TALLOC_FREE(frame);
724 0 : errno = ret;
725 0 : return PyErr_SetFromErrno(PyExc_OSError);
726 : }
727 :
728 1 : TALLOC_FREE(frame);
729 :
730 1 : Py_RETURN_NONE;
731 : }
732 :
733 : /*
734 : check if we have ACL support
735 : */
736 0 : static PyObject *py_smbd_have_posix_acls(PyObject *self,
737 : PyObject *Py_UNUSED(ignored))
738 : {
739 : #ifdef HAVE_POSIX_ACLS
740 0 : return PyBool_FromLong(true);
741 : #else
742 : return PyBool_FromLong(false);
743 : #endif
744 : }
745 :
746 : /*
747 : set the NT ACL on a file
748 : */
749 929 : static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
750 : {
751 929 : const char * const kwnames[] = {
752 : "fname",
753 : "security_info_sent",
754 : "sd",
755 : "session_info",
756 : "service",
757 : NULL
758 : };
759 :
760 : NTSTATUS status;
761 929 : char *fname, *service = NULL;
762 : int security_info_sent;
763 : PyObject *py_sd;
764 : struct security_descriptor *sd;
765 929 : PyObject *py_session = Py_None;
766 929 : struct auth_session_info *session_info = NULL;
767 : connection_struct *conn;
768 : TALLOC_CTX *frame;
769 :
770 929 : frame = talloc_stackframe();
771 :
772 929 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siOO|z",
773 : discard_const_p(char *, kwnames),
774 : &fname,
775 : &security_info_sent,
776 : &py_sd,
777 : &py_session,
778 : &service)) {
779 0 : TALLOC_FREE(frame);
780 0 : return NULL;
781 : }
782 :
783 929 : if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
784 0 : TALLOC_FREE(frame);
785 0 : return NULL;
786 : }
787 :
788 929 : if (!py_check_dcerpc_type(py_session,
789 : "samba.dcerpc.auth",
790 : "session_info")) {
791 0 : TALLOC_FREE(frame);
792 0 : return NULL;
793 : }
794 929 : session_info = pytalloc_get_type(py_session,
795 : struct auth_session_info);
796 929 : if (session_info == NULL) {
797 0 : PyErr_Format(PyExc_TypeError,
798 : "Expected auth_session_info for session_info argument got %s",
799 : pytalloc_get_name(py_session));
800 0 : return NULL;
801 : }
802 :
803 929 : conn = get_conn_tos(service, session_info);
804 929 : if (!conn) {
805 0 : TALLOC_FREE(frame);
806 0 : return NULL;
807 : }
808 :
809 929 : sd = pytalloc_get_type(py_sd, struct security_descriptor);
810 :
811 929 : status = set_nt_acl_conn(fname, security_info_sent, sd, conn);
812 929 : TALLOC_FREE(frame);
813 929 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
814 :
815 929 : Py_RETURN_NONE;
816 : }
817 :
818 : /*
819 : Return the NT ACL on a file
820 : */
821 110 : static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
822 : {
823 110 : const char * const kwnames[] = {
824 : "fname",
825 : "security_info_wanted",
826 : "session_info",
827 : "service",
828 : NULL
829 : };
830 110 : char *fname, *service = NULL;
831 : int security_info_wanted;
832 : PyObject *py_sd;
833 : struct security_descriptor *sd;
834 110 : TALLOC_CTX *frame = talloc_stackframe();
835 110 : PyObject *py_session = Py_None;
836 110 : struct auth_session_info *session_info = NULL;
837 : connection_struct *conn;
838 : NTSTATUS status;
839 110 : int ret = 1;
840 :
841 110 : ret = PyArg_ParseTupleAndKeywords(args,
842 : kwargs,
843 : "siO|z",
844 : discard_const_p(char *, kwnames),
845 : &fname,
846 : &security_info_wanted,
847 : &py_session,
848 : &service);
849 110 : if (!ret) {
850 0 : TALLOC_FREE(frame);
851 0 : return NULL;
852 : }
853 :
854 110 : if (!py_check_dcerpc_type(py_session,
855 : "samba.dcerpc.auth",
856 : "session_info")) {
857 0 : TALLOC_FREE(frame);
858 0 : return NULL;
859 : }
860 110 : session_info = pytalloc_get_type(py_session,
861 : struct auth_session_info);
862 110 : if (session_info == NULL) {
863 0 : PyErr_Format(
864 : PyExc_TypeError,
865 : "Expected auth_session_info for "
866 : "session_info argument got %s",
867 : pytalloc_get_name(py_session));
868 0 : return NULL;
869 : }
870 :
871 110 : conn = get_conn_tos(service, session_info);
872 110 : if (!conn) {
873 0 : TALLOC_FREE(frame);
874 0 : return NULL;
875 : }
876 :
877 110 : status = get_nt_acl_conn(frame, fname, conn, security_info_wanted, &sd);
878 110 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
879 :
880 110 : py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
881 :
882 110 : TALLOC_FREE(frame);
883 :
884 110 : return py_sd;
885 : }
886 :
887 : /*
888 : set the posix (or similar) ACL on a file
889 : */
890 0 : static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
891 : {
892 0 : const char * const kwnames[] = {
893 : "fname",
894 : "acl_type",
895 : "acl",
896 : "session_info",
897 : "service",
898 : NULL
899 : };
900 0 : TALLOC_CTX *frame = talloc_stackframe();
901 : int ret;
902 0 : char *fname, *service = NULL;
903 : PyObject *py_acl;
904 0 : PyObject *py_session = Py_None;
905 0 : struct auth_session_info *session_info = NULL;
906 : struct smb_acl_t *acl;
907 : int acl_type;
908 : connection_struct *conn;
909 :
910 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siOO|z",
911 : discard_const_p(char *, kwnames),
912 : &fname,
913 : &acl_type,
914 : &py_acl,
915 : &py_session,
916 : &service)) {
917 0 : TALLOC_FREE(frame);
918 0 : return NULL;
919 : }
920 :
921 0 : if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
922 0 : TALLOC_FREE(frame);
923 0 : return NULL;
924 : }
925 :
926 0 : if (!py_check_dcerpc_type(py_session,
927 : "samba.dcerpc.auth",
928 : "session_info")) {
929 0 : TALLOC_FREE(frame);
930 0 : return NULL;
931 : }
932 0 : session_info = pytalloc_get_type(py_session,
933 : struct auth_session_info);
934 0 : if (session_info == NULL) {
935 0 : PyErr_Format(PyExc_TypeError,
936 : "Expected auth_session_info for session_info argument got %s",
937 : pytalloc_get_name(py_session));
938 0 : TALLOC_FREE(frame);
939 0 : return NULL;
940 : }
941 :
942 0 : conn = get_conn_tos(service, session_info);
943 0 : if (!conn) {
944 0 : TALLOC_FREE(frame);
945 0 : return NULL;
946 : }
947 :
948 0 : acl = pytalloc_get_type(py_acl, struct smb_acl_t);
949 :
950 0 : ret = set_sys_acl_conn(fname, acl_type, acl, conn);
951 0 : if (ret != 0) {
952 0 : TALLOC_FREE(frame);
953 0 : errno = ret;
954 0 : return PyErr_SetFromErrno(PyExc_OSError);
955 : }
956 :
957 0 : TALLOC_FREE(frame);
958 0 : Py_RETURN_NONE;
959 : }
960 :
961 : /*
962 : Return the posix (or similar) ACL on a file
963 : */
964 0 : static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
965 : {
966 0 : const char * const kwnames[] = {
967 : "fname",
968 : "acl_type",
969 : "session_info",
970 : "service",
971 : NULL
972 : };
973 : char *fname;
974 : PyObject *py_acl;
975 0 : PyObject *py_session = Py_None;
976 0 : struct auth_session_info *session_info = NULL;
977 : struct smb_acl_t *acl;
978 : int acl_type;
979 0 : TALLOC_CTX *frame = talloc_stackframe();
980 : connection_struct *conn;
981 0 : char *service = NULL;
982 0 : struct smb_filename *smb_fname = NULL;
983 : NTSTATUS status;
984 :
985 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|z",
986 : discard_const_p(char *, kwnames),
987 : &fname,
988 : &acl_type,
989 : &py_session,
990 : &service)) {
991 0 : TALLOC_FREE(frame);
992 0 : return NULL;
993 : }
994 :
995 0 : if (!py_check_dcerpc_type(py_session,
996 : "samba.dcerpc.auth",
997 : "session_info")) {
998 0 : TALLOC_FREE(frame);
999 0 : return NULL;
1000 : }
1001 0 : session_info = pytalloc_get_type(py_session,
1002 : struct auth_session_info);
1003 0 : if (session_info == NULL) {
1004 0 : PyErr_Format(PyExc_TypeError,
1005 : "Expected auth_session_info for session_info argument got %s",
1006 : pytalloc_get_name(py_session));
1007 0 : TALLOC_FREE(frame);
1008 0 : return NULL;
1009 : }
1010 :
1011 0 : conn = get_conn_tos(service, session_info);
1012 0 : if (!conn) {
1013 0 : TALLOC_FREE(frame);
1014 0 : return NULL;
1015 : }
1016 :
1017 0 : smb_fname = synthetic_smb_fname_split(frame,
1018 : fname,
1019 0 : lp_posix_pathnames());
1020 0 : if (smb_fname == NULL) {
1021 0 : TALLOC_FREE(frame);
1022 0 : return NULL;
1023 : }
1024 :
1025 0 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
1026 0 : if (!NT_STATUS_IS_OK(status)) {
1027 0 : TALLOC_FREE(frame);
1028 0 : PyErr_SetNTSTATUS(status);
1029 0 : return NULL;
1030 : }
1031 :
1032 0 : acl = SMB_VFS_SYS_ACL_GET_FD(smb_fname->fsp, acl_type, frame);
1033 0 : if (!acl) {
1034 0 : TALLOC_FREE(frame);
1035 0 : return PyErr_SetFromErrno(PyExc_OSError);
1036 : }
1037 :
1038 0 : status = fd_close(smb_fname->fsp);
1039 0 : if (!NT_STATUS_IS_OK(status)) {
1040 0 : TALLOC_FREE(frame);
1041 0 : PyErr_SetNTSTATUS(status);
1042 0 : return NULL;
1043 : }
1044 :
1045 0 : py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
1046 :
1047 0 : TALLOC_FREE(frame);
1048 :
1049 0 : return py_acl;
1050 : }
1051 :
1052 340 : static PyObject *py_smbd_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
1053 : {
1054 340 : const char * const kwnames[] = {
1055 : "fname",
1056 : "session_info",
1057 : "service",
1058 : NULL
1059 : };
1060 340 : char *fname, *service = NULL;
1061 340 : PyObject *py_session = Py_None;
1062 340 : struct auth_session_info *session_info = NULL;
1063 340 : TALLOC_CTX *frame = talloc_stackframe();
1064 340 : struct connection_struct *conn = NULL;
1065 340 : struct smb_filename *smb_fname = NULL;
1066 340 : struct smb_filename *parent_fname = NULL;
1067 340 : struct smb_filename *base_name = NULL;
1068 : NTSTATUS status;
1069 : int ret;
1070 : mode_t saved_umask;
1071 :
1072 340 : if (!PyArg_ParseTupleAndKeywords(args,
1073 : kwargs,
1074 : "sO|z",
1075 : discard_const_p(char *,
1076 : kwnames),
1077 : &fname,
1078 : &py_session,
1079 : &service)) {
1080 0 : TALLOC_FREE(frame);
1081 0 : return NULL;
1082 : }
1083 :
1084 340 : if (!py_check_dcerpc_type(py_session,
1085 : "samba.dcerpc.auth",
1086 : "session_info")) {
1087 0 : TALLOC_FREE(frame);
1088 0 : return NULL;
1089 : }
1090 340 : session_info = pytalloc_get_type(py_session,
1091 : struct auth_session_info);
1092 340 : if (session_info == NULL) {
1093 0 : PyErr_Format(PyExc_TypeError,
1094 : "Expected auth_session_info for session_info argument got %s",
1095 : pytalloc_get_name(py_session));
1096 0 : TALLOC_FREE(frame);
1097 0 : return NULL;
1098 : }
1099 :
1100 340 : conn = get_conn_tos(service, session_info);
1101 340 : if (!conn) {
1102 0 : TALLOC_FREE(frame);
1103 0 : return NULL;
1104 : }
1105 :
1106 340 : smb_fname = synthetic_smb_fname(talloc_tos(),
1107 : fname,
1108 : NULL,
1109 : NULL,
1110 : 0,
1111 340 : lp_posix_pathnames() ?
1112 : SMB_FILENAME_POSIX_PATH : 0);
1113 :
1114 340 : if (smb_fname == NULL) {
1115 0 : TALLOC_FREE(frame);
1116 0 : return NULL;
1117 : }
1118 :
1119 340 : status = parent_pathref(talloc_tos(),
1120 : conn->cwd_fsp,
1121 : smb_fname,
1122 : &parent_fname,
1123 : &base_name);
1124 340 : if (!NT_STATUS_IS_OK(status)) {
1125 0 : TALLOC_FREE(frame);
1126 0 : return NULL;
1127 : }
1128 :
1129 : /* we want total control over the permissions on created files,
1130 : so set our umask to 0 */
1131 340 : saved_umask = umask(0);
1132 :
1133 340 : ret = SMB_VFS_MKDIRAT(conn,
1134 : parent_fname->fsp,
1135 : base_name,
1136 : 00755);
1137 :
1138 340 : umask(saved_umask);
1139 :
1140 340 : if (ret == -1) {
1141 0 : DBG_ERR("mkdirat error=%d (%s)\n", errno, strerror(errno));
1142 0 : TALLOC_FREE(frame);
1143 0 : return NULL;
1144 : }
1145 :
1146 340 : TALLOC_FREE(frame);
1147 340 : Py_RETURN_NONE;
1148 : }
1149 :
1150 :
1151 : /*
1152 : Create an empty file
1153 : */
1154 81 : static PyObject *py_smbd_create_file(PyObject *self, PyObject *args, PyObject *kwargs)
1155 : {
1156 81 : const char * const kwnames[] = {
1157 : "fname",
1158 : "session_info",
1159 : "service",
1160 : NULL
1161 : };
1162 81 : char *fname, *service = NULL;
1163 81 : PyObject *py_session = Py_None;
1164 81 : struct auth_session_info *session_info = NULL;
1165 81 : TALLOC_CTX *frame = talloc_stackframe();
1166 81 : struct connection_struct *conn = NULL;
1167 81 : struct files_struct *fsp = NULL;
1168 : NTSTATUS status;
1169 :
1170 81 : if (!PyArg_ParseTupleAndKeywords(args,
1171 : kwargs,
1172 : "sO|z",
1173 : discard_const_p(char *,
1174 : kwnames),
1175 : &fname,
1176 : &py_session,
1177 : &service)) {
1178 0 : TALLOC_FREE(frame);
1179 0 : return NULL;
1180 : }
1181 :
1182 81 : if (!py_check_dcerpc_type(py_session,
1183 : "samba.dcerpc.auth",
1184 : "session_info")) {
1185 0 : TALLOC_FREE(frame);
1186 0 : return NULL;
1187 : }
1188 81 : session_info = pytalloc_get_type(py_session,
1189 : struct auth_session_info);
1190 81 : if (session_info == NULL) {
1191 0 : PyErr_Format(PyExc_TypeError,
1192 : "Expected auth_session_info for session_info argument got %s",
1193 : pytalloc_get_name(py_session));
1194 0 : TALLOC_FREE(frame);
1195 0 : return NULL;
1196 : }
1197 :
1198 81 : conn = get_conn_tos(service, session_info);
1199 81 : if (!conn) {
1200 0 : TALLOC_FREE(frame);
1201 0 : return NULL;
1202 : }
1203 :
1204 81 : status = init_files_struct(frame,
1205 : fname,
1206 : conn,
1207 : O_CREAT|O_EXCL|O_RDWR,
1208 : &fsp);
1209 81 : if (!NT_STATUS_IS_OK(status)) {
1210 0 : DBG_ERR("init_files_struct failed: %s\n",
1211 : nt_errstr(status));
1212 81 : } else if (fsp != NULL) {
1213 81 : fd_close(fsp);
1214 : }
1215 :
1216 81 : TALLOC_FREE(frame);
1217 81 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1218 81 : Py_RETURN_NONE;
1219 : }
1220 :
1221 :
1222 : static PyMethodDef py_smbd_methods[] = {
1223 : { "have_posix_acls",
1224 : (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS,
1225 : NULL },
1226 : { "set_simple_acl",
1227 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_acl),
1228 : METH_VARARGS|METH_KEYWORDS,
1229 : NULL },
1230 : { "set_nt_acl",
1231 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_nt_acl),
1232 : METH_VARARGS|METH_KEYWORDS,
1233 : NULL },
1234 : { "get_nt_acl",
1235 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_nt_acl),
1236 : METH_VARARGS|METH_KEYWORDS,
1237 : NULL },
1238 : { "get_sys_acl",
1239 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_sys_acl),
1240 : METH_VARARGS|METH_KEYWORDS,
1241 : NULL },
1242 : { "set_sys_acl",
1243 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_sys_acl),
1244 : METH_VARARGS|METH_KEYWORDS,
1245 : NULL },
1246 : { "chown",
1247 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_chown),
1248 : METH_VARARGS|METH_KEYWORDS,
1249 : NULL },
1250 : { "unlink",
1251 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_unlink),
1252 : METH_VARARGS|METH_KEYWORDS,
1253 : NULL },
1254 : { "mkdir",
1255 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_mkdir),
1256 : METH_VARARGS|METH_KEYWORDS,
1257 : NULL },
1258 : { "create_file",
1259 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_create_file),
1260 : METH_VARARGS|METH_KEYWORDS,
1261 : NULL },
1262 : {0}
1263 : };
1264 :
1265 : void initsmbd(void);
1266 :
1267 : static struct PyModuleDef moduledef = {
1268 : PyModuleDef_HEAD_INIT,
1269 : .m_name = "smbd",
1270 : .m_doc = "Python bindings for the smbd file server.",
1271 : .m_size = -1,
1272 : .m_methods = py_smbd_methods,
1273 : };
1274 :
1275 1184 : MODULE_INIT_FUNC(smbd)
1276 : {
1277 1184 : PyObject *m = NULL;
1278 :
1279 1184 : m = PyModule_Create(&moduledef);
1280 1184 : return m;
1281 : }
|