diff options
Diffstat (limited to 'source/smbd/open.c')
-rw-r--r-- | source/smbd/open.c | 229 |
1 files changed, 99 insertions, 130 deletions
diff --git a/source/smbd/open.c b/source/smbd/open.c index a95793a0505..79330175bbd 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1,5 +1,6 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 1.9. file opening and share modes Copyright (C) Andrew Tridgell 1992-1998 Copyright (C) Jeremy Allison 2001 @@ -33,18 +34,19 @@ static int fd_open(struct connection_struct *conn, char *fname, int flags, mode_t mode) { int fd; + #ifdef O_NOFOLLOW if (!lp_symlinks(SNUM(conn))) flags |= O_NOFOLLOW; #endif - fd = conn->vfs_ops.open(conn,fname,flags,mode); + fd = conn->vfs_ops.open(conn,dos_to_unix_static(fname),flags,mode); /* Fix for files ending in '.' */ if((fd == -1) && (errno == ENOENT) && - (strchr_m(fname,'.')==NULL)) { + (strchr(fname,'.')==NULL)) { pstrcat(fname,"."); - fd = conn->vfs_ops.open(conn,fname,flags,mode); + fd = conn->vfs_ops.open(conn,dos_to_unix_static(fname),flags,mode); } DEBUG(10,("fd_open: name %s, flags = 0%o mode = 0%o, fd = %d. %s\n", fname, @@ -139,33 +141,21 @@ 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)) { - DEBUG(10,("open_file: truncate requested on read-only open for file %s\n",fname )); + if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) local_flags = (flags & ~O_ACCMODE)|O_RDWR; - } - - if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - (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. - */ + /* + * 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; + 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. - */ + /* actually do the open */ - if (VALID_STAT(*psbuf) && S_ISFIFO(psbuf->st_mode)) - local_flags |= O_NONBLOCK; -#endif + if ((desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || + (local_flags & O_CREAT)) { - /* actually do the open */ fsp->fd = fd_open(conn, fname, local_flags, mode); if (fsp->fd == -1) { @@ -226,7 +216,15 @@ static BOOL open_file(files_struct *fsp,connection_struct *conn, fsp->is_directory = False; fsp->directory_delete_on_close = False; fsp->conn = conn; + /* + * Note that the file name here is the *untranslated* name + * ie. it is still in the DOS codepage sent from the client. + * All use of this filename will pass though the sys_xxxx + * functions which will do the dos_to_unix translation before + * mapping into a UNIX filename. JRA. + */ string_set(&fsp->fsp_name,fname); + fsp->wbmpx_ptr = NULL; fsp->wcp = NULL; /* Write cache pointer. */ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", @@ -262,7 +260,7 @@ return True if the filename is one of the special executable types ********************************************************************/ static BOOL is_executable(const char *fname) { - if ((fname = strrchr_m(fname,'.'))) { + if ((fname = strrchr(fname,'.'))) { if (strequal(fname,".com") || strequal(fname,".dll") || strequal(fname,".exe") || @@ -527,10 +525,10 @@ existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsign ****************************************************************************/ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T dev, - SMB_INO_T inode, - uint32 desired_access, - int share_mode, int *p_flags, int *p_oplock_request, - BOOL *p_all_current_opens_are_level_II) + SMB_INO_T inode, + uint32 desired_access, + int share_mode, int *p_flags, int *p_oplock_request, + BOOL *p_all_current_opens_are_level_II) { int i; int num_share_modes; @@ -538,28 +536,28 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T share_mode_entry *old_shares = 0; BOOL fcbopen = False; BOOL broke_oplock; - + if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB) fcbopen = True; - + num_share_modes = get_share_modes(conn, dev, inode, &old_shares); - + if(num_share_modes == 0) return 0; - + /* * Check if the share modes will give us access. */ - + do { share_mode_entry broken_entry; - + broke_oplock = False; *p_all_current_opens_are_level_II = True; - + for(i = 0; i < num_share_modes; i++) { share_mode_entry *share_entry = &old_shares[i]; - + /* * By observation of NetBench, oplocks are broken *before* share * modes are checked. This allows a file to be closed by the client @@ -567,23 +565,23 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T * Check if someone has an oplock on this file. If so we must break * it before continuing. */ - + if((*p_oplock_request && EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) || - (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) { - + (!*p_oplock_request && (share_entry->op_type != NO_OPLOCK))) { + BOOL opb_ret; DEBUG(5,("open_mode_check: oplock_request = %d, breaking oplock (%x) on file %s, \ dev = %x, inode = %.0f\n", *p_oplock_request, share_entry->op_type, fname, (unsigned int)dev, (double)inode)); - + /* Oplock break - unlock to request it. */ unlock_share_entry(conn, dev, inode); - + opb_ret = request_oplock_break(share_entry); - + /* Now relock. */ lock_share_entry(conn, dev, inode); - + if(opb_ret == False) { DEBUG(0,("open_mode_check: FAILED when breaking oplock (%x) on file %s, \ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (double)inode)); @@ -593,85 +591,84 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou unix_ERR_code = ERRbadshare; return -1; } - + broke_oplock = True; broken_entry = *share_entry; break; - + } else if (!LEVEL_II_OPLOCK_TYPE(share_entry->op_type)) { *p_all_current_opens_are_level_II = False; } - + /* someone else has a share lock on it, check to see if we can too */ - if (!check_share_mode(conn, share_entry, share_mode, desired_access, + if (!check_share_mode(conn, share_entry, share_mode, desired_access, fname, fcbopen, p_flags)) { SAFE_FREE(old_shares); errno = EACCES; return -1; - } - + } + } /* end for */ - + if(broke_oplock) { SAFE_FREE(old_shares); num_share_modes = get_share_modes(conn, dev, inode, &old_shares); oplock_contention_count++; - + /* Paranoia check that this is no longer an exlusive entry. */ for(i = 0; i < num_share_modes; i++) { share_mode_entry *share_entry = &old_shares[i]; - + if (share_modes_identical(&broken_entry, share_entry) && - EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { - + EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type) ) { + /* * This should not happen. The target left this oplock * as exlusive.... The process *must* be dead.... */ - + DEBUG(0,("open_mode_check: exlusive oplock left by process %d after break ! For file %s, \ dev = %x, inode = %.0f. Deleting it to continue...\n", (int)broken_entry.pid, fname, (unsigned int)dev, (double)inode)); - + if (process_exists(broken_entry.pid)) { - DEBUG(0,("open_mode_check: Existent process %d left active oplock.\n", - broken_entry.pid )); + DEBUG(0,("open_mode_check: Existent process %u left active oplock.\n", + (unsigned int)broken_entry.pid )); } - + if (del_share_entry(dev, inode, &broken_entry, NULL) == -1) { errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; return -1; } - + /* * We must reload the share modes after deleting the * other process's entry. */ - + SAFE_FREE(old_shares); num_share_modes = get_share_modes(conn, dev, inode, &old_shares); break; } } /* end for paranoia... */ } /* end if broke_oplock */ - + } while(broke_oplock); - - if(old_shares != 0) - SAFE_FREE(old_shares); - + + SAFE_FREE(old_shares); + /* * Refuse to grant an oplock in case the contention limit is * reached when going through the lock list multiple times. */ - + if(oplock_contention_count >= lp_oplock_contention_limit(SNUM(conn))) { *p_oplock_request = 0; DEBUG(4,("open_mode_check: oplock contention = %d. Not granting oplock.\n", - oplock_contention_count )); + oplock_contention_count )); } - + return num_share_modes; } @@ -692,50 +689,24 @@ static void kernel_flock(files_struct *fsp, int deny_mode) } -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; -} - /**************************************************************************** - Open a file with a share mode. On output from this open we are guarenteeing - that + Open a file with a share mode - old method. ****************************************************************************/ + files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, - int share_mode,int ofun, mode_t mode,int oplock_request, - int *Access,int *action) + int share_mode,int ofun, mode_t mode,int oplock_request, int *Access,int *action) { - return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, mode, - oplock_request, Access, action); + return open_file_shared1(conn, fname, psbuf, 0, share_mode, ofun, mode, + oplock_request, Access, action); } /**************************************************************************** - Open a file with a share mode. On output from this open we are guarenteeing - that + Open a file with a share mode - called from NTCreateAndX. ****************************************************************************/ + files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_STAT *psbuf, - uint32 desired_access, - int share_mode,int ofun, mode_t mode,int oplock_request, + uint32 desired_access, + int share_mode,int ofun, mode_t mode,int oplock_request, int *Access,int *action) { int flags=0; @@ -756,8 +727,8 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ uint16 port = 0; if (conn->printer) { - /* printers are handled completely differently. Most of the passed parameters are - ignored */ + /* printers are handled completely differently. Most + of the passed parameters are ignored */ if (Access) *Access = DOS_OPEN_WRONLY; if (action) @@ -811,17 +782,6 @@ 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; @@ -884,10 +844,10 @@ files_struct *open_file_shared1(connection_struct *conn,char *fname, SMB_STRUCT_ lock_share_entry(conn, dev, inode); - num_share_modes = open_mode_check(conn, fname, dev, inode, - desired_access, - share_mode, - &flags, &oplock_request, &all_current_opens_are_level_II); + num_share_modes = open_mode_check(conn, fname, dev, inode, + desired_access, share_mode, + &flags, &oplock_request, &all_current_opens_are_level_II); + if(num_share_modes == -1) { /* @@ -925,7 +885,7 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", */ if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && - (def_acl = directory_has_default_acl(conn, parent_dirname(fname)))) + (def_acl = directory_has_default_acl(conn, dos_to_unix_static(parent_dirname(fname))))) mode = 0777; DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", @@ -960,10 +920,9 @@ flags=0x%X flags2=0x%X mode=0%o returned %d\n", lock_share_entry_fsp(fsp); - num_share_modes = open_mode_check(conn, fname, dev, inode, - desired_access, - share_mode, - &flags, &oplock_request, &all_current_opens_are_level_II); + num_share_modes = open_mode_check(conn, fname, dev, inode, + desired_access, share_mode, + &flags, &oplock_request, &all_current_opens_are_level_II); if(num_share_modes == -1) { unlock_share_entry_fsp(fsp); @@ -1213,7 +1172,7 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST */ if(!got_stat) { - DEBUG(3,("open_directory: unable to stat name = %s. Error was %s\n", + DEBUG(0,("open_directory: unable to stat name = %s. Error was %s\n", fname, strerror(errno) )); file_free(fsp); return NULL; @@ -1252,7 +1211,6 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST fsp->is_directory = True; fsp->directory_delete_on_close = False; fsp->conn = conn; - string_set(&fsp->fsp_name,fname); if (delete_on_close) { NTSTATUS result = set_delete_on_close_internal(fsp, delete_on_close); @@ -1262,6 +1220,17 @@ files_struct *open_directory(connection_struct *conn, char *fname, SMB_STRUCT_ST return NULL; } } + + /* + * Note that the file name here is the *untranslated* name + * ie. it is still in the DOS codepage sent from the client. + * All use of this filename will pass though the sys_xxxx + * functions which will do the dos_to_unix translation before + * mapping into a UNIX filename. JRA. + */ + string_set(&fsp->fsp_name,fname); + fsp->wbmpx_ptr = NULL; + conn->num_files_open++; return fsp; |