diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index d240ecf..003cb0f 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -126,7 +126,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, char *stream = NULL; bool component_was_mangled = False; bool name_has_wildcard = False; + bool posix_pathnames = false; NTSTATUS result; + int ret = -1; SET_STAT_INVALID(*pst); *pp_conv_path = NULL; @@ -225,7 +227,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } } - if (!lp_posix_pathnames()) { + posix_pathnames = lp_posix_pathnames(); + + if (!posix_pathnames) { stream = strchr_m(name, ':'); if (stream != NULL) { @@ -268,7 +272,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * stat the name - if it exists then we are all done! */ - if (SMB_VFS_STAT(conn,name,&st) == 0) { + if (posix_pathnames) { + ret = SMB_VFS_LSTAT(conn,name,&st); + } else { + ret = SMB_VFS_STAT(conn,name,&st); + } + + if (ret == 0) { /* Ensure we catch all names with in "/." this is disallowed under Windows. */ const char *p = strstr(name, "/."); /* mb safe. */ @@ -380,7 +390,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * Check if the name exists up to this point. */ - if (SMB_VFS_STAT(conn,name, &st) == 0) { + if (posix_pathnames) { + ret = SMB_VFS_LSTAT(conn,name, &st); + } else { + ret = SMB_VFS_STAT(conn,name, &st); + } + + if (ret == 0) { /* * It exists. it must either be a directory or this must * be the last part of the path for it to be OK. @@ -598,7 +614,13 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, * if it exists. JRA. */ - if (SMB_VFS_STAT(conn,name, &st) == 0) { + if (posix_pathnames) { + ret = SMB_VFS_LSTAT(conn,name, &st); + } else { + ret = SMB_VFS_STAT(conn,name, &st); + } + + if (ret == 0) { *pst = st; } else { SET_STAT_INVALID(st); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index bc51074..f7a52d7 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -432,28 +432,42 @@ static NTSTATUS open_file(files_struct *fsp, access_mask, &access_granted); if (!NT_STATUS_IS_OK(status)) { - - /* 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. */ - - if (!(NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && - (access_mask & DELETE_ACCESS) && - (access_granted == DELETE_ACCESS) && - can_delete_file_in_directory(conn, path))) { - DEBUG(10, ("open_file: Access denied on " - "file %s\n", - path)); + 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; } - - DEBUG(10,("open_file: overrode ACCESS_DENIED " - "on file %s\n", - path )); } } } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index f2d4ff7..bb5fadd 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -5616,7 +5616,13 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, return map_nt_error_from_unix(errno); } } else { - if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) { + int ret = -1; + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + } else { + ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + } + if (ret == -1) { return map_nt_error_from_unix(errno); } } @@ -5721,6 +5727,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, const char *dname; long offset = 0; int create_options = 0; + bool posix_pathnames = lp_posix_pathnames(); ZERO_STRUCT(sbuf1); ZERO_STRUCT(sbuf2); @@ -5832,7 +5839,11 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, } ZERO_STRUCT(sbuf1); - SMB_VFS_STAT(conn, directory, &sbuf1); + if (posix_pathnames) { + SMB_VFS_LSTAT(conn, directory, &sbuf1); + } else { + SMB_VFS_STAT(conn, directory, &sbuf1); + } if (S_ISDIR(sbuf1.st_mode)) { create_options |= FILE_DIRECTORY_FILE; @@ -5849,7 +5860,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, FILE_SHARE_WRITE), FILE_OPEN, /* create_disposition*/ create_options, /* create_options */ - 0, /* file_attributes */ + posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */ 0, /* oplock_request */ 0, /* allocation_size */ NULL, /* sd */ @@ -5948,7 +5959,11 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, } ZERO_STRUCT(sbuf1); - SMB_VFS_STAT(conn, fname, &sbuf1); + if (posix_pathnames) { + SMB_VFS_LSTAT(conn, fname, &sbuf1); + } else { + SMB_VFS_STAT(conn, fname, &sbuf1); + } create_options = 0; @@ -5967,7 +5982,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, FILE_SHARE_WRITE), FILE_OPEN, /* create_disposition*/ create_options, /* create_options */ - 0, /* file_attributes */ + posix_pathnames ? FILE_FLAG_POSIX_SEMANTICS|0777 : 0, /* file_attributes */ 0, /* oplock_request */ 0, /* allocation_size */ NULL, /* sd */ @@ -7167,7 +7182,14 @@ void reply_setattrE(struct smb_request *req) return; } } else { - if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) { + int ret = -1; + + if (fsp->posix_open) { + ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf); + } else { + ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf); + } + if (ret == -1) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); END_PROFILE(SMBsetattrE);