2 Unix SMB/CIFS implementation.
3 Set NT and POSIX ACLs and other VFS operations from Python
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
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.
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.
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/>.
28 #include "python/py3compat.h"
29 #include "smbd/smbd.h"
30 #include "libcli/util/pyerrors.h"
31 #include "librpc/rpc/pyrpc_util.h"
33 #include "system/filesys.h"
35 extern const struct generic_mapping file_generic_mapping
;
38 #define DBGC_CLASS DBGC_ACLS
40 static int conn_free_wrapper(connection_struct
*conn
)
46 static connection_struct
*get_conn(TALLOC_CTX
*mem_ctx
, const char *service
)
48 connection_struct
*conn
;
49 TALLOC_CTX
*frame
= talloc_stackframe();
53 if (!posix_locking_init(false)) {
60 snum
= lp_servicenumber(service
);
63 PyErr_SetString(PyExc_RuntimeError
, "unknown service");
68 status
= create_conn_struct(mem_ctx
, NULL
, NULL
, &conn
, snum
, "/",
70 PyErr_NTSTATUS_IS_ERR_RAISE(status
);
73 /* Ignore read-only and share restrictions */
74 conn
->read_only
= false;
75 conn
->share_access
= SEC_RIGHTS_FILE_ALL
;
76 talloc_set_destructor(conn
, conn_free_wrapper
);
80 static int set_sys_acl_conn(const char *fname
,
81 SMB_ACL_TYPE_T acltype
,
82 SMB_ACL_T theacl
, connection_struct
*conn
)
85 struct smb_filename
*smb_fname
= NULL
;
88 TALLOC_CTX
*frame
= talloc_stackframe();
90 /* we want total control over the permissions on created files,
91 so set our umask to 0 */
92 saved_umask
= umask(0);
94 smb_fname
= synthetic_smb_fname_split(frame
,
96 lp_posix_pathnames());
97 if (smb_fname
== NULL
) {
103 ret
= SMB_VFS_SYS_ACL_SET_FILE( conn
, smb_fname
, acltype
, theacl
);
111 static NTSTATUS
set_nt_acl_conn(const char *fname
,
112 uint32_t security_info_sent
, const struct security_descriptor
*sd
,
113 connection_struct
*conn
)
115 TALLOC_CTX
*frame
= talloc_stackframe();
116 NTSTATUS status
= NT_STATUS_OK
;
118 struct smb_filename
*smb_fname
= NULL
;
122 fsp
= talloc_zero(frame
, struct files_struct
);
125 return NT_STATUS_NO_MEMORY
;
127 fsp
->fh
= talloc(fsp
, struct fd_handle
);
128 if (fsp
->fh
== NULL
) {
130 return NT_STATUS_NO_MEMORY
;
134 /* we want total control over the permissions on created files,
135 so set our umask to 0 */
136 saved_umask
= umask(0);
138 smb_fname
= synthetic_smb_fname_split(fsp
,
140 lp_posix_pathnames());
141 if (smb_fname
== NULL
) {
144 return NT_STATUS_NO_MEMORY
;
147 fsp
->fsp_name
= smb_fname
;
150 flags
= O_RDONLY
|O_DIRECTORY
;
152 /* POSIX allows us to open a directory with O_RDONLY. */
156 fsp
->fh
->fd
= SMB_VFS_OPEN(conn
, smb_fname
, fsp
, O_RDWR
, 00400);
157 if (fsp
->fh
->fd
== -1 && errno
== EISDIR
) {
158 fsp
->fh
->fd
= SMB_VFS_OPEN(conn
, smb_fname
, fsp
, flags
, 00400);
160 if (fsp
->fh
->fd
== -1) {
161 printf("open: error=%d (%s)\n", errno
, strerror(errno
));
164 return NT_STATUS_UNSUCCESSFUL
;
167 ret
= SMB_VFS_FSTAT(fsp
, &smb_fname
->st
);
169 /* If we have an fd, this stat should succeed. */
170 DEBUG(0,("Error doing fstat on open file %s "
172 smb_fname_str_dbg(smb_fname
),
176 return map_nt_error_from_unix(errno
);
179 fsp
->file_id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
180 fsp
->vuid
= UID_FIELD_INVALID
;
182 fsp
->can_lock
= True
;
183 fsp
->can_read
= True
;
184 fsp
->can_write
= True
;
185 fsp
->print_file
= NULL
;
186 fsp
->modified
= False
;
187 fsp
->sent_oplock_break
= NO_BREAK_SENT
;
188 fsp
->is_directory
= S_ISDIR(smb_fname
->st
.st_ex_mode
);
190 status
= SMB_VFS_FSET_NT_ACL( fsp
, security_info_sent
, sd
);
191 if (!NT_STATUS_IS_OK(status
)) {
192 DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned %s.\n", nt_errstr(status
)));
204 static NTSTATUS
get_nt_acl_conn(TALLOC_CTX
*mem_ctx
,
206 connection_struct
*conn
,
207 uint32_t security_info_wanted
,
208 struct security_descriptor
**sd
)
210 TALLOC_CTX
*frame
= talloc_stackframe();
212 struct smb_filename
*smb_fname
= synthetic_smb_fname(talloc_tos(),
216 lp_posix_pathnames() ?
217 SMB_FILENAME_POSIX_PATH
: 0);
219 if (smb_fname
== NULL
) {
221 return NT_STATUS_NO_MEMORY
;
224 status
= SMB_VFS_GET_NT_ACL(conn
,
226 security_info_wanted
,
229 if (!NT_STATUS_IS_OK(status
)) {
230 DEBUG(0,("get_nt_acl_conn: get_nt_acl returned %s.\n", nt_errstr(status
)));
238 static int set_acl_entry_perms(SMB_ACL_ENTRY_T entry
, mode_t perm_mask
)
240 SMB_ACL_PERMSET_T perms
= NULL
;
242 if (sys_acl_get_permset(entry
, &perms
) != 0) {
246 if (sys_acl_clear_perms(perms
) != 0) {
250 if ((perm_mask
& SMB_ACL_READ
) != 0 &&
251 sys_acl_add_perm(perms
, SMB_ACL_READ
) != 0) {
255 if ((perm_mask
& SMB_ACL_WRITE
) != 0 &&
256 sys_acl_add_perm(perms
, SMB_ACL_WRITE
) != 0) {
260 if ((perm_mask
& SMB_ACL_EXECUTE
) != 0 &&
261 sys_acl_add_perm(perms
, SMB_ACL_EXECUTE
) != 0) {
265 if (sys_acl_set_permset(entry
, perms
) != 0) {
272 static SMB_ACL_T
make_simple_acl(gid_t gid
, mode_t chmod_mode
)
274 TALLOC_CTX
*frame
= talloc_stackframe();
276 mode_t mode
= SMB_ACL_READ
|SMB_ACL_WRITE
|SMB_ACL_EXECUTE
;
278 mode_t mode_user
= (chmod_mode
& 0700) >> 6;
279 mode_t mode_group
= (chmod_mode
& 070) >> 3;
280 mode_t mode_other
= chmod_mode
& 07;
281 SMB_ACL_ENTRY_T entry
;
282 SMB_ACL_T acl
= sys_acl_init(frame
);
288 if (sys_acl_create_entry(&acl
, &entry
) != 0) {
293 if (sys_acl_set_tag_type(entry
, SMB_ACL_USER_OBJ
) != 0) {
298 if (set_acl_entry_perms(entry
, mode_user
) != 0) {
303 if (sys_acl_create_entry(&acl
, &entry
) != 0) {
308 if (sys_acl_set_tag_type(entry
, SMB_ACL_GROUP_OBJ
) != 0) {
313 if (set_acl_entry_perms(entry
, mode_group
) != 0) {
318 if (sys_acl_create_entry(&acl
, &entry
) != 0) {
323 if (sys_acl_set_tag_type(entry
, SMB_ACL_OTHER
) != 0) {
328 if (set_acl_entry_perms(entry
, mode_other
) != 0) {
334 if (sys_acl_create_entry(&acl
, &entry
) != 0) {
339 if (sys_acl_set_tag_type(entry
, SMB_ACL_GROUP
) != 0) {
344 if (sys_acl_set_qualifier(entry
, &gid
) != 0) {
349 if (set_acl_entry_perms(entry
, mode_group
) != 0) {
355 if (sys_acl_create_entry(&acl
, &entry
) != 0) {
360 if (sys_acl_set_tag_type(entry
, SMB_ACL_MASK
) != 0) {
365 if (set_acl_entry_perms(entry
, mode
) != 0) {
373 set a simple ACL on a file, as a test
375 static PyObject
*py_smbd_set_simple_acl(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
377 const char * const kwnames
[] = { "fname", "mode", "gid", "service", NULL
};
378 char *fname
, *service
= NULL
;
383 connection_struct
*conn
;
385 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "si|iz",
386 discard_const_p(char *, kwnames
),
387 &fname
, &mode
, &gid
, &service
))
390 acl
= make_simple_acl(gid
, mode
);
392 frame
= talloc_stackframe();
394 conn
= get_conn(frame
, service
);
399 ret
= set_sys_acl_conn(fname
, SMB_ACL_TYPE_ACCESS
, acl
, conn
);
405 return PyErr_SetFromErrno(PyExc_OSError
);
416 static PyObject
*py_smbd_chown(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
418 const char * const kwnames
[] = { "fname", "uid", "gid", "service", NULL
};
419 connection_struct
*conn
;
422 char *fname
, *service
= NULL
;
426 struct smb_filename
*smb_fname
= NULL
;
428 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "sii|z",
429 discard_const_p(char *, kwnames
),
430 &fname
, &uid
, &gid
, &service
))
433 frame
= talloc_stackframe();
435 conn
= get_conn(frame
, service
);
440 /* we want total control over the permissions on created files,
441 so set our umask to 0 */
442 saved_umask
= umask(0);
444 smb_fname
= synthetic_smb_fname(talloc_tos(),
448 lp_posix_pathnames() ?
449 SMB_FILENAME_POSIX_PATH
: 0);
450 if (smb_fname
== NULL
) {
454 return PyErr_SetFromErrno(PyExc_OSError
);
457 ret
= SMB_VFS_CHOWN(conn
, smb_fname
, uid
, gid
);
462 return PyErr_SetFromErrno(PyExc_OSError
);
475 static PyObject
*py_smbd_unlink(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
477 const char * const kwnames
[] = { "fname", "service", NULL
};
478 connection_struct
*conn
;
480 struct smb_filename
*smb_fname
= NULL
;
481 char *fname
, *service
= NULL
;
484 frame
= talloc_stackframe();
486 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|z",
487 discard_const_p(char *, kwnames
),
493 conn
= get_conn(frame
, service
);
499 smb_fname
= synthetic_smb_fname_split(frame
,
501 lp_posix_pathnames());
502 if (smb_fname
== NULL
) {
504 return PyErr_NoMemory();
507 ret
= SMB_VFS_UNLINK(conn
, smb_fname
);
511 return PyErr_SetFromErrno(PyExc_OSError
);
520 check if we have ACL support
522 static PyObject
*py_smbd_have_posix_acls(PyObject
*self
)
524 #ifdef HAVE_POSIX_ACLS
525 return PyBool_FromLong(true);
527 return PyBool_FromLong(false);
532 set the NT ACL on a file
534 static PyObject
*py_smbd_set_nt_acl(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
536 const char * const kwnames
[] = { "fname", "security_info_sent", "sd", "service", NULL
};
538 char *fname
, *service
= NULL
;
539 int security_info_sent
;
541 struct security_descriptor
*sd
;
542 connection_struct
*conn
;
545 frame
= talloc_stackframe();
547 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
,
548 "siO|z", discard_const_p(char *, kwnames
),
549 &fname
, &security_info_sent
, &py_sd
, &service
)) {
554 if (!py_check_dcerpc_type(py_sd
, "samba.dcerpc.security", "descriptor")) {
559 conn
= get_conn(frame
, service
);
565 sd
= pytalloc_get_type(py_sd
, struct security_descriptor
);
567 status
= set_nt_acl_conn(fname
, security_info_sent
, sd
, conn
);
569 PyErr_NTSTATUS_IS_ERR_RAISE(status
);
575 Return the NT ACL on a file
577 static PyObject
*py_smbd_get_nt_acl(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
579 const char * const kwnames
[] = { "fname", "security_info_wanted", "service", NULL
};
580 char *fname
, *service
= NULL
;
581 int security_info_wanted
;
583 struct security_descriptor
*sd
;
584 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
585 connection_struct
*conn
;
588 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "si|z", discard_const_p(char *, kwnames
),
589 &fname
, &security_info_wanted
, &service
)) {
590 TALLOC_FREE(tmp_ctx
);
594 conn
= get_conn(tmp_ctx
, service
);
596 TALLOC_FREE(tmp_ctx
);
600 status
= get_nt_acl_conn(tmp_ctx
, fname
, conn
, security_info_wanted
, &sd
);
601 PyErr_NTSTATUS_IS_ERR_RAISE(status
);
603 py_sd
= py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd
, sd
);
605 TALLOC_FREE(tmp_ctx
);
611 set the posix (or similar) ACL on a file
613 static PyObject
*py_smbd_set_sys_acl(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
615 const char * const kwnames
[] = { "fname", "acl_type", "acl", "service", NULL
};
616 TALLOC_CTX
*frame
= talloc_stackframe();
618 char *fname
, *service
= NULL
;
620 struct smb_acl_t
*acl
;
622 connection_struct
*conn
;
624 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "siO|z",
625 discard_const_p(char *, kwnames
),
626 &fname
, &acl_type
, &py_acl
, &service
)) {
631 if (!py_check_dcerpc_type(py_acl
, "samba.dcerpc.smb_acl", "t")) {
636 conn
= get_conn(frame
, service
);
642 acl
= pytalloc_get_type(py_acl
, struct smb_acl_t
);
644 ret
= set_sys_acl_conn(fname
, acl_type
, acl
, conn
);
648 return PyErr_SetFromErrno(PyExc_OSError
);
656 Return the posix (or similar) ACL on a file
658 static PyObject
*py_smbd_get_sys_acl(PyObject
*self
, PyObject
*args
, PyObject
*kwargs
)
660 const char * const kwnames
[] = { "fname", "acl_type", "service", NULL
};
663 struct smb_acl_t
*acl
;
665 TALLOC_CTX
*frame
= talloc_stackframe();
666 TALLOC_CTX
*tmp_ctx
= talloc_new(NULL
);
667 connection_struct
*conn
;
668 char *service
= NULL
;
669 struct smb_filename
*smb_fname
= NULL
;
676 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "si|z",
677 discard_const_p(char *, kwnames
),
678 &fname
, &acl_type
, &service
)) {
680 TALLOC_FREE(tmp_ctx
);
684 conn
= get_conn(frame
, service
);
687 TALLOC_FREE(tmp_ctx
);
691 smb_fname
= synthetic_smb_fname_split(frame
,
693 lp_posix_pathnames());
694 if (smb_fname
== NULL
) {
696 TALLOC_FREE(tmp_ctx
);
699 acl
= SMB_VFS_SYS_ACL_GET_FILE( conn
, smb_fname
, acl_type
, tmp_ctx
);
702 TALLOC_FREE(tmp_ctx
);
703 return PyErr_SetFromErrno(PyExc_OSError
);
706 py_acl
= py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl
, acl
);
709 TALLOC_FREE(tmp_ctx
);
714 static PyMethodDef py_smbd_methods
[] = {
716 (PyCFunction
)py_smbd_have_posix_acls
, METH_NOARGS
,
719 (PyCFunction
)py_smbd_set_simple_acl
, METH_VARARGS
|METH_KEYWORDS
,
722 (PyCFunction
)py_smbd_set_nt_acl
, METH_VARARGS
|METH_KEYWORDS
,
725 (PyCFunction
)py_smbd_get_nt_acl
, METH_VARARGS
|METH_KEYWORDS
,
728 (PyCFunction
)py_smbd_get_sys_acl
, METH_VARARGS
|METH_KEYWORDS
,
731 (PyCFunction
)py_smbd_set_sys_acl
, METH_VARARGS
|METH_KEYWORDS
,
734 (PyCFunction
)py_smbd_chown
, METH_VARARGS
|METH_KEYWORDS
,
737 (PyCFunction
)py_smbd_unlink
, METH_VARARGS
|METH_KEYWORDS
,
744 static struct PyModuleDef moduledef
= {
745 PyModuleDef_HEAD_INIT
,
747 .m_doc
= "Python bindings for the smbd file server.",
749 .m_methods
= py_smbd_methods
,
752 MODULE_INIT_FUNC(smbd
)
756 m
= PyModule_Create(&moduledef
);