Line data Source code
1 : /*
2 : * Store Windows ACLs in a tdb.
3 : *
4 : * Copyright (C) Volker Lendecke, 2008
5 : * Copyright (C) Jeremy Allison, 2008
6 : *
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.
11 : *
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.
16 : *
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/>.
19 : */
20 :
21 : #include "includes.h"
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"
27 : #include "auth.h"
28 : #include "util_tdb.h"
29 : #include "vfs_acl_common.h"
30 :
31 : #undef DBGC_CLASS
32 : #define DBGC_CLASS DBGC_VFS
33 :
34 : #define ACL_MODULE_NAME "acl_tdb"
35 :
36 : static unsigned int ref_count;
37 : static struct db_context *acl_db;
38 :
39 : /*******************************************************************
40 : Open acl_db if not already open, increment ref count.
41 : *******************************************************************/
42 :
43 0 : static bool acl_tdb_init(void)
44 : {
45 : char *dbname;
46 :
47 0 : if (acl_db) {
48 0 : ref_count++;
49 0 : return true;
50 : }
51 :
52 0 : dbname = state_path(talloc_tos(), "file_ntacls.tdb");
53 :
54 0 : if (dbname == NULL) {
55 0 : errno = ENOSYS;
56 0 : return false;
57 : }
58 :
59 0 : become_root();
60 0 : acl_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600,
61 : DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
62 0 : unbecome_root();
63 :
64 0 : if (acl_db == NULL) {
65 : #if defined(ENOTSUP)
66 0 : errno = ENOTSUP;
67 : #else
68 : errno = ENOSYS;
69 : #endif
70 0 : TALLOC_FREE(dbname);
71 0 : return false;
72 : }
73 :
74 0 : ref_count++;
75 0 : TALLOC_FREE(dbname);
76 0 : return true;
77 : }
78 :
79 : /*******************************************************************
80 : Lower ref count and close acl_db if zero.
81 : *******************************************************************/
82 :
83 0 : static void disconnect_acl_tdb(struct vfs_handle_struct *handle)
84 : {
85 0 : SMB_VFS_NEXT_DISCONNECT(handle);
86 0 : ref_count--;
87 0 : if (ref_count == 0) {
88 0 : TALLOC_FREE(acl_db);
89 : }
90 0 : }
91 :
92 : /*******************************************************************
93 : Delete the tdb acl record for a file
94 : *******************************************************************/
95 :
96 0 : static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
97 : struct db_context *db,
98 : SMB_STRUCT_STAT *psbuf)
99 : {
100 : NTSTATUS status;
101 0 : struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
102 : uint8_t id_buf[16];
103 :
104 : /* For backwards compatibility only store the dev/inode. */
105 0 : push_file_id_16((char *)id_buf, &id);
106 :
107 0 : status = dbwrap_delete(db, make_tdb_data(id_buf, sizeof(id_buf)));
108 0 : return status;
109 : }
110 :
111 : /*******************************************************************
112 : Pull a security descriptor from an fsp into a DATA_BLOB from a tdb store.
113 : *******************************************************************/
114 :
115 0 : static NTSTATUS fget_acl_blob(TALLOC_CTX *ctx,
116 : vfs_handle_struct *handle,
117 : files_struct *fsp,
118 : DATA_BLOB *pblob)
119 : {
120 : uint8_t id_buf[16];
121 : TDB_DATA data;
122 : struct file_id id;
123 0 : struct db_context *db = acl_db;
124 0 : NTSTATUS status = NT_STATUS_OK;
125 :
126 0 : status = vfs_stat_fsp(fsp);
127 0 : if (!NT_STATUS_IS_OK(status)) {
128 0 : return status;
129 : }
130 :
131 0 : id = vfs_file_id_from_sbuf(handle->conn, &fsp->fsp_name->st);
132 :
133 : /* For backwards compatibility only store the dev/inode. */
134 0 : push_file_id_16((char *)id_buf, &id);
135 :
136 0 : status = dbwrap_fetch(db,
137 : ctx,
138 : make_tdb_data(id_buf, sizeof(id_buf)),
139 : &data);
140 0 : if (!NT_STATUS_IS_OK(status)) {
141 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
142 : }
143 :
144 0 : pblob->data = data.dptr;
145 0 : pblob->length = data.dsize;
146 :
147 0 : DBG_DEBUG("returned %u bytes from file %s\n",
148 : (unsigned int)data.dsize,
149 : fsp_str_dbg(fsp));
150 :
151 0 : if (pblob->length == 0 || pblob->data == NULL) {
152 0 : return NT_STATUS_NOT_FOUND;
153 : }
154 0 : return NT_STATUS_OK;
155 : }
156 :
157 : /*******************************************************************
158 : Store a DATA_BLOB into a tdb record given an fsp pointer.
159 : *******************************************************************/
160 :
161 0 : static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
162 : files_struct *fsp,
163 : DATA_BLOB *pblob)
164 : {
165 : uint8_t id_buf[16];
166 : struct file_id id;
167 0 : TDB_DATA data = { .dptr = pblob->data, .dsize = pblob->length };
168 0 : struct db_context *db = acl_db;
169 : NTSTATUS status;
170 :
171 0 : DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
172 : (unsigned int)pblob->length, fsp_str_dbg(fsp)));
173 :
174 0 : status = vfs_stat_fsp(fsp);
175 0 : if (!NT_STATUS_IS_OK(status)) {
176 0 : return status;
177 : }
178 :
179 0 : id = vfs_file_id_from_sbuf(handle->conn, &fsp->fsp_name->st);
180 :
181 : /* For backwards compatibility only store the dev/inode. */
182 0 : push_file_id_16((char *)id_buf, &id);
183 :
184 0 : status = dbwrap_store(
185 : db, make_tdb_data(id_buf, sizeof(id_buf)), data, 0);
186 0 : return status;
187 : }
188 :
189 : /*********************************************************************
190 : On unlinkat we need to delete the tdb record (if using tdb).
191 : *********************************************************************/
192 :
193 0 : static int unlinkat_acl_tdb(vfs_handle_struct *handle,
194 : struct files_struct *dirfsp,
195 : const struct smb_filename *smb_fname,
196 : int flags)
197 : {
198 0 : struct smb_filename *smb_fname_tmp = NULL;
199 0 : struct db_context *db = acl_db;
200 0 : int ret = -1;
201 :
202 0 : smb_fname_tmp = cp_smb_filename_nostream(talloc_tos(), smb_fname);
203 0 : if (smb_fname_tmp == NULL) {
204 0 : errno = ENOMEM;
205 0 : goto out;
206 : }
207 :
208 0 : ret = vfs_stat(handle->conn, smb_fname_tmp);
209 0 : if (ret == -1) {
210 0 : goto out;
211 : }
212 :
213 0 : if (flags & AT_REMOVEDIR) {
214 0 : ret = rmdir_acl_common(handle,
215 : dirfsp,
216 : smb_fname_tmp);
217 : } else {
218 0 : ret = unlink_acl_common(handle,
219 : dirfsp,
220 : smb_fname_tmp,
221 : flags);
222 : }
223 :
224 0 : if (ret == -1) {
225 0 : goto out;
226 : }
227 :
228 0 : acl_tdb_delete(handle, db, &smb_fname_tmp->st);
229 0 : out:
230 0 : return ret;
231 : }
232 :
233 : /*******************************************************************
234 : Handle opening the storage tdb if so configured.
235 : *******************************************************************/
236 :
237 0 : static int connect_acl_tdb(struct vfs_handle_struct *handle,
238 : const char *service,
239 : const char *user)
240 : {
241 0 : int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
242 : bool ok;
243 0 : struct acl_common_config *config = NULL;
244 :
245 0 : if (ret < 0) {
246 0 : return ret;
247 : }
248 :
249 0 : if (!acl_tdb_init()) {
250 0 : SMB_VFS_NEXT_DISCONNECT(handle);
251 0 : return -1;
252 : }
253 :
254 0 : ok = init_acl_common_config(handle, ACL_MODULE_NAME);
255 0 : if (!ok) {
256 0 : DBG_ERR("init_acl_common_config failed\n");
257 0 : return -1;
258 : }
259 :
260 : /* Ensure we have the parameters correct if we're
261 : * using this module. */
262 0 : DEBUG(2,("connect_acl_tdb: setting 'inherit acls = true' "
263 : "'dos filemode = true' and "
264 : "'force unknown acl user = true' for service %s\n",
265 : service ));
266 :
267 0 : lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
268 0 : lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
269 0 : lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
270 :
271 0 : SMB_VFS_HANDLE_GET_DATA(handle, config,
272 : struct acl_common_config,
273 : return -1);
274 :
275 0 : if (config->ignore_system_acls) {
276 0 : mode_t create_mask = lp_create_mask(SNUM(handle->conn));
277 0 : char *create_mask_str = NULL;
278 :
279 0 : if ((create_mask & 0666) != 0666) {
280 0 : create_mask |= 0666;
281 0 : create_mask_str = talloc_asprintf(handle, "0%o",
282 : create_mask);
283 0 : if (create_mask_str == NULL) {
284 0 : DBG_ERR("talloc_asprintf failed\n");
285 0 : return -1;
286 : }
287 :
288 0 : DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
289 :
290 0 : lp_do_parameter (SNUM(handle->conn),
291 : "create mask", create_mask_str);
292 :
293 0 : TALLOC_FREE(create_mask_str);
294 : }
295 :
296 0 : DBG_NOTICE("setting 'directory mask = 0777', "
297 : "'store dos attributes = yes' and all "
298 : "'map ...' options to 'no'\n");
299 :
300 0 : lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
301 0 : lp_do_parameter(SNUM(handle->conn), "map archive", "no");
302 0 : lp_do_parameter(SNUM(handle->conn), "map hidden", "no");
303 0 : lp_do_parameter(SNUM(handle->conn), "map readonly", "no");
304 0 : lp_do_parameter(SNUM(handle->conn), "map system", "no");
305 0 : lp_do_parameter(SNUM(handle->conn), "store dos attributes",
306 : "yes");
307 : }
308 :
309 0 : return 0;
310 : }
311 :
312 : /*********************************************************************
313 : Remove a Windows ACL - we're setting the underlying POSIX ACL.
314 : *********************************************************************/
315 :
316 0 : static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
317 : files_struct *fsp,
318 : SMB_ACL_TYPE_T type,
319 : SMB_ACL_T theacl)
320 : {
321 : struct acl_common_fsp_ext *ext = (struct acl_common_fsp_ext *)
322 0 : VFS_FETCH_FSP_EXTENSION(handle, fsp);
323 0 : struct db_context *db = acl_db;
324 : NTSTATUS status;
325 : int ret;
326 :
327 0 : status = vfs_stat_fsp(fsp);
328 0 : if (!NT_STATUS_IS_OK(status)) {
329 0 : return -1;
330 : }
331 :
332 0 : ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
333 : fsp,
334 : type,
335 : theacl);
336 0 : if (ret == -1) {
337 0 : return -1;
338 : }
339 :
340 0 : if (ext != NULL && ext->setting_nt_acl) {
341 0 : return 0;
342 : }
343 :
344 0 : acl_tdb_delete(handle, db, &fsp->fsp_name->st);
345 0 : return 0;
346 : }
347 :
348 0 : static NTSTATUS acl_tdb_fget_nt_acl(vfs_handle_struct *handle,
349 : files_struct *fsp,
350 : uint32_t security_info,
351 : TALLOC_CTX *mem_ctx,
352 : struct security_descriptor **ppdesc)
353 : {
354 : NTSTATUS status;
355 0 : status = fget_nt_acl_common(fget_acl_blob, handle, fsp,
356 : security_info, mem_ctx, ppdesc);
357 0 : return status;
358 : }
359 :
360 0 : static NTSTATUS acl_tdb_fset_nt_acl(vfs_handle_struct *handle,
361 : files_struct *fsp,
362 : uint32_t security_info_sent,
363 : const struct security_descriptor *psd)
364 : {
365 : NTSTATUS status;
366 0 : status = fset_nt_acl_common(fget_acl_blob, store_acl_blob_fsp,
367 : ACL_MODULE_NAME,
368 : handle, fsp, security_info_sent, psd);
369 0 : return status;
370 : }
371 :
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
380 : };
381 :
382 : static_decl_vfs;
383 27 : NTSTATUS vfs_acl_tdb_init(TALLOC_CTX *ctx)
384 : {
385 27 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb",
386 : &vfs_acl_tdb_fns);
387 : }
|