2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 this is the open files database. It implements shared storage of
23 what files are open between server instances, and implements the rules
24 of shared access to files.
26 The caller needs to provide a file_key, which specifies what file
27 they are talking about. This needs to be a unique key across all
28 filesystems, and is usually implemented in terms of a device/inode
31 Before any operations can be performed the caller needs to establish
32 a lock on the record associated with file_key. That is done by
33 calling odb_lock(). The caller releases this lock by calling
34 talloc_free() on the returned handle.
36 All other operations on a record are done by passing the odb_lock()
37 handle back to this module. The handle contains internal
38 information about what file_key is being operated on.
42 #include "system/filesys.h"
43 #include "lib/tdb/include/tdb.h"
44 #include "messaging/messaging.h"
45 #include "librpc/gen_ndr/ndr_security.h"
47 #include "smb_server/smb_server.h"
48 #include "lib/messaging/irpc.h"
53 struct messaging_context *messaging_ctx;
57 the database is indexed by a file_key, and contains entries of the
64 uint32_t share_access;
65 uint32_t create_options;
73 an odb lock handle. You must obtain one of these using odb_lock() before doing
77 struct odb_context *odb;
82 Open up the openfiles.tdb database. Close it down using
83 talloc_free(). We need the messaging_ctx to allow for pending open
86 struct odb_context *odb_init(TALLOC_CTX *mem_ctx, uint32_t server,
87 struct messaging_context *messaging_ctx)
90 struct odb_context *odb;
92 odb = talloc(mem_ctx, struct odb_context);
97 path = smbd_tmp_path(odb, "openfiles.tdb");
98 odb->w = tdb_wrap_open(odb, path, 0,
100 O_RDWR|O_CREAT, 0600);
102 if (odb->w == NULL) {
107 odb->server = server;
108 odb->messaging_ctx = messaging_ctx;
114 destroy a lock on the database
116 static int odb_lock_destructor(void *ptr)
118 struct odb_lock *lck = ptr;
119 tdb_chainunlock(lck->odb->w->tdb, lck->key);
124 get a lock on a entry in the odb. This call returns a lock handle,
125 which the caller should unlock using talloc_free().
127 struct odb_lock *odb_lock(TALLOC_CTX *mem_ctx,
128 struct odb_context *odb, DATA_BLOB *file_key)
130 struct odb_lock *lck;
132 lck = talloc(mem_ctx, struct odb_lock);
137 lck->odb = talloc_reference(lck, odb);
138 lck->key.dptr = talloc_memdup(lck, file_key->data, file_key->length);
139 lck->key.dsize = file_key->length;
140 if (lck->key.dptr == NULL) {
145 if (tdb_chainlock(odb->w->tdb, lck->key) != 0) {
150 talloc_set_destructor(lck, odb_lock_destructor);
156 determine if two odb_entry structures conflict
158 return NT_STATUS_OK on no conflict
160 static NTSTATUS share_conflict(struct odb_entry *e1, struct odb_entry *e2)
162 if (e1->pending || e2->pending) return NT_STATUS_OK;
164 /* if either open involves no read.write or delete access then
166 if (!(e1->access_mask & (SEC_FILE_WRITE_DATA |
167 SEC_FILE_APPEND_DATA |
173 if (!(e2->access_mask & (SEC_FILE_WRITE_DATA |
174 SEC_FILE_APPEND_DATA |
181 /* data IO access masks. This is skipped if the two open handles
182 are on different streams (as in that case the masks don't
184 if (e1->stream_id != e2->stream_id) {
188 #define CHECK_MASK(am, right, sa, share) \
189 if (((am) & (right)) && !((sa) & (share))) return NT_STATUS_SHARING_VIOLATION
191 CHECK_MASK(e1->access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
192 e2->share_access, NTCREATEX_SHARE_ACCESS_WRITE);
193 CHECK_MASK(e2->access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
194 e1->share_access, NTCREATEX_SHARE_ACCESS_WRITE);
196 CHECK_MASK(e1->access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
197 e2->share_access, NTCREATEX_SHARE_ACCESS_READ);
198 CHECK_MASK(e2->access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
199 e1->share_access, NTCREATEX_SHARE_ACCESS_READ);
201 CHECK_MASK(e1->access_mask, SEC_STD_DELETE,
202 e2->share_access, NTCREATEX_SHARE_ACCESS_DELETE);
203 CHECK_MASK(e2->access_mask, SEC_STD_DELETE,
204 e1->share_access, NTCREATEX_SHARE_ACCESS_DELETE);
206 /* if a delete is pending then a second open is not allowed */
207 if ((e1->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) ||
208 (e2->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
209 return NT_STATUS_DELETE_PENDING;
216 register an open file in the open files database. This implements the share_access
219 NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle,
221 uint32_t share_access, uint32_t create_options,
222 uint32_t access_mask)
224 struct odb_context *odb = lck->odb;
228 struct odb_entry *elist;
230 dbuf = tdb_fetch(odb->w->tdb, lck->key);
232 e.server = odb->server;
233 e.file_handle = file_handle;
234 e.stream_id = stream_id;
235 e.share_access = share_access;
236 e.create_options = create_options;
237 e.access_mask = access_mask;
241 /* check the existing file opens to see if they
243 elist = (struct odb_entry *)dbuf.dptr;
244 count = dbuf.dsize / sizeof(struct odb_entry);
246 for (i=0;i<count;i++) {
248 status = share_conflict(elist+i, &e);
249 if (!NT_STATUS_IS_OK(status)) {
250 if (dbuf.dptr) free(dbuf.dptr);
255 elist = realloc_p(dbuf.dptr, struct odb_entry, count+1);
257 if (dbuf.dptr) free(dbuf.dptr);
258 return NT_STATUS_NO_MEMORY;
261 dbuf.dptr = (char *)elist;
262 dbuf.dsize = (count+1) * sizeof(struct odb_entry);
264 memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
265 &e, sizeof(struct odb_entry));
267 if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
269 return NT_STATUS_INTERNAL_DB_CORRUPTION;
278 register a pending open file in the open files database
280 NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private)
282 struct odb_context *odb = lck->odb;
285 struct odb_entry *elist;
288 dbuf = tdb_fetch(odb->w->tdb, lck->key);
290 e.server = odb->server;
291 e.file_handle = NULL;
294 e.create_options = 0;
296 e.notify_ptr = private;
299 /* check the existing file opens to see if they
301 elist = (struct odb_entry *)dbuf.dptr;
302 count = dbuf.dsize / sizeof(struct odb_entry);
304 elist = realloc_p(dbuf.dptr, struct odb_entry, count+1);
306 if (dbuf.dptr) free(dbuf.dptr);
307 return NT_STATUS_NO_MEMORY;
310 dbuf.dptr = (char *)elist;
311 dbuf.dsize = (count+1) * sizeof(struct odb_entry);
313 memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
314 &e, sizeof(struct odb_entry));
316 if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
318 return NT_STATUS_INTERNAL_DB_CORRUPTION;
327 remove a opendb entry
329 NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle)
331 struct odb_context *odb = lck->odb;
333 struct odb_entry *elist;
337 dbuf = tdb_fetch(odb->w->tdb, lck->key);
339 if (dbuf.dptr == NULL) {
340 return NT_STATUS_UNSUCCESSFUL;
343 elist = (struct odb_entry *)dbuf.dptr;
344 count = dbuf.dsize / sizeof(struct odb_entry);
346 /* send any pending notifications, removing them once sent */
347 for (i=0;i<count;i++) {
348 if (elist[i].pending) {
349 messaging_send_ptr(odb->messaging_ctx, elist[i].server,
350 MSG_PVFS_RETRY_OPEN, elist[i].notify_ptr);
351 memmove(&elist[i], &elist[i+1], sizeof(struct odb_entry)*(count-(i+1)));
357 /* find the entry, and delete it */
358 for (i=0;i<count;i++) {
359 if (file_handle == elist[i].file_handle &&
360 odb->server == elist[i].server) {
362 memmove(elist+i, elist+i+1,
363 (count - (i+1)) * sizeof(struct odb_entry));
369 status = NT_STATUS_OK;
372 status = NT_STATUS_UNSUCCESSFUL;
373 } else if (count == 1) {
374 if (tdb_delete(odb->w->tdb, lck->key) != 0) {
375 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
378 dbuf.dsize = (count-1) * sizeof(struct odb_entry);
379 if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
380 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
391 remove a pending opendb entry
393 NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private)
395 struct odb_context *odb = lck->odb;
397 struct odb_entry *elist;
401 dbuf = tdb_fetch(odb->w->tdb, lck->key);
403 if (dbuf.dptr == NULL) {
404 return NT_STATUS_UNSUCCESSFUL;
407 elist = (struct odb_entry *)dbuf.dptr;
408 count = dbuf.dsize / sizeof(struct odb_entry);
410 /* find the entry, and delete it */
411 for (i=0;i<count;i++) {
412 if (private == elist[i].notify_ptr &&
413 odb->server == elist[i].server) {
415 memmove(elist+i, elist+i+1,
416 (count - (i+1)) * sizeof(struct odb_entry));
422 status = NT_STATUS_OK;
425 status = NT_STATUS_UNSUCCESSFUL;
426 } else if (count == 1) {
427 if (tdb_delete(odb->w->tdb, lck->key) != 0) {
428 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
431 dbuf.dsize = (count-1) * sizeof(struct odb_entry);
432 if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
433 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
444 update create options on an open file
446 NTSTATUS odb_set_create_options(struct odb_lock *lck,
447 void *file_handle, uint32_t create_options)
449 struct odb_context *odb = lck->odb;
451 struct odb_entry *elist;
455 dbuf = tdb_fetch(odb->w->tdb, lck->key);
456 if (dbuf.dptr == NULL) {
457 return NT_STATUS_UNSUCCESSFUL;
460 elist = (struct odb_entry *)dbuf.dptr;
461 count = dbuf.dsize / sizeof(struct odb_entry);
463 /* find the entry, and modify it */
464 for (i=0;i<count;i++) {
465 if (file_handle == elist[i].file_handle &&
466 odb->server == elist[i].server) {
467 elist[i].create_options = create_options;
472 if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
473 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
475 status = NT_STATUS_OK;
485 determine if a file can be opened with the given share_access,
486 create_options and access_mask
488 NTSTATUS odb_can_open(struct odb_context *odb, DATA_BLOB *key,
489 uint32_t share_access, uint32_t create_options,
490 uint32_t access_mask)
494 struct odb_entry *elist;
498 kbuf.dptr = (char *)key->data;
499 kbuf.dsize = key->length;
501 dbuf = tdb_fetch(odb->w->tdb, kbuf);
502 if (dbuf.dptr == NULL) {
506 elist = (struct odb_entry *)dbuf.dptr;
507 count = dbuf.dsize / sizeof(struct odb_entry);
514 e.server = odb->server;
515 e.file_handle = NULL;
517 e.share_access = share_access;
518 e.create_options = create_options;
519 e.access_mask = access_mask;
523 for (i=0;i<count;i++) {
525 status = share_conflict(elist+i, &e);
526 if (!NT_STATUS_IS_OK(status)) {
527 if (dbuf.dptr) free(dbuf.dptr);
528 /* note that we discard the error code
529 here. We do this as unless we are actually
530 doing an open (which comes via a sdifferent
531 function), we need to return a sharing
533 return NT_STATUS_SHARING_VIOLATION;