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