s3:smbd: fix a race in open code
authorMichael Adam <obnox@samba.org>
Tue, 9 Sep 2014 22:31:25 +0000 (00:31 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 10 Sep 2014 17:24:13 +0000 (19:24 +0200)
The race is when a file vanishes between
existence check and acl check.

In this case, open_file_ncreate() returns
OBJECT_NAME_NOT_FOUND even if the create
was called with disposition OPEN_IF.
But in this case, the file should be created.

Signed-off-by: Michael Adam <obnox@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/open.c

index 67ba25e254a896898d3776e8ca9a1c00f67a36a2..a33cce19ad7fcc316f1fc71526d82a2fef168665 100644 (file)
@@ -819,24 +819,49 @@ static NTSTATUS open_file(files_struct *fsp,
                                                smb_fname,
                                                false,
                                                access_mask);
-                       } else if (local_flags & O_CREAT){
-                               status = check_parent_access(conn,
-                                               smb_fname,
-                                               SEC_DIR_ADD_FILE);
-                       } else {
-                               /* File didn't exist and no O_CREAT. */
-                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       DEBUG(10, ("open_file: "
+                                                  "smbd_check_access_rights "
+                                                  "on file %s returned %s\n",
+                                                  smb_fname_str_dbg(smb_fname),
+                                                  nt_errstr(status)));
+                               }
+
+                               if (!NT_STATUS_IS_OK(status) &&
+                                   !NT_STATUS_EQUAL(status,
+                                       NT_STATUS_OBJECT_NAME_NOT_FOUND))
+                               {
+                                       return status;
+                               }
+
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       DEBUG(10, ("open_file: "
+                                               "file %s vanished since we "
+                                               "checked for existence.\n",
+                                               smb_fname_str_dbg(smb_fname)));
+                                       file_existed = false;
+                                       SET_STAT_INVALID(fsp->fsp_name->st);
+                               }
                        }
-                       if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(10,("open_file: "
-                                       "%s on file "
-                                       "%s returned %s\n",
-                                       file_existed ?
-                                               "smbd_check_access_rights" :
-                                               "check_parent_access",
-                                       smb_fname_str_dbg(smb_fname),
-                                       nt_errstr(status) ));
-                               return status;
+
+                       if (!file_existed) {
+                               if (!(local_flags & O_CREAT)) {
+                                       /* File didn't exist and no O_CREAT. */
+                                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                               }
+
+                               status = check_parent_access(conn,
+                                                            smb_fname,
+                                                            SEC_DIR_ADD_FILE);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       DEBUG(10, ("open_file: "
+                                                  "check_parent_access on "
+                                                  "file %s returned %s\n",
+                                                  smb_fname_str_dbg(smb_fname),
+                                                  nt_errstr(status) ));
+                                       return status;
+                               }
                        }
                }