summaryrefslogtreecommitdiffstats
path: root/source/smbd/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/smbd/open.c')
-rw-r--r--source/smbd/open.c66
1 files changed, 57 insertions, 9 deletions
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 79330175bbd..5c54b450df3 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -141,21 +141,33 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn,
* as we always opened files read-write in that release. JRA.
*/
- if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC))
+ if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
+ DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname ));
local_flags = (flags & ~O_ACCMODE)|O_RDWR;
-
- /*
- * We can't actually truncate here as the file may be locked.
- * open_file_shared will take care of the truncate later. JRA.
- */
-
- local_flags &= ~O_TRUNC;
+ }
/* actually do the open */
if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
- (local_flags & O_CREAT)) {
+ (local_flags & O_CREAT) || ((local_flags & O_TRUNC) == O_TRUNC) ) {
+
+ /*
+ * We can't actually truncate here as the file may be locked.
+ * open_file_shared will take care of the truncate later. JRA.
+ */
+ local_flags &= ~O_TRUNC;
+
+#if defined(O_NONBLOCK) && defined(S_ISFIFO)
+ /*
+ * We would block on opening a FIFO with no one else on the
+ * other end. Do what we used to do and add O_NONBLOCK to the
+ * open flags. JRA.
+ */
+
+ if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode))
+ local_flags |= O_NONBLOCK;
+#endif
fsp->fd = fd_open(conn, fname, local_flags, mode);
if (fsp->fd == -1) {
@@ -672,6 +684,31 @@ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fn
return num_share_modes;
}
+static BOOL open_match_attributes(connection_struct *conn, char *path, mode_t existing_mode, mode_t new_mode)
+{
+ uint32 old_dos_mode, new_dos_mode;
+ SMB_STRUCT_STAT sbuf;
+
+ ZERO_STRUCT(sbuf);
+
+ sbuf.st_mode = existing_mode;
+ old_dos_mode = dos_mode(conn, path, &sbuf);
+
+ sbuf.st_mode = new_mode;
+ new_dos_mode = dos_mode(conn, path, &sbuf);
+
+ /* If we're mapping SYSTEM and HIDDEN ensure they match. */
+ if (lp_map_system(SNUM(conn))) {
+ if ((old_dos_mode & FILE_ATTRIBUTE_SYSTEM) != (new_dos_mode & FILE_ATTRIBUTE_SYSTEM))
+ return False;
+ }
+ if (lp_map_hidden(SNUM(conn))) {
+ if ((old_dos_mode & FILE_ATTRIBUTE_HIDDEN) != (new_dos_mode & FILE_ATTRIBUTE_HIDDEN))
+ return False;
+ }
+ return True;
+}
+
/****************************************************************************
set a kernel flock on a file for NFS interoperability
this requires a patch to Linux
@@ -782,6 +819,17 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_
if (CAN_WRITE(conn) && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE))
flags2 |= O_TRUNC;
+ /* We only care about matching attributes on file exists and truncate. */
+ if (file_existed && (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_TRUNCATE)) {
+ if (!open_match_attributes(conn, fname, psbuf->st_mode, mode)) {
+ DEBUG(5,("open_file_shared: attributes missmatch for file %s (0%o, 0%o)\n",
+ fname, psbuf->st_mode, mode ));
+ file_free(fsp);
+ errno = EACCES;
+ return NULL;
+ }
+ }
+
if (GET_FILE_OPEN_DISPOSITION(ofun) == FILE_EXISTS_FAIL)
flags2 |= O_EXCL;