source: branches/samba-3.2.x/source/smbd/open.c@ 228

Last change on this file since 228 was 228, checked in by Herwig Bauernfeind, 17 years ago

Update 3.2 branch to 3.2.6

File size: 88.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 file opening and share modes
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2001-2004
6 Copyright (C) Volker Lendecke 2005
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23
24extern const struct generic_mapping file_generic_mapping;
25extern struct current_user current_user;
26extern userdom_struct current_user_info;
27extern bool global_client_failed_oplock_break;
28
29struct deferred_open_record {
30 bool delayed_for_oplocks;
31 struct file_id id;
32};
33
34/****************************************************************************
35 fd support routines - attempt to do a dos_open.
36****************************************************************************/
37
38static NTSTATUS fd_open(struct connection_struct *conn,
39 const char *fname,
40 files_struct *fsp,
41 int flags,
42 mode_t mode)
43{
44 NTSTATUS status = NT_STATUS_OK;
45
46#ifdef O_NOFOLLOW
47 /*
48 * Never follow symlinks on a POSIX client. The
49 * client should be doing this.
50 */
51
52 if (fsp->posix_open || !lp_symlinks(SNUM(conn))) {
53 flags |= O_NOFOLLOW;
54 }
55#endif
56
57 fsp->fh->fd = SMB_VFS_OPEN(conn,fname,fsp,flags,mode);
58 if (fsp->fh->fd == -1) {
59 status = map_nt_error_from_unix(errno);
60 }
61
62 DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
63 fname, flags, (int)mode, fsp->fh->fd,
64 (fsp->fh->fd == -1) ? strerror(errno) : "" ));
65
66 return status;
67}
68
69/****************************************************************************
70 Close the file associated with a fsp.
71****************************************************************************/
72
73NTSTATUS fd_close(files_struct *fsp)
74{
75 int ret;
76
77 if (fsp->fh->fd == -1) {
78 return NT_STATUS_OK; /* What we used to call a stat open. */
79 }
80 if (fsp->fh->ref_count > 1) {
81 return NT_STATUS_OK; /* Shared handle. Only close last reference. */
82 }
83
84 ret = SMB_VFS_CLOSE(fsp);
85 fsp->fh->fd = -1;
86 if (ret == -1) {
87 return map_nt_error_from_unix(errno);
88 }
89 return NT_STATUS_OK;
90}
91
92/****************************************************************************
93 Change the ownership of a file to that of the parent directory.
94 Do this by fd if possible.
95****************************************************************************/
96
97static void change_file_owner_to_parent(connection_struct *conn,
98 const char *inherit_from_dir,
99 files_struct *fsp)
100{
101 SMB_STRUCT_STAT parent_st;
102 int ret;
103
104 ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st);
105 if (ret == -1) {
106 DEBUG(0,("change_file_owner_to_parent: failed to stat parent "
107 "directory %s. Error was %s\n",
108 inherit_from_dir, strerror(errno) ));
109 return;
110 }
111
112 become_root();
113 ret = SMB_VFS_FCHOWN(fsp, parent_st.st_uid, (gid_t)-1);
114 unbecome_root();
115 if (ret == -1) {
116 DEBUG(0,("change_file_owner_to_parent: failed to fchown "
117 "file %s to parent directory uid %u. Error "
118 "was %s\n", fsp->fsp_name,
119 (unsigned int)parent_st.st_uid,
120 strerror(errno) ));
121 }
122
123 DEBUG(10,("change_file_owner_to_parent: changed new file %s to "
124 "parent directory uid %u.\n", fsp->fsp_name,
125 (unsigned int)parent_st.st_uid ));
126}
127
128static NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
129 const char *inherit_from_dir,
130 const char *fname,
131 SMB_STRUCT_STAT *psbuf)
132{
133 char *saved_dir = NULL;
134 SMB_STRUCT_STAT sbuf;
135 SMB_STRUCT_STAT parent_st;
136 TALLOC_CTX *ctx = talloc_tos();
137 NTSTATUS status = NT_STATUS_OK;
138 int ret;
139
140 ret = SMB_VFS_STAT(conn, inherit_from_dir, &parent_st);
141 if (ret == -1) {
142 status = map_nt_error_from_unix(errno);
143 DEBUG(0,("change_dir_owner_to_parent: failed to stat parent "
144 "directory %s. Error was %s\n",
145 inherit_from_dir, strerror(errno) ));
146 return status;
147 }
148
149 /* We've already done an lstat into psbuf, and we know it's a
150 directory. If we can cd into the directory and the dev/ino
151 are the same then we can safely chown without races as
152 we're locking the directory in place by being in it. This
153 should work on any UNIX (thanks tridge :-). JRA.
154 */
155
156 saved_dir = vfs_GetWd(ctx,conn);
157 if (!saved_dir) {
158 status = map_nt_error_from_unix(errno);
159 DEBUG(0,("change_dir_owner_to_parent: failed to get "
160 "current working directory. Error was %s\n",
161 strerror(errno)));
162 return status;
163 }
164
165 /* Chdir into the new path. */
166 if (vfs_ChDir(conn, fname) == -1) {
167 status = map_nt_error_from_unix(errno);
168 DEBUG(0,("change_dir_owner_to_parent: failed to change "
169 "current working directory to %s. Error "
170 "was %s\n", fname, strerror(errno) ));
171 goto out;
172 }
173
174 if (SMB_VFS_STAT(conn,".",&sbuf) == -1) {
175 status = map_nt_error_from_unix(errno);
176 DEBUG(0,("change_dir_owner_to_parent: failed to stat "
177 "directory '.' (%s) Error was %s\n",
178 fname, strerror(errno)));
179 goto out;
180 }
181
182 /* Ensure we're pointing at the same place. */
183 if (sbuf.st_dev != psbuf->st_dev ||
184 sbuf.st_ino != psbuf->st_ino ||
185 sbuf.st_mode != psbuf->st_mode ) {
186 DEBUG(0,("change_dir_owner_to_parent: "
187 "device/inode/mode on directory %s changed. "
188 "Refusing to chown !\n", fname ));
189 status = NT_STATUS_ACCESS_DENIED;
190 goto out;
191 }
192
193 become_root();
194 ret = SMB_VFS_CHOWN(conn, ".", parent_st.st_uid, (gid_t)-1);
195 unbecome_root();
196 if (ret == -1) {
197 status = map_nt_error_from_unix(errno);
198 DEBUG(10,("change_dir_owner_to_parent: failed to chown "
199 "directory %s to parent directory uid %u. "
200 "Error was %s\n", fname,
201 (unsigned int)parent_st.st_uid, strerror(errno) ));
202 goto out;
203 }
204
205 DEBUG(10,("change_dir_owner_to_parent: changed ownership of new "
206 "directory %s to parent directory uid %u.\n",
207 fname, (unsigned int)parent_st.st_uid ));
208
209 out:
210
211 vfs_ChDir(conn,saved_dir);
212 return status;
213}
214
215/****************************************************************************
216 Open a file.
217****************************************************************************/
218
219static NTSTATUS open_file(files_struct *fsp,
220 connection_struct *conn,
221 struct smb_request *req,
222 const char *parent_dir,
223 const char *name,
224 const char *path,
225 SMB_STRUCT_STAT *psbuf,
226 int flags,
227 mode_t unx_mode,
228 uint32 access_mask, /* client requested access mask. */
229 uint32 open_access_mask) /* what we're actually using in the open. */
230{
231 NTSTATUS status = NT_STATUS_OK;
232 int accmode = (flags & O_ACCMODE);
233 int local_flags = flags;
234 bool file_existed = VALID_STAT(*psbuf);
235
236 fsp->fh->fd = -1;
237 errno = EPERM;
238
239 /* Check permissions */
240
241 /*
242 * This code was changed after seeing a client open request
243 * containing the open mode of (DENY_WRITE/read-only) with
244 * the 'create if not exist' bit set. The previous code
245 * would fail to open the file read only on a read-only share
246 * as it was checking the flags parameter directly against O_RDONLY,
247 * this was failing as the flags parameter was set to O_RDONLY|O_CREAT.
248 * JRA.
249 */
250
251 if (!CAN_WRITE(conn)) {
252 /* It's a read-only share - fail if we wanted to write. */
253 if(accmode != O_RDONLY) {
254 DEBUG(3,("Permission denied opening %s\n", path));
255 return NT_STATUS_ACCESS_DENIED;
256 } else if(flags & O_CREAT) {
257 /* We don't want to write - but we must make sure that
258 O_CREAT doesn't create the file if we have write
259 access into the directory.
260 */
261 flags &= ~O_CREAT;
262 local_flags &= ~O_CREAT;
263 }
264 }
265
266 /*
267 * This little piece of insanity is inspired by the
268 * fact that an NT client can open a file for O_RDONLY,
269 * but set the create disposition to FILE_EXISTS_TRUNCATE.
270 * If the client *can* write to the file, then it expects to
271 * truncate the file, even though it is opening for readonly.
272 * Quicken uses this stupid trick in backup file creation...
273 * Thanks *greatly* to "David W. Chapman Jr." <[email protected]>
274 * for helping track this one down. It didn't bite us in 2.0.x
275 * as we always opened files read-write in that release. JRA.
276 */
277
278 if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
279 DEBUG(10,("open_file: truncate requested on read-only open "
280 "for file %s\n", path));
281 local_flags = (flags & ~O_ACCMODE)|O_RDWR;
282 }
283
284 if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
285 (!file_existed && (local_flags & O_CREAT)) ||
286 ((local_flags & O_TRUNC) == O_TRUNC) ) {
287 const char *wild;
288
289 /*
290 * We can't actually truncate here as the file may be locked.
291 * open_file_ntcreate will take care of the truncate later. JRA.
292 */
293
294 local_flags &= ~O_TRUNC;
295
296#if defined(O_NONBLOCK) && defined(S_ISFIFO)
297 /*
298 * We would block on opening a FIFO with no one else on the
299 * other end. Do what we used to do and add O_NONBLOCK to the
300 * open flags. JRA.
301 */
302
303 if (file_existed && S_ISFIFO(psbuf->st_mode)) {
304 local_flags |= O_NONBLOCK;
305 }
306#endif
307
308 /* Don't create files with Microsoft wildcard characters. */
309 if (fsp->base_fsp) {
310 /*
311 * wildcard characters are allowed in stream names
312 * only test the basefilename
313 */
314 wild = fsp->base_fsp->fsp_name;
315 } else {
316 wild = path;
317 }
318 if ((local_flags & O_CREAT) && !file_existed &&
319 ms_has_wild(wild)) {
320 return NT_STATUS_OBJECT_NAME_INVALID;
321 }
322
323 /* Actually do the open */
324 status = fd_open(conn, path, fsp, local_flags, unx_mode);
325 if (!NT_STATUS_IS_OK(status)) {
326 DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
327 "(flags=%d)\n",
328 path,nt_errstr(status),local_flags,flags));
329 return status;
330 }
331
332 if ((local_flags & O_CREAT) && !file_existed) {
333
334 /* Inherit the ACL if required */
335 if (lp_inherit_perms(SNUM(conn))) {
336 inherit_access_acl(conn, parent_dir, path,
337 unx_mode);
338 }
339
340 /* Change the owner if required. */
341 if (lp_inherit_owner(SNUM(conn))) {
342 change_file_owner_to_parent(conn, parent_dir,
343 fsp);
344 }
345
346 notify_fname(conn, NOTIFY_ACTION_ADDED,
347 FILE_NOTIFY_CHANGE_FILE_NAME, path);
348 }
349
350 } else {
351 fsp->fh->fd = -1; /* What we used to call a stat open. */
352 }
353
354 if (!file_existed) {
355 int ret;
356
357 if (fsp->fh->fd == -1) {
358 ret = SMB_VFS_STAT(conn, path, psbuf);
359 } else {
360 ret = SMB_VFS_FSTAT(fsp, psbuf);
361 /* If we have an fd, this stat should succeed. */
362 if (ret == -1) {
363 DEBUG(0,("Error doing fstat on open file %s "
364 "(%s)\n", path,strerror(errno) ));
365 }
366 }
367
368 /* For a non-io open, this stat failing means file not found. JRA */
369 if (ret == -1) {
370 status = map_nt_error_from_unix(errno);
371 fd_close(fsp);
372 return status;
373 }
374 }
375
376 /*
377 * POSIX allows read-only opens of directories. We don't
378 * want to do this (we use a different code path for this)
379 * so catch a directory open and return an EISDIR. JRA.
380 */
381
382 if(S_ISDIR(psbuf->st_mode)) {
383 fd_close(fsp);
384 errno = EISDIR;
385 return NT_STATUS_FILE_IS_A_DIRECTORY;
386 }
387
388 fsp->mode = psbuf->st_mode;
389 fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
390 fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
391 fsp->file_pid = req ? req->smbpid : 0;
392 fsp->can_lock = True;
393 fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
394 if (!CAN_WRITE(conn)) {
395 fsp->can_write = False;
396 } else {
397 fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ?
398 True : False;
399 }
400 fsp->print_file = False;
401 fsp->modified = False;
402 fsp->sent_oplock_break = NO_BREAK_SENT;
403 fsp->is_directory = False;
404 fsp->is_stat = False;
405 if (conn->aio_write_behind_list &&
406 is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) {
407 fsp->aio_write_behind = True;
408 }
409
410 string_set(&fsp->fsp_name, path);
411 fsp->wcp = NULL; /* Write cache pointer. */
412
413 DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
414 *current_user_info.smb_name ?
415 current_user_info.smb_name : conn->user,fsp->fsp_name,
416 BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
417 conn->num_files_open));
418
419 errno = 0;
420 return NT_STATUS_OK;
421}
422
423/*******************************************************************
424 Return True if the filename is one of the special executable types.
425********************************************************************/
426
427static bool is_executable(const char *fname)
428{
429 if ((fname = strrchr_m(fname,'.'))) {
430 if (strequal(fname,".com") ||
431 strequal(fname,".dll") ||
432 strequal(fname,".exe") ||
433 strequal(fname,".sym")) {
434 return True;
435 }
436 }
437 return False;
438}
439
440/****************************************************************************
441 Check if we can open a file with a share mode.
442 Returns True if conflict, False if not.
443****************************************************************************/
444
445static bool share_conflict(struct share_mode_entry *entry,
446 uint32 access_mask,
447 uint32 share_access)
448{
449 DEBUG(10,("share_conflict: entry->access_mask = 0x%x, "
450 "entry->share_access = 0x%x, "
451 "entry->private_options = 0x%x\n",
452 (unsigned int)entry->access_mask,
453 (unsigned int)entry->share_access,
454 (unsigned int)entry->private_options));
455
456 DEBUG(10,("share_conflict: access_mask = 0x%x, share_access = 0x%x\n",
457 (unsigned int)access_mask, (unsigned int)share_access));
458
459 if ((entry->access_mask & (FILE_WRITE_DATA|
460 FILE_APPEND_DATA|
461 FILE_READ_DATA|
462 FILE_EXECUTE|
463 DELETE_ACCESS)) == 0) {
464 DEBUG(10,("share_conflict: No conflict due to "
465 "entry->access_mask = 0x%x\n",
466 (unsigned int)entry->access_mask ));
467 return False;
468 }
469
470 if ((access_mask & (FILE_WRITE_DATA|
471 FILE_APPEND_DATA|
472 FILE_READ_DATA|
473 FILE_EXECUTE|
474 DELETE_ACCESS)) == 0) {
475 DEBUG(10,("share_conflict: No conflict due to "
476 "access_mask = 0x%x\n",
477 (unsigned int)access_mask ));
478 return False;
479 }
480
481#if 1 /* JRA TEST - Superdebug. */
482#define CHECK_MASK(num, am, right, sa, share) \
483 DEBUG(10,("share_conflict: [%d] am (0x%x) & right (0x%x) = 0x%x\n", \
484 (unsigned int)(num), (unsigned int)(am), \
485 (unsigned int)(right), (unsigned int)(am)&(right) )); \
486 DEBUG(10,("share_conflict: [%d] sa (0x%x) & share (0x%x) = 0x%x\n", \
487 (unsigned int)(num), (unsigned int)(sa), \
488 (unsigned int)(share), (unsigned int)(sa)&(share) )); \
489 if (((am) & (right)) && !((sa) & (share))) { \
490 DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
491sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
492 (unsigned int)(share) )); \
493 return True; \
494 }
495#else
496#define CHECK_MASK(num, am, right, sa, share) \
497 if (((am) & (right)) && !((sa) & (share))) { \
498 DEBUG(10,("share_conflict: check %d conflict am = 0x%x, right = 0x%x, \
499sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (unsigned int)(sa), \
500 (unsigned int)(share) )); \
501 return True; \
502 }
503#endif
504
505 CHECK_MASK(1, entry->access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,
506 share_access, FILE_SHARE_WRITE);
507 CHECK_MASK(2, access_mask, FILE_WRITE_DATA | FILE_APPEND_DATA,
508 entry->share_access, FILE_SHARE_WRITE);
509
510 CHECK_MASK(3, entry->access_mask, FILE_READ_DATA | FILE_EXECUTE,
511 share_access, FILE_SHARE_READ);
512 CHECK_MASK(4, access_mask, FILE_READ_DATA | FILE_EXECUTE,
513 entry->share_access, FILE_SHARE_READ);
514
515 CHECK_MASK(5, entry->access_mask, DELETE_ACCESS,
516 share_access, FILE_SHARE_DELETE);
517 CHECK_MASK(6, access_mask, DELETE_ACCESS,
518 entry->share_access, FILE_SHARE_DELETE);
519
520 DEBUG(10,("share_conflict: No conflict.\n"));
521 return False;
522}
523
524#if defined(DEVELOPER)
525static void validate_my_share_entries(int num,
526 struct share_mode_entry *share_entry)
527{
528 files_struct *fsp;
529
530 if (!procid_is_me(&share_entry->pid)) {
531 return;
532 }
533
534 if (is_deferred_open_entry(share_entry) &&
535 !open_was_deferred(share_entry->op_mid)) {
536 char *str = talloc_asprintf(talloc_tos(),
537 "Got a deferred entry without a request: "
538 "PANIC: %s\n",
539 share_mode_str(talloc_tos(), num, share_entry));
540 smb_panic(str);
541 }
542
543 if (!is_valid_share_mode_entry(share_entry)) {
544 return;
545 }
546
547 fsp = file_find_dif(share_entry->id,
548 share_entry->share_file_id);
549 if (!fsp) {
550 DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
551 share_mode_str(talloc_tos(), num, share_entry) ));
552 smb_panic("validate_my_share_entries: Cannot match a "
553 "share entry with an open file\n");
554 }
555
556 if (is_deferred_open_entry(share_entry) ||
557 is_unused_share_mode_entry(share_entry)) {
558 goto panic;
559 }
560
561 if ((share_entry->op_type == NO_OPLOCK) &&
562 (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK)) {
563 /* Someone has already written to it, but I haven't yet
564 * noticed */
565 return;
566 }
567
568 if (((uint16)fsp->oplock_type) != share_entry->op_type) {
569 goto panic;
570 }
571
572 return;
573
574 panic:
575 {
576 char *str;
577 DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
578 share_mode_str(talloc_tos(), num, share_entry) ));
579 str = talloc_asprintf(talloc_tos(),
580 "validate_my_share_entries: "
581 "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
582 fsp->fsp_name, (unsigned int)fsp->oplock_type,
583 (unsigned int)share_entry->op_type );
584 smb_panic(str);
585 }
586}
587#endif
588
589static bool is_stat_open(uint32 access_mask)
590{
591 return (access_mask &&
592 ((access_mask & ~(SYNCHRONIZE_ACCESS| FILE_READ_ATTRIBUTES|
593 FILE_WRITE_ATTRIBUTES))==0) &&
594 ((access_mask & (SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES|
595 FILE_WRITE_ATTRIBUTES)) != 0));
596}
597
598/****************************************************************************
599 Deal with share modes
600 Invarient: Share mode must be locked on entry and exit.
601 Returns -1 on error, or number of share modes on success (may be zero).
602****************************************************************************/
603
604static NTSTATUS open_mode_check(connection_struct *conn,
605 const char *fname,
606 struct share_mode_lock *lck,
607 uint32 access_mask,
608 uint32 share_access,
609 uint32 create_options,
610 bool *file_existed)
611{
612 int i;
613
614 if(lck->num_share_modes == 0) {
615 return NT_STATUS_OK;
616 }
617
618 *file_existed = True;
619
620 /* A delete on close prohibits everything */
621
622 if (lck->delete_on_close) {
623 return NT_STATUS_DELETE_PENDING;
624 }
625
626 if (is_stat_open(access_mask)) {
627 /* Stat open that doesn't trigger oplock breaks or share mode
628 * checks... ! JRA. */
629 return NT_STATUS_OK;
630 }
631
632 /*
633 * Check if the share modes will give us access.
634 */
635
636#if defined(DEVELOPER)