📄 open.c
字号:
return True;}/* Map generic permissions to file object specific permissions */ struct generic_mapping file_generic_mapping = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_GENERIC_ALL};/**************************************************************************** Open a file with a share mode.****************************************************************************/files_struct *open_file_ntcreate(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ uint32 share_access, /* share constants (FILE_SHARE_READ etc). */ uint32 create_disposition, /* FILE_OPEN_IF etc. */ uint32 create_options, /* options such as delete on close. */ uint32 new_dos_attributes, /* attributes used for new file. */ int oplock_request, /* internal Samba oplock codes. */ /* Information (FILE_EXISTS etc.) */ int *pinfo){ int flags=0; int flags2=0; BOOL file_existed = VALID_STAT(*psbuf); BOOL def_acl = False; BOOL internal_only_open = False; SMB_DEV_T dev = 0; SMB_INO_T inode = 0; BOOL fsp_open = False; files_struct *fsp = NULL; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; int info; uint32 existing_dos_attributes = 0; struct pending_message_list *pml = NULL; uint16 mid = get_current_mid(); BOOL delayed_for_oplocks = False; struct timeval request_time = timeval_zero(); struct share_mode_lock *lck = NULL; NTSTATUS status; if (conn->printer) { /* * Printers are handled completely differently. * Most of the passed parameters are ignored. */ if (pinfo) { *pinfo = FILE_WAS_CREATED; } DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); return print_fsp_open(conn, fname); } /* We add aARCH to this as this mode is only used if the file is * created new. */ unx_mode = unix_mode(conn, new_dos_attributes | aARCH,fname, True); DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x " "access_mask=0x%x share_access=0x%x " "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, oplock_request)); if (oplock_request == INTERNAL_OPEN_ONLY) { internal_only_open = True; oplock_request = 0; } if ((pml = get_open_deferred_message(mid)) != NULL) { struct deferred_open_record *state = (struct deferred_open_record *)pml->private_data.data; request_time = pml->request_time; delayed_for_oplocks = state->delayed_for_oplocks; /* There could be a race condition where the dev/inode pair has changed since we deferred the message. If so, just remove the deferred open entry and return sharing violation. */ /* If the timeout value is non-zero, we need to just return sharing violation. Don't retry the open as we were not notified of a close and we don't want to trigger another spurious oplock break. */ /* Now remove the deferred open entry under lock. */ lck = get_share_mode_lock(NULL, state->dev, state->inode, NULL, NULL); if (lck == NULL) { DEBUG(0, ("could not get share mode lock\n")); } else { del_deferred_open_entry(lck, mid); talloc_destroy(lck); } /* Ensure we don't reprocess this message. */ remove_deferred_open_smb_message(mid); } if (!check_name(fname,conn)) { return NULL; } new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; if (file_existed) { existing_dos_attributes = dos_mode(conn, fname, psbuf); } /* ignore any oplock requests if oplocks are disabled */ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break || IS_VETO_OPLOCK_PATH(conn, fname)) { oplock_request = 0; } /* this is for OS/2 long file names - say we don't support them */ if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) { /* OS/2 Workplace shell fix may be main code stream in a later * release. */ set_saved_error_triple(ERRDOS, ERRcannotopen, NT_STATUS_OBJECT_NAME_NOT_FOUND); DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not " "supported.\n")); return NULL; } switch( create_disposition ) { /* * Currently we're using FILE_SUPERSEDE as the same as * FILE_OVERWRITE_IF but they really are * different. FILE_SUPERSEDE deletes an existing file * (requiring delete access) then recreates it. */ case FILE_SUPERSEDE: /* If file exists replace/overwrite. If file doesn't * exist create. */ flags2 |= (O_CREAT | O_TRUNC); break; case FILE_OVERWRITE_IF: /* If file exists replace/overwrite. If file doesn't * exist create. */ flags2 |= (O_CREAT | O_TRUNC); break; case FILE_OPEN: /* If file exists open. If file doesn't exist error. */ if (!file_existed) { DEBUG(5,("open_file_ntcreate: FILE_OPEN " "requested for file %s and file " "doesn't exist.\n", fname )); set_saved_ntstatus(NT_STATUS_OBJECT_NAME_NOT_FOUND); errno = ENOENT; return NULL; } break; case FILE_OVERWRITE: /* If file exists overwrite. If file doesn't exist * error. */ if (!file_existed) { DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE " "requested for file %s and file " "doesn't exist.\n", fname )); set_saved_ntstatus(NT_STATUS_OBJECT_NAME_NOT_FOUND); errno = ENOENT; return NULL; } flags2 |= O_TRUNC; break; case FILE_CREATE: /* If file exists error. If file doesn't exist * create. */ if (file_existed) { DEBUG(5,("open_file_ntcreate: FILE_CREATE " "requested for file %s and file " "already exists.\n", fname )); if (S_ISDIR(psbuf->st_mode)) { errno = EISDIR; } else { errno = EEXIST; } return NULL; } flags2 |= (O_CREAT|O_EXCL); break; case FILE_OPEN_IF: /* If file exists open. If file doesn't exist * create. */ flags2 |= O_CREAT; break; default: set_saved_ntstatus(NT_STATUS_INVALID_PARAMETER); return NULL; } /* We only care about matching attributes on file exists and * overwrite. */ if (file_existed && ((create_disposition == FILE_OVERWRITE) || (create_disposition == FILE_OVERWRITE_IF))) { if (!open_match_attributes(conn, fname, existing_dos_attributes, new_dos_attributes, psbuf->st_mode, unx_mode, &new_unx_mode)) { DEBUG(5,("open_file_ntcreate: attributes missmatch " "for file %s (%x %x) (0%o, 0%o)\n", fname, existing_dos_attributes, new_dos_attributes, (unsigned int)psbuf->st_mode, (unsigned int)unx_mode )); errno = EACCES; return NULL; } } /* This is a nasty hack - must fix... JRA. */ if (access_mask == MAXIMUM_ALLOWED_ACCESS) { access_mask = FILE_GENERIC_ALL; } /* * Convert GENERIC bits to specific bits. */ se_map_generic(&access_mask, &file_generic_mapping); DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping " "access_mask=0x%x\n", fname, access_mask )); /* * Note that we ignore the append flag as append does not * mean the same thing under DOS and Unix. */ if (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) { flags = O_RDWR; } else { flags = O_RDONLY; } /* * Currently we only look at FILE_WRITE_THROUGH for create options. */#if defined(O_SYNC) if (create_options & FILE_WRITE_THROUGH) { flags2 |= O_SYNC; }#endif /* O_SYNC */ if (!CAN_WRITE(conn)) { /* * We should really return a permission denied error if either * O_CREAT or O_TRUNC are set, but for compatibility with * older versions of Samba we just AND them out. */ flags2 &= ~(O_CREAT|O_TRUNC); } /* * Ensure we can't write on a read-only share or file. */ if (flags != O_RDONLY && file_existed && (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) { DEBUG(5,("open_file_ntcreate: write access requested for " "file %s on read only %s\n", fname, !CAN_WRITE(conn) ? "share" : "file" )); set_saved_ntstatus(NT_STATUS_ACCESS_DENIED); errno = EACCES; return NULL; } fsp = file_new(conn); if(!fsp) { return NULL; } fsp->dev = psbuf->st_dev; fsp->inode = psbuf->st_ino; fsp->share_access = share_access; fsp->fh->private_options = create_options; fsp->access_mask = access_mask; fsp->oplock_type = oplock_request; if (timeval_is_zero(&request_time)) { request_time = fsp->open_time; } if (file_existed) { dev = psbuf->st_dev; inode = psbuf->st_ino; lck = get_share_mode_lock(NULL, dev, inode, conn->connectpath, fname); if (lck == NULL) { DEBUG(0, ("Could not get share mode lock\n")); set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION); return NULL; } if (delay_for_oplocks(lck, fsp)) { struct deferred_open_record state; struct timeval timeout; if (delayed_for_oplocks) { DEBUG(0, ("Trying to delay for oplocks " "twice\n")); exit_server("exiting"); } timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0); /* Normally the smbd we asked should respond within * OPLOCK_BREAK_TIMEOUT seconds regardless of whether * the client did, give twice the timeout as a safety * measure here in case the other smbd is stuck * somewhere else. */ state.delayed_for_oplocks = True; state.dev = dev; state.inode = inode; if (!request_timed_out(request_time, timeout)) { defer_open(lck, request_time, timeout, &state); } talloc_free(lck); return NULL; } status = open_mode_check(conn, fname, lck, access_mask, share_access, create_options, &file_existed); if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) { /* DELETE_PENDING is not deferred for a second */ set_saved_ntstatus(status); talloc_free(lck); file_free(fsp); return NULL; } if (!NT_STATUS_IS_OK(status)) { SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)); /* Check if this can be done with the deny_dos and fcb * calls. */ if (create_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { files_struct *fsp_dup; fsp_dup = fcb_or_dos_open(conn, fname, dev, inode, access_mask, share_access, create_options); if (fsp_dup) { talloc_free(lck); file_free(fsp); if (pinfo) { *pinfo = FILE_WAS_OPENED; } conn->num_files_open++; return fsp_dup; } } /* * This next line is a subtlety we need for * MS-Access. If a file open will fail due to share * permissions and also for security (access) reasons, * we need to return the access failed error, not the * share error. This means we must attempt to open the * file anyway in order to get the UNIX access error - * even if we're going to fail the open for share * reasons. This is bad, as we're burning another fd * if there are existing locks but there's nothing * else we can do. We also ensure we're not going to * create or tuncate the file as we only want an * access decision at this stage. JRA. */ errno = 0; fsp_open = open_file(fsp,conn,fname,psbuf, flags|(flags2&~(O_TRUNC|O_CREAT)), unx_mode,access_mask); DEBUG(4,("open_file_ntcreate : share_mode deny - " "calling open_file with flags=0x%X " "flags2=0x%X mode=0%o returned %d\n", flags, (flags2&~(O_TRUNC|O_CREAT)), (unsigned int)unx_mode, (int)fsp_open )); if (!fsp_open && errno) { /* Default error. */ set_saved_ntstatus(NT_STATUS_ACCESS_DENIED); } /* * If we're returning a share violation, ensure we * cope with the braindead 1 second delay. */ if (!internal_only_open && lp_defer_sharing_violations()) { struct timeval timeout; struct deferred_open_record state; timeout = timeval_set(0, SHARING_VIOLATION_USEC_WAIT); state.delayed_for_oplocks = False; state.dev = dev; state.inode = inode; if (!request_timed_out(request_time, timeout)) { defer_open(lck, request_time, timeout, &state); } } talloc_free(lck); if (fsp_open) { fd_close(conn, fsp); /* * We have detected a sharing violation here * so return the correct error code */ set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION); } file_free(fsp); return NULL; } /* * We exit this block with the share entry *locked*..... */ } SMB_ASSERT(!file_existed || (lck != NULL)); /* * Ensure we pay attention to default ACLs on directories if required. */ if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && (def_acl = directory_has_default_acl(conn, parent_dirname(fname)))) { unx_mode = 0777; } DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", (unsigned int)flags, (unsigned int)flags2, (unsigned int)unx_mode)); /* * open_file strips any O_TRUNC flags itself. */ fsp_open = open_file(fsp,conn,fname,psbuf,flags|flags2,unx_mode, access_mask); if (!fsp_open) { if (lck != NULL) { talloc_free(lck); } file_free(fsp); return NULL; } if (!file_existed) { /* * Deal with the race condition where two smbd's detect the * file doesn't exist and do the create at the same time. One * of them will win and set a share mode, the other (ie. this * one) should check if the requested share mode for this * create is allowed. */ /* * Now the file exists and fsp is successfully opened, * fsp->dev and fsp->inode are valid and should replace the * dev=0,inode=0 from a non existent file. Spotted by * Nadav Danieli <nadavd@exanet.com>. JRA. */ dev = fsp->dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -