*/
#include "includes.h"
+#include "smbd/globals.h"
extern const struct generic_mapping file_generic_mapping;
-extern bool global_client_failed_oplock_break;
struct deferred_open_record {
bool delayed_for_oplocks;
static NTSTATUS check_open_rights(struct connection_struct *conn,
const char *fname,
- uint32_t access_mask)
+ uint32_t access_mask,
+ uint32_t *access_granted)
{
/* Check if we have rights to open. */
NTSTATUS status;
- uint32_t access_granted = 0;
struct security_descriptor *sd;
+ *access_granted = 0;
+
+ if (conn->server_info->utok.uid == 0 || conn->admin_user) {
+ /* I'm sorry sir, I didn't know you were root... */
+ *access_granted = access_mask;
+ if (access_mask & SEC_FLAG_MAXIMUM_ALLOWED) {
+ *access_granted |= FILE_GENERIC_ALL;
+ }
+ return NT_STATUS_OK;
+ }
+
status = SMB_VFS_GET_NT_ACL(conn, fname,
(OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
status = smb1_file_se_access_check(sd,
conn->server_info->ptok,
access_mask,
- &access_granted);
+ access_granted);
TALLOC_FREE(sd);
+
+ DEBUG(10,("check_open_rights: file %s requesting "
+ "0x%x returning 0x%x (%s)\n",
+ fname,
+ (unsigned int)access_mask,
+ (unsigned int)*access_granted,
+ nt_errstr(status) ));
+
return status;
}
fsp->fh->fd = SMB_VFS_OPEN(conn,fname,fsp,flags,mode);
if (fsp->fh->fd == -1) {
status = map_nt_error_from_unix(errno);
+ if (errno == EMFILE) {
+ static time_t last_warned = 0L;
+
+ if (time((time_t *) NULL) > last_warned) {
+ DEBUG(0,("Too many open files, unable "
+ "to open more! smbd's max "
+ "open files = %d\n",
+ lp_max_open_files()));
+ last_warned = time((time_t *) NULL);
+ }
+ }
+
}
DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n",
} else {
fsp->fh->fd = -1; /* What we used to call a stat open. */
if (file_existed) {
+ uint32_t access_granted = 0;
+
status = check_open_rights(conn,
path,
- access_mask);
+ access_mask,
+ &access_granted);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("open_file: Access denied on "
- "file %s\n",
- path));
- return status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ if ((access_mask & DELETE_ACCESS) &&
+ (access_granted == DELETE_ACCESS) &&
+ can_delete_file_in_directory(conn, path)) {
+ /* Were we trying to do a stat open
+ * for delete and didn't get DELETE
+ * access (only) ? Check if the
+ * directory allows DELETE_CHILD.
+ * See here:
+ * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
+ * for details. */
+
+ DEBUG(10,("open_file: overrode ACCESS_DENIED "
+ "on file %s\n",
+ path ));
+ } else {
+ DEBUG(10, ("open_file: Access denied on "
+ "file %s\n",
+ path));
+ return status;
+ }
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
+ fsp->posix_open &&
+ S_ISLNK(psbuf->st_mode)) {
+ /* This is a POSIX stat open for delete
+ * or rename on a symlink that points
+ * nowhere. Allow. */
+ DEBUG(10, ("open_file: allowing POSIX open "
+ "on bad symlink %s\n",
+ path ));
+ } else {
+ DEBUG(10, ("open_file: check_open_rights "
+ "on file %s returned %s\n",
+ path, nt_errstr(status) ));
+ return status;
+ }
}
}
}
int pass_number,
int oplock_request)
{
- extern uint32 global_client_caps;
int i;
struct share_mode_entry *exclusive = NULL;
bool valid_entry = false;
bool def_acl = False;
bool posix_open = False;
bool new_file_created = False;
+ bool clear_ads = false;
struct file_id id;
NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
mode_t new_unx_mode = (mode_t)0;
DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname));
- return print_fsp_open(req, conn, fname, req->vuid, fsp);
+ return print_fsp_open(req, conn, fname, req->vuid, fsp, psbuf);
}
- if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
- &newname)) {
+ if (!parent_dirname(talloc_tos(), fname, &parent_dir, &newname)) {
return NT_STATUS_NO_MEMORY;
}
"create_disposition = 0x%x create_options=0x%x "
"unix mode=0%o oplock_request=%d\n",
fname, new_dos_attributes, access_mask, share_access,
- create_disposition, create_options, unx_mode,
+ create_disposition, create_options, (unsigned int)unx_mode,
oplock_request));
if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) {
/* If file exists replace/overwrite. If file doesn't
* exist create. */
flags2 |= (O_CREAT | O_TRUNC);
+ clear_ads = true;
break;
case FILE_OVERWRITE_IF:
/* If file exists replace/overwrite. If file doesn't
* exist create. */
flags2 |= (O_CREAT | O_TRUNC);
+ clear_ads = true;
break;
case FILE_OPEN:
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
flags2 |= O_TRUNC;
+ clear_ads = true;
break;
case FILE_CREATE:
SMB_ASSERT(lck != NULL);
+ /* Delete streams if create_disposition requires it */
+ if (file_existed && clear_ads && !is_ntfs_stream_name(fname)) {
+ status = delete_all_streams(conn, fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ return status;
+ }
+ }
+
/* note that we ignore failure for the following. It is
basically a hack for NFS, and NFS will never set one of
these only read them. Nobody but Samba can ever set a deny
return status;
}
- if (!parent_dirname_talloc(talloc_tos(), name, &parent_dir,
- &dirname)) {
+ if (!parent_dirname(talloc_tos(), name, &parent_dir, &dirname)) {
return NT_STATUS_NO_MEMORY;
}
}
if (info == FILE_WAS_OPENED) {
+ uint32_t access_granted = 0;
status = check_open_rights(conn,
fname,
- access_mask);
+ access_mask,
+ &access_granted);
+
+ /* Were we trying to do a directory open
+ * for delete and didn't get DELETE
+ * access (only) ? Check if the
+ * directory allows DELETE_CHILD.
+ * See here:
+ * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
+ * for details. */
+
+ if ((NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ (access_mask & DELETE_ACCESS) &&
+ (access_granted == DELETE_ACCESS) &&
+ can_delete_file_in_directory(conn, fname))) {
+ DEBUG(10,("open_directory: overrode ACCESS_DENIED "
+ "on directory %s\n",
+ fname ));
+ status = NT_STATUS_OK;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("open_directory: check_open_rights on "
"file %s failed with %s\n",
}
/* Unpack the message. */
- pull_file_id_16(frm, &id);
- sharepath = &frm[16];
+ pull_file_id_24(frm, &id);
+ sharepath = &frm[24];
newname = sharepath + strlen(sharepath) + 1;
sp_len = strlen(sharepath);
&& (create_disposition != FILE_CREATE)
&& (share_access & FILE_SHARE_DELETE)
&& (access_mask & DELETE_ACCESS)
- && (!can_delete_file_in_directory(conn, fname))) {
+ && (!(can_delete_file_in_directory(conn, fname) ||
+ can_access_file_acl(conn, fname, DELETE_ACCESS)))) {
status = NT_STATUS_ACCESS_DENIED;
+ DEBUG(10,("create_file_unixpath: open file %s "
+ "for delete ACCESS_DENIED\n", fname ));
goto fail;
}