• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/modules/
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/* NOTE: This is an experimental module, not yet finished. JRA. */
22
23#include "includes.h"
24#include "librpc/gen_ndr/xattr.h"
25#include "librpc/gen_ndr/ndr_xattr.h"
26#include "../lib/crypto/crypto.h"
27
28#undef DBGC_CLASS
29#define DBGC_CLASS DBGC_VFS
30
31#define ACL_MODULE_NAME "acl_tdb"
32#include "modules/vfs_acl_common.c"
33
34static unsigned int ref_count;
35static struct db_context *acl_db;
36
37/*******************************************************************
38 Open acl_db if not already open, increment ref count.
39*******************************************************************/
40
41static bool acl_tdb_init(void)
42{
43	char *dbname;
44
45	if (acl_db) {
46		ref_count++;
47		return true;
48	}
49
50	dbname = state_path("file_ntacls.tdb");
51
52	if (dbname == NULL) {
53		errno = ENOSYS;
54		return false;
55	}
56
57	become_root();
58	acl_db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
59	unbecome_root();
60
61	if (acl_db == NULL) {
62#if defined(ENOTSUP)
63		errno = ENOTSUP;
64#else
65		errno = ENOSYS;
66#endif
67		TALLOC_FREE(dbname);
68		return false;
69	}
70
71	ref_count++;
72	TALLOC_FREE(dbname);
73	return true;
74}
75
76/*******************************************************************
77 Lower ref count and close acl_db if zero.
78*******************************************************************/
79
80static void disconnect_acl_tdb(struct vfs_handle_struct *handle)
81{
82	SMB_VFS_NEXT_DISCONNECT(handle);
83	ref_count--;
84	if (ref_count == 0) {
85		TALLOC_FREE(acl_db);
86	}
87}
88
89/*******************************************************************
90 Fetch_lock the tdb acl record for a file
91*******************************************************************/
92
93static struct db_record *acl_tdb_lock(TALLOC_CTX *mem_ctx,
94					struct db_context *db,
95					const struct file_id *id)
96{
97	uint8 id_buf[16];
98
99	/* For backwards compatibility only store the dev/inode. */
100	push_file_id_16((char *)id_buf, id);
101	return db->fetch_locked(db,
102				mem_ctx,
103				make_tdb_data(id_buf,
104					sizeof(id_buf)));
105}
106
107/*******************************************************************
108 Delete the tdb acl record for a file
109*******************************************************************/
110
111static NTSTATUS acl_tdb_delete(vfs_handle_struct *handle,
112				struct db_context *db,
113				SMB_STRUCT_STAT *psbuf)
114{
115	NTSTATUS status;
116	struct file_id id = vfs_file_id_from_sbuf(handle->conn, psbuf);
117	struct db_record *rec = acl_tdb_lock(talloc_tos(), db, &id);
118
119	/*
120	 * If rec == NULL there's not much we can do about it
121	 */
122
123	if (rec == NULL) {
124		DEBUG(10,("acl_tdb_delete: rec == NULL\n"));
125		TALLOC_FREE(rec);
126		return NT_STATUS_OK;
127	}
128
129	status = rec->delete_rec(rec);
130	TALLOC_FREE(rec);
131	return status;
132}
133
134/*******************************************************************
135 Pull a security descriptor into a DATA_BLOB from a tdb store.
136*******************************************************************/
137
138static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
139			vfs_handle_struct *handle,
140			files_struct *fsp,
141			const char *name,
142			DATA_BLOB *pblob)
143{
144	uint8 id_buf[16];
145	TDB_DATA data;
146	struct file_id id;
147	struct db_context *db = acl_db;
148	NTSTATUS status = NT_STATUS_OK;
149	SMB_STRUCT_STAT sbuf;
150
151	ZERO_STRUCT(sbuf);
152
153	if (fsp) {
154		status = vfs_stat_fsp(fsp);
155		sbuf = fsp->fsp_name->st;
156	} else {
157		int ret = vfs_stat_smb_fname(handle->conn, name, &sbuf);
158		if (ret == -1) {
159			status = map_nt_error_from_unix(errno);
160		}
161	}
162
163	if (!NT_STATUS_IS_OK(status)) {
164		return status;
165	}
166
167	id = vfs_file_id_from_sbuf(handle->conn, &sbuf);
168
169	/* For backwards compatibility only store the dev/inode. */
170	push_file_id_16((char *)id_buf, &id);
171
172	if (db->fetch(db,
173			ctx,
174			make_tdb_data(id_buf, sizeof(id_buf)),
175			&data) == -1) {
176		return NT_STATUS_INTERNAL_DB_CORRUPTION;
177	}
178
179	pblob->data = data.dptr;
180	pblob->length = data.dsize;
181
182	DEBUG(10,("get_acl_blob: returned %u bytes from file %s\n",
183		(unsigned int)data.dsize, name ));
184
185	if (pblob->length == 0 || pblob->data == NULL) {
186		return NT_STATUS_NOT_FOUND;
187	}
188	return NT_STATUS_OK;
189}
190
191/*******************************************************************
192 Store a DATA_BLOB into a tdb record given an fsp pointer.
193*******************************************************************/
194
195static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
196				files_struct *fsp,
197				DATA_BLOB *pblob)
198{
199	uint8 id_buf[16];
200	struct file_id id;
201	TDB_DATA data;
202	struct db_context *db = acl_db;
203	struct db_record *rec;
204	NTSTATUS status;
205
206	DEBUG(10,("store_acl_blob_fsp: storing blob length %u on file %s\n",
207		  (unsigned int)pblob->length, fsp_str_dbg(fsp)));
208
209	status = vfs_stat_fsp(fsp);
210	if (!NT_STATUS_IS_OK(status)) {
211		return status;
212	}
213
214	id = vfs_file_id_from_sbuf(handle->conn, &fsp->fsp_name->st);
215
216	/* For backwards compatibility only store the dev/inode. */
217	push_file_id_16((char *)id_buf, &id);
218	rec = db->fetch_locked(db, talloc_tos(),
219				make_tdb_data(id_buf,
220					sizeof(id_buf)));
221	if (rec == NULL) {
222		DEBUG(0, ("store_acl_blob_fsp_tdb: fetch_lock failed\n"));
223		return NT_STATUS_INTERNAL_DB_CORRUPTION;
224	}
225	data.dptr = pblob->data;
226	data.dsize = pblob->length;
227	return rec->store(rec, data, 0);
228}
229
230/*********************************************************************
231 On unlink we need to delete the tdb record (if using tdb).
232*********************************************************************/
233
234static int unlink_acl_tdb(vfs_handle_struct *handle,
235			  const struct smb_filename *smb_fname)
236{
237	struct smb_filename *smb_fname_tmp = NULL;
238	struct db_context *db = acl_db;
239	NTSTATUS status;
240	int ret = -1;
241
242	status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
243	if (!NT_STATUS_IS_OK(status)) {
244		errno = map_errno_from_nt_status(status);
245		goto out;
246	}
247
248	if (lp_posix_pathnames()) {
249		ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
250	} else {
251		ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
252	}
253
254	if (ret == -1) {
255		goto out;
256	}
257
258	ret = unlink_acl_common(handle, smb_fname_tmp);
259
260	if (ret == -1) {
261		goto out;
262	}
263
264	acl_tdb_delete(handle, db, &smb_fname_tmp->st);
265 out:
266	return ret;
267}
268
269/*********************************************************************
270 On rmdir we need to delete the tdb record (if using tdb).
271*********************************************************************/
272
273static int rmdir_acl_tdb(vfs_handle_struct *handle, const char *path)
274{
275
276	SMB_STRUCT_STAT sbuf;
277	struct db_context *db = acl_db;
278	int ret = -1;
279
280	if (lp_posix_pathnames()) {
281		ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
282	} else {
283		ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
284	}
285
286	if (ret == -1) {
287		return -1;
288	}
289
290	ret = rmdir_acl_common(handle, path);
291	if (ret == -1) {
292		return -1;
293	}
294
295	acl_tdb_delete(handle, db, &sbuf);
296	return 0;
297}
298
299/*******************************************************************
300 Handle opening the storage tdb if so configured.
301*******************************************************************/
302
303static int connect_acl_tdb(struct vfs_handle_struct *handle,
304				const char *service,
305				const char *user)
306{
307	int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
308
309	if (ret < 0) {
310		return ret;
311	}
312
313	if (!acl_tdb_init()) {
314		SMB_VFS_NEXT_DISCONNECT(handle);
315		return -1;
316	}
317
318	/* Ensure we have the parameters correct if we're
319	 * using this module. */
320	DEBUG(2,("connect_acl_tdb: setting 'inherit acls = true' "
321		"'dos filemode = true' and "
322		"'force unknown acl user = true' for service %s\n",
323		service ));
324
325	lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
326	lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
327	lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
328
329	return 0;
330}
331
332/*********************************************************************
333 Remove a Windows ACL - we're setting the underlying POSIX ACL.
334*********************************************************************/
335
336static int sys_acl_set_file_tdb(vfs_handle_struct *handle,
337                              const char *path,
338                              SMB_ACL_TYPE_T type,
339                              SMB_ACL_T theacl)
340{
341	SMB_STRUCT_STAT sbuf;
342	struct db_context *db = acl_db;
343	int ret = -1;
344
345	if (lp_posix_pathnames()) {
346		ret = vfs_lstat_smb_fname(handle->conn, path, &sbuf);
347	} else {
348		ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
349	}
350
351	if (ret == -1) {
352		return -1;
353	}
354
355	ret = SMB_VFS_NEXT_SYS_ACL_SET_FILE(handle,
356						path,
357						type,
358						theacl);
359	if (ret == -1) {
360		return -1;
361	}
362
363	acl_tdb_delete(handle, db, &sbuf);
364	return 0;
365}
366
367/*********************************************************************
368 Remove a Windows ACL - we're setting the underlying POSIX ACL.
369*********************************************************************/
370
371static int sys_acl_set_fd_tdb(vfs_handle_struct *handle,
372                            files_struct *fsp,
373                            SMB_ACL_T theacl)
374{
375	struct db_context *db = acl_db;
376	NTSTATUS status;
377	int ret;
378
379	status = vfs_stat_fsp(fsp);
380	if (!NT_STATUS_IS_OK(status)) {
381		return -1;
382	}
383
384	ret = SMB_VFS_NEXT_SYS_ACL_SET_FD(handle,
385						fsp,
386						theacl);
387	if (ret == -1) {
388		return -1;
389	}
390
391	acl_tdb_delete(handle, db, &fsp->fsp_name->st);
392	return 0;
393}
394
395static struct vfs_fn_pointers vfs_acl_tdb_fns = {
396	.connect_fn = connect_acl_tdb,
397	.disconnect = disconnect_acl_tdb,
398	.opendir = opendir_acl_common,
399	.mkdir = mkdir_acl_common,
400	.open = open_acl_common,
401	.create_file = create_file_acl_common,
402	.unlink = unlink_acl_tdb,
403	.rmdir = rmdir_acl_tdb,
404	.fget_nt_acl = fget_nt_acl_common,
405	.get_nt_acl = get_nt_acl_common,
406	.fset_nt_acl = fset_nt_acl_common,
407	.sys_acl_set_file = sys_acl_set_file_tdb,
408	.sys_acl_set_fd = sys_acl_set_fd_tdb
409};
410
411NTSTATUS vfs_acl_tdb_init(void)
412{
413	return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "acl_tdb",
414				&vfs_acl_tdb_fns);
415}
416