2 * Store Windows ACLs in a tdb.
4 * Copyright (C) Volker Lendecke, 2008
5 * Copyright (C) Jeremy Allison, 2008
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/smbd.h"
23 #include "system/filesys.h"
24 #include "librpc/gen_ndr/xattr.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_open.h"
29 #include "vfs_acl_common.h"
32 #define DBGC_CLASS DBGC_VFS
34 #define ACL_MODULE_NAME "acl_tdb"
36 static unsigned int ref_count
;
37 static struct db_context
*acl_db
;
39 /*******************************************************************
40 Open acl_db if not already open, increment ref count.
41 *******************************************************************/
43 static bool acl_tdb_init(void)
52 dbname
= state_path(talloc_tos(), "file_ntacls.tdb");
60 acl_db
= db_open(NULL
, dbname
, 0, TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600,
61 DBWRAP_LOCK_ORDER_1
, DBWRAP_FLAG_NONE
);
79 /*******************************************************************
80 Lower ref count and close acl_db if zero.
81 *******************************************************************/
83 static void disconnect_acl_tdb(struct vfs_handle_struct
*handle
)
85 SMB_VFS_NEXT_DISCONNECT(handle
);
92 /*******************************************************************
93 Delete the tdb acl record for a file
94 *******************************************************************/
96 static NTSTATUS
acl_tdb_delete(vfs_handle_struct
*handle
,
97 struct db_context
*db
,
98 SMB_STRUCT_STAT
*psbuf
)
101 struct file_id id
= vfs_file_id_from_sbuf(handle
->conn
, psbuf
);
104 /* For backwards compatibility only store the dev/inode. */
105 push_file_id_16(id_buf
, &id
);
107 status
= dbwrap_delete(db
, make_tdb_data(id_buf
, sizeof(id_buf
)));
111 /*******************************************************************
112 Pull a security descriptor from an fsp into a DATA_BLOB from a tdb store.
113 *******************************************************************/
115 static NTSTATUS
fget_acl_blob(TALLOC_CTX
*ctx
,
116 vfs_handle_struct
*handle
,
123 struct db_context
*db
= acl_db
;
124 NTSTATUS status
= NT_STATUS_OK
;
126 status
= vfs_stat_fsp(fsp
);
127 if (!NT_STATUS_IS_OK(status
)) {
131 id
= vfs_file_id_from_sbuf(handle
->conn
, &fsp
->fsp_name
->st
);
133 /* For backwards compatibility only store the dev/inode. */
134 push_file_id_16(id_buf
, &id
);
136 status
= dbwrap_fetch(db
,
138 make_tdb_data(id_buf
, sizeof(id_buf
)),
140 if (!NT_STATUS_IS_OK(status
)) {
141 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
144 pblob
->data
= data
.dptr
;
145 pblob
->length
= data
.dsize
;
147 DBG_DEBUG("returned %u bytes from file %s\n",
148 (unsigned int)data
.dsize
,
151 if (pblob
->length
== 0 || pblob
->data
== NULL
) {
152 return NT_STATUS_NOT_FOUND
;
157 /*******************************************************************
158 Store a DATA_BLOB into a tdb record given an fsp pointer.
159 *******************************************************************/
161 static NTSTATUS
store_acl_blob_fsp(vfs_handle_struct
*handle
,
167 TDB_DATA data
= { .dptr
= pblob
->data
, .dsize
= pblob
->length
};
168 struct db_context
*db
= acl_db
;
171 DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
172 (unsigned int)pblob
->length
, fsp_str_dbg(fsp
)));
174 status
= vfs_stat_fsp(fsp
);
175 if (!NT_STATUS_IS_OK(status
)) {
179 id
= vfs_file_id_from_sbuf(handle
->conn
, &fsp
->fsp_name
->st
);
181 /* For backwards compatibility only store the dev/inode. */
182 push_file_id_16(id_buf
, &id
);
184 status
= dbwrap_store(
185 db
, make_tdb_data(id_buf
, sizeof(id_buf
)), data
, 0);
189 /*********************************************************************
190 On unlinkat we need to delete the tdb record (if using tdb).
191 *********************************************************************/
193 static int unlinkat_acl_tdb(vfs_handle_struct
*handle
,
194 struct files_struct
*dirfsp
,
195 const struct smb_filename
*smb_fname
,
198 struct smb_filename
*smb_fname_tmp
= NULL
;
199 struct db_context
*db
= acl_db
;
202 smb_fname_tmp
= cp_smb_filename_nostream(talloc_tos(), smb_fname
);
203 if (smb_fname_tmp
== NULL
) {
208 ret
= vfs_stat(handle
->conn
, smb_fname_tmp
);
213 if (flags
& AT_REMOVEDIR
) {
214 ret
= rmdir_acl_common(handle
,
218 ret
= unlink_acl_common(handle
,
228 acl_tdb_delete(handle
, db
, &smb_fname_tmp
->st
);
233 /*******************************************************************
234 Handle opening the storage tdb if so configured.
235 *******************************************************************/
237 static int connect_acl_tdb(struct vfs_handle_struct
*handle
,
241 int ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
243 struct acl_common_config
*config
= NULL
;
249 if (!acl_tdb_init()) {
250 SMB_VFS_NEXT_DISCONNECT(handle
);
254 ok
= init_acl_common_config(handle
, ACL_MODULE_NAME
);
256 DBG_ERR("init_acl_common_config failed\n");
260 /* Ensure we have the parameters correct if we're
261 * using this module. */
262 DEBUG(2,("connect_acl_tdb: setting 'inherit acls = true' "
263 "'dos filemode = true' and "
264 "'force unknown acl user = true' for service %s\n",
267 lp_do_parameter(SNUM(handle
->conn
), "inherit acls", "true");
268 lp_do_parameter(SNUM(handle
->conn
), "dos filemode", "true");
269 lp_do_parameter(SNUM(handle
->conn
), "force unknown acl user", "true");
271 SMB_VFS_HANDLE_GET_DATA(handle
, config
,
272 struct acl_common_config
,
275 if (config
->ignore_system_acls
) {
276 mode_t create_mask
= lp_create_mask(SNUM(handle
->conn
));
277 char *create_mask_str
= NULL
;
279 if ((create_mask
& 0666) != 0666) {
281 create_mask_str
= talloc_asprintf(handle
, "0%o",
283 if (create_mask_str
== NULL
) {
284 DBG_ERR("talloc_asprintf failed\n");
288 DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str
);
290 lp_do_parameter (SNUM(handle
->conn
),
291 "create mask", create_mask_str
);
293 TALLOC_FREE(create_mask_str
);
296 DBG_NOTICE("setting 'directory mask = 0777', "
297 "'store dos attributes = yes' and all "
298 "'map ...' options to 'no'\n");
300 lp_do_parameter(SNUM(handle
->conn
), "directory mask", "0777");
301 lp_do_parameter(SNUM(handle
->conn
), "map archive", "no");
302 lp_do_parameter(SNUM(handle
->conn
), "map hidden", "no");
303 lp_do_parameter(SNUM(handle
->conn
), "map readonly", "no");
304 lp_do_parameter(SNUM(handle
->conn
), "map system", "no");
305 lp_do_parameter(SNUM(handle
->conn
), "store dos attributes",
312 /*********************************************************************
313 Remove a Windows ACL - we're setting the underlying POSIX ACL.
314 *********************************************************************/
316 static int sys_acl_set_fd_tdb(vfs_handle_struct
*handle
,
321 struct acl_common_fsp_ext
*ext
= (struct acl_common_fsp_ext
*)
322 VFS_FETCH_FSP_EXTENSION(handle
, fsp
);
323 struct db_context
*db
= acl_db
;
327 status
= vfs_stat_fsp(fsp
);
328 if (!NT_STATUS_IS_OK(status
)) {
332 ret
= SMB_VFS_NEXT_SYS_ACL_SET_FD(handle
,
340 if (ext
!= NULL
&& ext
->setting_nt_acl
) {
344 acl_tdb_delete(handle
, db
, &fsp
->fsp_name
->st
);
348 static NTSTATUS
acl_tdb_fget_nt_acl(vfs_handle_struct
*handle
,
350 uint32_t security_info
,
352 struct security_descriptor
**ppdesc
)
355 status
= fget_nt_acl_common(fget_acl_blob
, handle
, fsp
,
356 security_info
, mem_ctx
, ppdesc
);
360 static NTSTATUS
acl_tdb_fset_nt_acl(vfs_handle_struct
*handle
,
362 uint32_t security_info_sent
,
363 const struct security_descriptor
*psd
)
366 status
= fset_nt_acl_common(fget_acl_blob
, store_acl_blob_fsp
,
368 handle
, fsp
, security_info_sent
, psd
);
372 static struct vfs_fn_pointers vfs_acl_tdb_fns
= {
373 .connect_fn
= connect_acl_tdb
,
374 .disconnect_fn
= disconnect_acl_tdb
,
375 .unlinkat_fn
= unlinkat_acl_tdb
,
376 .fchmod_fn
= fchmod_acl_module_common
,
377 .fget_nt_acl_fn
= acl_tdb_fget_nt_acl
,
378 .fset_nt_acl_fn
= acl_tdb_fset_nt_acl
,
379 .sys_acl_set_fd_fn
= sys_acl_set_fd_tdb
383 NTSTATUS
vfs_acl_tdb_init(TALLOC_CTX
*ctx
)
385 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
, "acl_tdb",