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 "lib/replace/system/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 3822 : static connection_struct *get_conn_tos(
53 : const char *service,
54 : const struct auth_session_info *session_info)
55 : {
56 3822 : struct conn_struct_tos *c = NULL;
57 3822 : int snum = -1;
58 115 : NTSTATUS status;
59 3822 : char *cwd = NULL;
60 3822 : struct smb_filename cwd_fname = {0};
61 115 : int ret;
62 :
63 3822 : if (!posix_locking_init(false)) {
64 0 : PyErr_NoMemory();
65 0 : return NULL;
66 : }
67 :
68 3822 : if (service) {
69 2522 : snum = lp_servicenumber(service);
70 2522 : 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 3822 : if (session_info->unix_info == NULL) {
81 0 : PyErr_SetString(PyExc_RuntimeError,
82 : "Session unix info not initialized");
83 0 : return NULL;
84 : }
85 3822 : 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 3822 : status = create_conn_struct_tos(NULL,
92 : snum,
93 : "/",
94 : session_info,
95 : &c);
96 3822 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
97 :
98 : /* Ignore read-only and share restrictions */
99 3822 : c->conn->read_only = false;
100 3822 : c->conn->share_access = SEC_RIGHTS_FILE_ALL;
101 :
102 : /* Provided by libreplace if not present. Always mallocs. */
103 3822 : cwd = get_current_dir_name();
104 3822 : if (cwd == NULL) {
105 0 : PyErr_NoMemory();
106 0 : return NULL;
107 : }
108 :
109 3822 : 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 3822 : ret = vfs_ChDir(c->conn, &cwd_fname);
116 3822 : 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 3822 : SAFE_FREE(cwd);
123 :
124 3822 : return c->conn;
125 : }
126 :
127 186 : 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 5 : int ret;
132 186 : struct smb_filename *smb_fname = NULL;
133 186 : TALLOC_CTX *frame = talloc_stackframe();
134 5 : NTSTATUS status;
135 :
136 186 : smb_fname = synthetic_smb_fname_split(frame,
137 : fname,
138 186 : lp_posix_pathnames());
139 186 : if (smb_fname == NULL) {
140 0 : TALLOC_FREE(frame);
141 0 : return -1;
142 : }
143 :
144 186 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
145 186 : 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 186 : ret = SMB_VFS_SYS_ACL_SET_FD(smb_fname->fsp, acltype, theacl);
152 :
153 186 : status = fd_close(smb_fname->fsp);
154 186 : 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 186 : TALLOC_FREE(frame);
161 181 : return ret;
162 : }
163 :
164 :
165 3667 : 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 3667 : struct vfs_open_how how = { .flags = flags, .mode = 0644 };
172 3667 : struct smb_filename *smb_fname = NULL;
173 195 : int fd;
174 195 : mode_t saved_umask;
175 195 : struct files_struct *fsp;
176 3667 : struct files_struct *fspcwd = NULL;
177 195 : NTSTATUS status;
178 :
179 3667 : fsp = talloc_zero(mem_ctx, struct files_struct);
180 3667 : if (fsp == NULL) {
181 0 : return NT_STATUS_NO_MEMORY;
182 : }
183 3667 : fsp->fh = fd_handle_create(fsp);
184 3667 : if (fsp->fh == NULL) {
185 0 : return NT_STATUS_NO_MEMORY;
186 : }
187 3667 : fsp->conn = conn;
188 :
189 3667 : smb_fname = synthetic_smb_fname_split(fsp,
190 : fname,
191 3667 : lp_posix_pathnames());
192 3667 : if (smb_fname == NULL) {
193 0 : return NT_STATUS_NO_MEMORY;
194 : }
195 :
196 3667 : fsp->fsp_name = smb_fname;
197 :
198 3667 : status = vfs_at_fspcwd(fsp, conn, &fspcwd);
199 3667 : 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 3667 : saved_umask = umask(0);
208 :
209 3667 : fd = SMB_VFS_OPENAT(conn,
210 : fspcwd,
211 : smb_fname,
212 : fsp,
213 : &how);
214 :
215 3667 : umask(saved_umask);
216 :
217 3667 : if (fd == -1) {
218 1490 : int err = errno;
219 1490 : if (err == ENOENT) {
220 4 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
221 : }
222 1486 : return NT_STATUS_INVALID_PARAMETER;
223 : }
224 2177 : fsp_set_fd(fsp, fd);
225 :
226 2177 : status = vfs_stat_fsp(fsp);
227 2177 : 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 2177 : fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
236 2177 : fsp->vuid = UID_FIELD_INVALID;
237 2177 : fsp->file_pid = 0;
238 2177 : fsp->fsp_flags.can_lock = true;
239 2177 : fsp->fsp_flags.can_read = true;
240 2177 : fsp->fsp_flags.can_write = true;
241 2177 : fsp->print_file = NULL;
242 2177 : fsp->fsp_flags.modified = false;
243 2177 : fsp->sent_oplock_break = NO_BREAK_SENT;
244 2177 : fsp->fsp_flags.is_directory = S_ISDIR(smb_fname->st.st_ex_mode);
245 :
246 2177 : *_fsp = fsp;
247 :
248 2177 : return NT_STATUS_OK;
249 : }
250 :
251 1968 : 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 1968 : TALLOC_CTX *frame = talloc_stackframe();
256 1968 : struct files_struct *fsp = NULL;
257 1968 : NTSTATUS status = NT_STATUS_OK;
258 :
259 : /* first, try to open it as a file with flag O_RDWR */
260 1968 : status = init_files_struct(frame,
261 : fname,
262 : conn,
263 : O_RDWR,
264 : &fsp);
265 1968 : if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
266 : /* if fail, try to open as dir */
267 1474 : status = init_files_struct(frame,
268 : fname,
269 : conn,
270 : DIRECTORY_FLAGS,
271 : &fsp);
272 : }
273 :
274 1968 : if (!NT_STATUS_IS_OK(status)) {
275 4 : DBG_ERR("init_files_struct failed: %s\n",
276 : nt_errstr(status));
277 4 : if (fsp != NULL) {
278 0 : fd_close(fsp);
279 : }
280 4 : TALLOC_FREE(frame);
281 4 : return status;
282 : }
283 :
284 1964 : status = SMB_VFS_FSET_NT_ACL(metadata_fsp(fsp), security_info_sent, sd);
285 1964 : if (!NT_STATUS_IS_OK(status)) {
286 0 : DEBUG(0,("set_nt_acl_conn: fset_nt_acl returned %s.\n", nt_errstr(status)));
287 : }
288 :
289 1964 : fd_close(fsp);
290 :
291 1964 : TALLOC_FREE(frame);
292 1964 : return status;
293 : }
294 :
295 530 : 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 530 : TALLOC_CTX *frame = talloc_stackframe();
302 0 : NTSTATUS status;
303 530 : struct smb_filename *smb_fname = NULL;
304 :
305 530 : smb_fname = synthetic_smb_fname_split(frame,
306 : fname,
307 530 : lp_posix_pathnames());
308 :
309 530 : if (smb_fname == NULL) {
310 0 : TALLOC_FREE(frame);
311 0 : return NT_STATUS_NO_MEMORY;
312 : }
313 :
314 530 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
315 530 : if (!NT_STATUS_IS_OK(status)) {
316 0 : TALLOC_FREE(frame);
317 0 : return status;
318 : }
319 :
320 530 : status = SMB_VFS_FGET_NT_ACL(metadata_fsp(smb_fname->fsp),
321 : security_info_wanted,
322 : mem_ctx,
323 : sd);
324 530 : if (!NT_STATUS_IS_OK(status)) {
325 0 : DBG_ERR("fget_nt_acl_at returned %s.\n",
326 : nt_errstr(status));
327 : }
328 :
329 530 : status = fd_close(smb_fname->fsp);
330 530 : if (!NT_STATUS_IS_OK(status)) {
331 0 : TALLOC_FREE(frame);
332 0 : return status;
333 : }
334 :
335 530 : TALLOC_FREE(frame);
336 :
337 530 : return status;
338 : }
339 :
340 846 : static int set_acl_entry_perms(SMB_ACL_ENTRY_T entry, mode_t perm_mask)
341 : {
342 846 : SMB_ACL_PERMSET_T perms = NULL;
343 :
344 846 : if (sys_acl_get_permset(entry, &perms) != 0) {
345 0 : return -1;
346 : }
347 :
348 846 : if (sys_acl_clear_perms(perms) != 0) {
349 0 : return -1;
350 : }
351 :
352 1572 : if ((perm_mask & SMB_ACL_READ) != 0 &&
353 726 : sys_acl_add_perm(perms, SMB_ACL_READ) != 0) {
354 0 : return -1;
355 : }
356 :
357 1242 : if ((perm_mask & SMB_ACL_WRITE) != 0 &&
358 396 : sys_acl_add_perm(perms, SMB_ACL_WRITE) != 0) {
359 0 : return -1;
360 : }
361 :
362 1392 : if ((perm_mask & SMB_ACL_EXECUTE) != 0 &&
363 546 : sys_acl_add_perm(perms, SMB_ACL_EXECUTE) != 0) {
364 0 : return -1;
365 : }
366 :
367 846 : if (sys_acl_set_permset(entry, perms) != 0) {
368 0 : return -1;
369 : }
370 :
371 821 : return 0;
372 : }
373 :
374 186 : static SMB_ACL_T make_simple_acl(TALLOC_CTX *mem_ctx,
375 : gid_t gid,
376 : mode_t chmod_mode)
377 : {
378 186 : mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE;
379 :
380 186 : mode_t mode_user = (chmod_mode & 0700) >> 6;
381 186 : mode_t mode_group = (chmod_mode & 070) >> 3;
382 186 : mode_t mode_other = chmod_mode & 07;
383 5 : SMB_ACL_ENTRY_T entry;
384 186 : SMB_ACL_T acl = sys_acl_init(mem_ctx);
385 :
386 186 : if (!acl) {
387 0 : return NULL;
388 : }
389 :
390 186 : if (sys_acl_create_entry(&acl, &entry) != 0) {
391 0 : TALLOC_FREE(acl);
392 0 : return NULL;
393 : }
394 :
395 186 : if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
396 0 : TALLOC_FREE(acl);
397 0 : return NULL;
398 : }
399 :
400 186 : if (set_acl_entry_perms(entry, mode_user) != 0) {
401 0 : TALLOC_FREE(acl);
402 0 : return NULL;
403 : }
404 :
405 186 : if (sys_acl_create_entry(&acl, &entry) != 0) {
406 0 : TALLOC_FREE(acl);
407 0 : return NULL;
408 : }
409 :
410 186 : if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
411 0 : TALLOC_FREE(acl);
412 0 : return NULL;
413 : }
414 :
415 186 : if (set_acl_entry_perms(entry, mode_group) != 0) {
416 0 : TALLOC_FREE(acl);
417 0 : return NULL;
418 : }
419 :
420 186 : if (sys_acl_create_entry(&acl, &entry) != 0) {
421 0 : TALLOC_FREE(acl);
422 0 : return NULL;
423 : }
424 :
425 186 : if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
426 0 : TALLOC_FREE(acl);
427 0 : return NULL;
428 : }
429 :
430 186 : if (set_acl_entry_perms(entry, mode_other) != 0) {
431 0 : TALLOC_FREE(acl);
432 0 : return NULL;
433 : }
434 :
435 186 : if (gid != -1) {
436 102 : if (sys_acl_create_entry(&acl, &entry) != 0) {
437 0 : TALLOC_FREE(acl);
438 0 : return NULL;
439 : }
440 :
441 102 : if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
442 0 : TALLOC_FREE(acl);
443 0 : return NULL;
444 : }
445 :
446 102 : if (sys_acl_set_qualifier(entry, &gid) != 0) {
447 0 : TALLOC_FREE(acl);
448 0 : return NULL;
449 : }
450 :
451 102 : if (set_acl_entry_perms(entry, mode_group) != 0) {
452 0 : TALLOC_FREE(acl);
453 0 : return NULL;
454 : }
455 : }
456 :
457 186 : if (sys_acl_create_entry(&acl, &entry) != 0) {
458 0 : TALLOC_FREE(acl);
459 0 : return NULL;
460 : }
461 :
462 186 : if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
463 0 : TALLOC_FREE(acl);
464 0 : return NULL;
465 : }
466 :
467 186 : if (set_acl_entry_perms(entry, mode) != 0) {
468 0 : TALLOC_FREE(acl);
469 0 : return NULL;
470 : }
471 :
472 186 : return acl;
473 : }
474 :
475 : /*
476 : set a simple ACL on a file, as a test
477 : */
478 186 : static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args, PyObject *kwargs)
479 : {
480 186 : const char * const kwnames[] = {
481 : "fname",
482 : "mode",
483 : "session_info",
484 : "gid",
485 : "service",
486 : NULL
487 : };
488 186 : char *fname, *service = NULL;
489 186 : PyObject *py_session = Py_None;
490 186 : struct auth_session_info *session_info = NULL;
491 5 : int ret;
492 186 : int mode, gid = -1;
493 5 : SMB_ACL_T acl;
494 5 : TALLOC_CTX *frame;
495 5 : connection_struct *conn;
496 :
497 186 : 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 186 : if (!py_check_dcerpc_type(py_session,
507 : "samba.dcerpc.auth",
508 : "session_info")) {
509 0 : return NULL;
510 : }
511 186 : session_info = pytalloc_get_type(py_session,
512 : struct auth_session_info);
513 186 : 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 186 : frame = talloc_stackframe();
521 :
522 186 : acl = make_simple_acl(frame, gid, mode);
523 186 : if (acl == NULL) {
524 0 : TALLOC_FREE(frame);
525 0 : return NULL;
526 : }
527 :
528 186 : conn = get_conn_tos(service, session_info);
529 186 : if (!conn) {
530 0 : TALLOC_FREE(frame);
531 0 : return NULL;
532 : }
533 :
534 186 : ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn);
535 :
536 186 : if (ret != 0) {
537 0 : TALLOC_FREE(frame);
538 0 : errno = ret;
539 0 : return PyErr_SetFromErrno(PyExc_OSError);
540 : }
541 :
542 186 : TALLOC_FREE(frame);
543 :
544 186 : Py_RETURN_NONE;
545 : }
546 :
547 : /*
548 : chown a file
549 : */
550 78 : static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs)
551 : {
552 78 : const char * const kwnames[] = {
553 : "fname",
554 : "uid",
555 : "gid",
556 : "session_info",
557 : "service",
558 : NULL
559 : };
560 5 : connection_struct *conn;
561 5 : int ret;
562 5 : NTSTATUS status;
563 78 : char *fname, *service = NULL;
564 78 : PyObject *py_session = Py_None;
565 78 : struct auth_session_info *session_info = NULL;
566 5 : int uid, gid;
567 5 : TALLOC_CTX *frame;
568 78 : struct files_struct *fsp = NULL;
569 :
570 78 : 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 78 : if (!py_check_dcerpc_type(py_session,
580 : "samba.dcerpc.auth",
581 : "session_info")) {
582 0 : return NULL;
583 : }
584 78 : session_info = pytalloc_get_type(py_session,
585 : struct auth_session_info);
586 78 : 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 78 : frame = talloc_stackframe();
594 :
595 78 : conn = get_conn_tos(service, session_info);
596 78 : 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 78 : status = init_files_struct(frame,
603 : fname,
604 : conn,
605 : O_RDWR,
606 : &fsp);
607 78 : if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
608 : /* if fail, try to open as dir */
609 12 : status = init_files_struct(frame,
610 : fname,
611 : conn,
612 : DIRECTORY_FLAGS,
613 : &fsp);
614 : }
615 :
616 78 : 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 78 : ret = SMB_VFS_FCHOWN(fsp, uid, gid);
631 78 : 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 78 : fd_close(fsp);
640 78 : TALLOC_FREE(frame);
641 :
642 78 : Py_RETURN_NONE;
643 : }
644 :
645 : /*
646 : unlink a file
647 : */
648 279 : static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
649 : {
650 279 : const char * const kwnames[] = {
651 : "fname",
652 : "session_info",
653 : "service",
654 : NULL
655 : };
656 0 : connection_struct *conn;
657 0 : int ret;
658 279 : struct smb_filename *smb_fname = NULL;
659 279 : struct smb_filename *parent_fname = NULL;
660 279 : struct smb_filename *at_fname = NULL;
661 279 : PyObject *py_session = Py_None;
662 279 : struct auth_session_info *session_info = NULL;
663 279 : char *fname, *service = NULL;
664 0 : TALLOC_CTX *frame;
665 0 : NTSTATUS status;
666 :
667 279 : frame = talloc_stackframe();
668 :
669 279 : 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 279 : 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 279 : session_info = pytalloc_get_type(py_session,
685 : struct auth_session_info);
686 279 : 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 279 : conn = get_conn_tos(service, session_info);
695 279 : if (!conn) {
696 0 : TALLOC_FREE(frame);
697 0 : return NULL;
698 : }
699 :
700 279 : smb_fname = synthetic_smb_fname_split(frame,
701 : fname,
702 279 : lp_posix_pathnames());
703 279 : if (smb_fname == NULL) {
704 0 : TALLOC_FREE(frame);
705 0 : return PyErr_NoMemory();
706 : }
707 :
708 279 : status = parent_pathref(frame,
709 : conn->cwd_fsp,
710 : smb_fname,
711 : &parent_fname,
712 : &at_fname);
713 279 : if (!NT_STATUS_IS_OK(status)) {
714 0 : TALLOC_FREE(frame);
715 0 : return PyErr_NoMemory();
716 : }
717 :
718 279 : ret = SMB_VFS_UNLINKAT(conn,
719 : parent_fname->fsp,
720 : at_fname,
721 : 0);
722 279 : if (ret != 0) {
723 0 : TALLOC_FREE(frame);
724 0 : errno = ret;
725 0 : return PyErr_SetFromErrno(PyExc_OSError);
726 : }
727 :
728 279 : TALLOC_FREE(frame);
729 :
730 279 : 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 1968 : static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
750 : {
751 1968 : const char * const kwnames[] = {
752 : "fname",
753 : "security_info_sent",
754 : "sd",
755 : "session_info",
756 : "service",
757 : NULL
758 : };
759 :
760 105 : NTSTATUS status;
761 1968 : char *fname, *service = NULL;
762 105 : int security_info_sent;
763 105 : PyObject *py_sd;
764 105 : struct security_descriptor *sd;
765 1968 : PyObject *py_session = Py_None;
766 1968 : struct auth_session_info *session_info = NULL;
767 105 : connection_struct *conn;
768 105 : TALLOC_CTX *frame;
769 :
770 1968 : frame = talloc_stackframe();
771 :
772 1968 : 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 1968 : if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
784 0 : TALLOC_FREE(frame);
785 0 : return NULL;
786 : }
787 :
788 1968 : 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 1968 : session_info = pytalloc_get_type(py_session,
795 : struct auth_session_info);
796 1968 : 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 1968 : conn = get_conn_tos(service, session_info);
804 1968 : if (!conn) {
805 0 : TALLOC_FREE(frame);
806 0 : return NULL;
807 : }
808 :
809 1968 : sd = pytalloc_get_type(py_sd, struct security_descriptor);
810 :
811 1968 : status = set_nt_acl_conn(fname, security_info_sent, sd, conn);
812 1968 : TALLOC_FREE(frame);
813 1968 : if (NT_STATUS_IS_ERR(status)) {
814 4 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
815 : /*
816 : * This will show up as a FileNotFoundError in python.
817 : */
818 4 : PyErr_SetFromErrnoWithFilename(PyExc_OSError, fname);
819 : } else {
820 0 : PyErr_SetNTSTATUS(status);
821 : }
822 4 : return NULL;
823 : }
824 :
825 1964 : Py_RETURN_NONE;
826 : }
827 :
828 : /*
829 : Return the NT ACL on a file
830 : */
831 530 : static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
832 : {
833 530 : const char * const kwnames[] = {
834 : "fname",
835 : "security_info_wanted",
836 : "session_info",
837 : "service",
838 : NULL
839 : };
840 530 : char *fname, *service = NULL;
841 0 : int security_info_wanted;
842 0 : PyObject *py_sd;
843 0 : struct security_descriptor *sd;
844 530 : TALLOC_CTX *frame = talloc_stackframe();
845 530 : PyObject *py_session = Py_None;
846 530 : struct auth_session_info *session_info = NULL;
847 0 : connection_struct *conn;
848 0 : NTSTATUS status;
849 530 : int ret = 1;
850 :
851 530 : ret = PyArg_ParseTupleAndKeywords(args,
852 : kwargs,
853 : "siO|z",
854 : discard_const_p(char *, kwnames),
855 : &fname,
856 : &security_info_wanted,
857 : &py_session,
858 : &service);
859 530 : if (!ret) {
860 0 : TALLOC_FREE(frame);
861 0 : return NULL;
862 : }
863 :
864 530 : if (!py_check_dcerpc_type(py_session,
865 : "samba.dcerpc.auth",
866 : "session_info")) {
867 0 : TALLOC_FREE(frame);
868 0 : return NULL;
869 : }
870 530 : session_info = pytalloc_get_type(py_session,
871 : struct auth_session_info);
872 530 : if (session_info == NULL) {
873 0 : PyErr_Format(
874 : PyExc_TypeError,
875 : "Expected auth_session_info for "
876 : "session_info argument got %s",
877 : pytalloc_get_name(py_session));
878 0 : TALLOC_FREE(frame);
879 0 : return NULL;
880 : }
881 :
882 530 : conn = get_conn_tos(service, session_info);
883 530 : if (!conn) {
884 0 : TALLOC_FREE(frame);
885 0 : return NULL;
886 : }
887 :
888 530 : status = get_nt_acl_conn(frame, fname, conn, security_info_wanted, &sd);
889 530 : if (NT_STATUS_IS_ERR(status)) {
890 0 : if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
891 : /*
892 : * This will show up as a FileNotFoundError in python,
893 : * from which samba-tool can at least produce a short
894 : * message containing the problematic filename.
895 : */
896 0 : PyErr_SetFromErrnoWithFilename(PyExc_OSError, fname);
897 : } else {
898 0 : PyErr_SetNTSTATUS(status);
899 : }
900 0 : TALLOC_FREE(frame);
901 0 : return NULL;
902 : }
903 :
904 530 : py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
905 :
906 530 : TALLOC_FREE(frame);
907 :
908 530 : return py_sd;
909 : }
910 :
911 : /*
912 : set the posix (or similar) ACL on a file
913 : */
914 0 : static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
915 : {
916 0 : const char * const kwnames[] = {
917 : "fname",
918 : "acl_type",
919 : "acl",
920 : "session_info",
921 : "service",
922 : NULL
923 : };
924 0 : TALLOC_CTX *frame = talloc_stackframe();
925 0 : int ret;
926 0 : char *fname, *service = NULL;
927 0 : PyObject *py_acl;
928 0 : PyObject *py_session = Py_None;
929 0 : struct auth_session_info *session_info = NULL;
930 0 : struct smb_acl_t *acl;
931 0 : int acl_type;
932 0 : connection_struct *conn;
933 :
934 0 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siOO|z",
935 : discard_const_p(char *, kwnames),
936 : &fname,
937 : &acl_type,
938 : &py_acl,
939 : &py_session,
940 : &service)) {
941 0 : TALLOC_FREE(frame);
942 0 : return NULL;
943 : }
944 :
945 0 : if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
946 0 : TALLOC_FREE(frame);
947 0 : return NULL;
948 : }
949 :
950 0 : if (!py_check_dcerpc_type(py_session,
951 : "samba.dcerpc.auth",
952 : "session_info")) {
953 0 : TALLOC_FREE(frame);
954 0 : return NULL;
955 : }
956 0 : session_info = pytalloc_get_type(py_session,
957 : struct auth_session_info);
958 0 : if (session_info == NULL) {
959 0 : PyErr_Format(PyExc_TypeError,
960 : "Expected auth_session_info for session_info argument got %s",
961 : pytalloc_get_name(py_session));
962 0 : TALLOC_FREE(frame);
963 0 : return NULL;
964 : }
965 :
966 0 : conn = get_conn_tos(service, session_info);
967 0 : if (!conn) {
968 0 : TALLOC_FREE(frame);
969 0 : return NULL;
970 : }
971 :
972 0 : acl = pytalloc_get_type(py_acl, struct smb_acl_t);
973 :
974 0 : ret = set_sys_acl_conn(fname, acl_type, acl, conn);
975 0 : if (ret != 0) {
976 0 : TALLOC_FREE(frame);
977 0 : errno = ret;
978 0 : return PyErr_SetFromErrno(PyExc_OSError);
979 : }
980 :
981 0 : TALLOC_FREE(frame);
982 0 : Py_RETURN_NONE;
983 : }
984 :
985 : /*
986 : Return the posix (or similar) ACL on a file
987 : */
988 96 : static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
989 : {
990 96 : const char * const kwnames[] = {
991 : "fname",
992 : "acl_type",
993 : "session_info",
994 : "service",
995 : NULL
996 : };
997 0 : char *fname;
998 0 : PyObject *py_acl;
999 96 : PyObject *py_session = Py_None;
1000 96 : struct auth_session_info *session_info = NULL;
1001 0 : struct smb_acl_t *acl;
1002 0 : int acl_type;
1003 96 : TALLOC_CTX *frame = talloc_stackframe();
1004 0 : connection_struct *conn;
1005 96 : char *service = NULL;
1006 96 : struct smb_filename *smb_fname = NULL;
1007 0 : NTSTATUS status;
1008 :
1009 96 : if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|z",
1010 : discard_const_p(char *, kwnames),
1011 : &fname,
1012 : &acl_type,
1013 : &py_session,
1014 : &service)) {
1015 0 : TALLOC_FREE(frame);
1016 0 : return NULL;
1017 : }
1018 :
1019 96 : if (!py_check_dcerpc_type(py_session,
1020 : "samba.dcerpc.auth",
1021 : "session_info")) {
1022 0 : TALLOC_FREE(frame);
1023 0 : return NULL;
1024 : }
1025 96 : session_info = pytalloc_get_type(py_session,
1026 : struct auth_session_info);
1027 96 : if (session_info == NULL) {
1028 0 : PyErr_Format(PyExc_TypeError,
1029 : "Expected auth_session_info for session_info argument got %s",
1030 : pytalloc_get_name(py_session));
1031 0 : TALLOC_FREE(frame);
1032 0 : return NULL;
1033 : }
1034 :
1035 96 : conn = get_conn_tos(service, session_info);
1036 96 : if (!conn) {
1037 0 : TALLOC_FREE(frame);
1038 0 : return NULL;
1039 : }
1040 :
1041 96 : smb_fname = synthetic_smb_fname_split(frame,
1042 : fname,
1043 96 : lp_posix_pathnames());
1044 96 : if (smb_fname == NULL) {
1045 0 : TALLOC_FREE(frame);
1046 0 : return NULL;
1047 : }
1048 :
1049 96 : status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
1050 96 : if (!NT_STATUS_IS_OK(status)) {
1051 0 : TALLOC_FREE(frame);
1052 0 : PyErr_SetNTSTATUS(status);
1053 0 : return NULL;
1054 : }
1055 :
1056 96 : acl = SMB_VFS_SYS_ACL_GET_FD(smb_fname->fsp, acl_type, frame);
1057 96 : if (!acl) {
1058 0 : TALLOC_FREE(frame);
1059 0 : return PyErr_SetFromErrno(PyExc_OSError);
1060 : }
1061 :
1062 96 : status = fd_close(smb_fname->fsp);
1063 96 : if (!NT_STATUS_IS_OK(status)) {
1064 0 : TALLOC_FREE(frame);
1065 0 : PyErr_SetNTSTATUS(status);
1066 0 : return NULL;
1067 : }
1068 :
1069 96 : py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
1070 :
1071 96 : TALLOC_FREE(frame);
1072 :
1073 96 : return py_acl;
1074 : }
1075 :
1076 550 : static PyObject *py_smbd_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
1077 : {
1078 550 : const char * const kwnames[] = {
1079 : "fname",
1080 : "session_info",
1081 : "service",
1082 : NULL
1083 : };
1084 550 : char *fname, *service = NULL;
1085 550 : PyObject *py_session = Py_None;
1086 550 : struct auth_session_info *session_info = NULL;
1087 550 : TALLOC_CTX *frame = talloc_stackframe();
1088 550 : struct connection_struct *conn = NULL;
1089 550 : struct smb_filename *smb_fname = NULL;
1090 550 : struct smb_filename *parent_fname = NULL;
1091 550 : struct smb_filename *base_name = NULL;
1092 0 : NTSTATUS status;
1093 0 : int ret;
1094 0 : mode_t saved_umask;
1095 :
1096 550 : if (!PyArg_ParseTupleAndKeywords(args,
1097 : kwargs,
1098 : "sO|z",
1099 : discard_const_p(char *,
1100 : kwnames),
1101 : &fname,
1102 : &py_session,
1103 : &service)) {
1104 0 : TALLOC_FREE(frame);
1105 0 : return NULL;
1106 : }
1107 :
1108 550 : if (!py_check_dcerpc_type(py_session,
1109 : "samba.dcerpc.auth",
1110 : "session_info")) {
1111 0 : TALLOC_FREE(frame);
1112 0 : return NULL;
1113 : }
1114 550 : session_info = pytalloc_get_type(py_session,
1115 : struct auth_session_info);
1116 550 : if (session_info == NULL) {
1117 0 : PyErr_Format(PyExc_TypeError,
1118 : "Expected auth_session_info for session_info argument got %s",
1119 : pytalloc_get_name(py_session));
1120 0 : TALLOC_FREE(frame);
1121 0 : return NULL;
1122 : }
1123 :
1124 550 : conn = get_conn_tos(service, session_info);
1125 550 : if (!conn) {
1126 0 : TALLOC_FREE(frame);
1127 0 : return NULL;
1128 : }
1129 :
1130 550 : smb_fname = synthetic_smb_fname(talloc_tos(),
1131 : fname,
1132 : NULL,
1133 : NULL,
1134 : 0,
1135 550 : lp_posix_pathnames() ?
1136 : SMB_FILENAME_POSIX_PATH : 0);
1137 :
1138 550 : if (smb_fname == NULL) {
1139 0 : TALLOC_FREE(frame);
1140 0 : return NULL;
1141 : }
1142 :
1143 550 : status = parent_pathref(talloc_tos(),
1144 : conn->cwd_fsp,
1145 : smb_fname,
1146 : &parent_fname,
1147 : &base_name);
1148 550 : if (!NT_STATUS_IS_OK(status)) {
1149 0 : TALLOC_FREE(frame);
1150 0 : return NULL;
1151 : }
1152 :
1153 : /* we want total control over the permissions on created files,
1154 : so set our umask to 0 */
1155 550 : saved_umask = umask(0);
1156 :
1157 550 : ret = SMB_VFS_MKDIRAT(conn,
1158 : parent_fname->fsp,
1159 : base_name,
1160 : 00755);
1161 :
1162 550 : umask(saved_umask);
1163 :
1164 550 : if (ret == -1) {
1165 0 : DBG_ERR("mkdirat error=%d (%s)\n", errno, strerror(errno));
1166 0 : TALLOC_FREE(frame);
1167 0 : return NULL;
1168 : }
1169 :
1170 550 : TALLOC_FREE(frame);
1171 550 : Py_RETURN_NONE;
1172 : }
1173 :
1174 :
1175 : /*
1176 : Create an empty file
1177 : */
1178 135 : static PyObject *py_smbd_create_file(PyObject *self, PyObject *args, PyObject *kwargs)
1179 : {
1180 135 : const char * const kwnames[] = {
1181 : "fname",
1182 : "session_info",
1183 : "service",
1184 : NULL
1185 : };
1186 135 : char *fname, *service = NULL;
1187 135 : PyObject *py_session = Py_None;
1188 135 : struct auth_session_info *session_info = NULL;
1189 135 : TALLOC_CTX *frame = talloc_stackframe();
1190 135 : struct connection_struct *conn = NULL;
1191 135 : struct files_struct *fsp = NULL;
1192 0 : NTSTATUS status;
1193 :
1194 135 : if (!PyArg_ParseTupleAndKeywords(args,
1195 : kwargs,
1196 : "sO|z",
1197 : discard_const_p(char *,
1198 : kwnames),
1199 : &fname,
1200 : &py_session,
1201 : &service)) {
1202 0 : TALLOC_FREE(frame);
1203 0 : return NULL;
1204 : }
1205 :
1206 135 : if (!py_check_dcerpc_type(py_session,
1207 : "samba.dcerpc.auth",
1208 : "session_info")) {
1209 0 : TALLOC_FREE(frame);
1210 0 : return NULL;
1211 : }
1212 135 : session_info = pytalloc_get_type(py_session,
1213 : struct auth_session_info);
1214 135 : if (session_info == NULL) {
1215 0 : PyErr_Format(PyExc_TypeError,
1216 : "Expected auth_session_info for session_info argument got %s",
1217 : pytalloc_get_name(py_session));
1218 0 : TALLOC_FREE(frame);
1219 0 : return NULL;
1220 : }
1221 :
1222 135 : conn = get_conn_tos(service, session_info);
1223 135 : if (!conn) {
1224 0 : TALLOC_FREE(frame);
1225 0 : return NULL;
1226 : }
1227 :
1228 135 : status = init_files_struct(frame,
1229 : fname,
1230 : conn,
1231 : O_CREAT|O_EXCL|O_RDWR,
1232 : &fsp);
1233 135 : if (!NT_STATUS_IS_OK(status)) {
1234 0 : DBG_ERR("init_files_struct failed: %s\n",
1235 : nt_errstr(status));
1236 135 : } else if (fsp != NULL) {
1237 135 : fd_close(fsp);
1238 : }
1239 :
1240 135 : TALLOC_FREE(frame);
1241 135 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
1242 135 : Py_RETURN_NONE;
1243 : }
1244 :
1245 :
1246 : static PyMethodDef py_smbd_methods[] = {
1247 : { "have_posix_acls",
1248 : (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS,
1249 : NULL },
1250 : { "set_simple_acl",
1251 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_acl),
1252 : METH_VARARGS|METH_KEYWORDS,
1253 : NULL },
1254 : { "set_nt_acl",
1255 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_nt_acl),
1256 : METH_VARARGS|METH_KEYWORDS,
1257 : NULL },
1258 : { "get_nt_acl",
1259 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_nt_acl),
1260 : METH_VARARGS|METH_KEYWORDS,
1261 : NULL },
1262 : { "get_sys_acl",
1263 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_sys_acl),
1264 : METH_VARARGS|METH_KEYWORDS,
1265 : NULL },
1266 : { "set_sys_acl",
1267 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_sys_acl),
1268 : METH_VARARGS|METH_KEYWORDS,
1269 : NULL },
1270 : { "chown",
1271 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_chown),
1272 : METH_VARARGS|METH_KEYWORDS,
1273 : NULL },
1274 : { "unlink",
1275 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_unlink),
1276 : METH_VARARGS|METH_KEYWORDS,
1277 : NULL },
1278 : { "mkdir",
1279 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_mkdir),
1280 : METH_VARARGS|METH_KEYWORDS,
1281 : NULL },
1282 : { "create_file",
1283 : PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_create_file),
1284 : METH_VARARGS|METH_KEYWORDS,
1285 : NULL },
1286 : {0}
1287 : };
1288 :
1289 : void initsmbd(void);
1290 :
1291 : static struct PyModuleDef moduledef = {
1292 : PyModuleDef_HEAD_INIT,
1293 : .m_name = "smbd",
1294 : .m_doc = "Python bindings for the smbd file server.",
1295 : .m_size = -1,
1296 : .m_methods = py_smbd_methods,
1297 : };
1298 :
1299 1731 : MODULE_INIT_FUNC(smbd)
1300 : {
1301 1731 : PyObject *m = NULL;
1302 :
1303 1731 : m = PyModule_Create(&moduledef);
1304 1731 : return m;
1305 : }
|