static BOOL check_share_mode(connection_struct *conn, share_mode_entry *share, int share_mode, uint32 desired_access, const char *fname, BOOL fcbopen, int *flags) { int deny_mode = GET_DENY_MODE(share_mode); int old_open_mode = GET_OPEN_MODE(share->share_mode); int old_deny_mode = GET_DENY_MODE(share->share_mode); /* * share modes = false means don't bother to check for * DENY mode conflict. This is a *really* bad idea :-). JRA. */ if(!lp_share_modes(SNUM(conn))) return True; /* * Don't allow any opens once the delete on close flag has been * set. */ if (GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) { DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n", fname )); /* Use errno to map to correct error. */ unix_ERR_class = SMB_SUCCESS; unix_ERR_code = 0; unix_ERR_ntstatus = NT_STATUS_OK; return False; } /* this is a nasty hack, but necessary until we rewrite our open handling to use a NTCreateX call as the basic call. NT may open a file with neither read nor write access, and in this case it expects the open not to conflict with any existing deny modes. This happens (for example) during a "xcopy /o" where the second file descriptor is used for ACL sets (tridge) */ /* * This is a bit wierd - the test for desired access not having the * critical bits seems seems odd. Firstly, if both opens have no * critical bits then always ignore. Then check the "allow delete" * then check for either. This probably isn't quite right yet but * gets us much closer. JRA. */ /* * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE * and the existing desired_acces then share modes don't conflict. */ if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) && !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { /* * Wrinkle discovered by smbtorture.... * If both are non-io open and requester is asking for delete and current open has delete access * but neither open has allowed file share delete then deny.... this is very strange and * seems to be the only case in which non-io opens conflict. JRA. */ if ((desired_access & DELETE_ACCESS) && (share->desired_access & DELETE_ACCESS) && (!GET_ALLOW_SHARE_DELETE(share->share_mode) || !GET_ALLOW_SHARE_DELETE(share_mode))) { DEBUG(5,("check_share_mode: Failing open on file %s as delete access requests conflict.\n", fname )); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return False; } DEBUG(5,("check_share_mode: Allowing open on file %s as both desired access (0x%x) \ and existing desired access (0x%x) are non-data opens\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); return True; } /* * If delete access was requested and the existing share mode doesn't have * ALLOW_SHARE_DELETE then deny. */ if ((desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) { DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n", fname )); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return False; } /* * The inverse of the above. * If delete access was granted and the new share mode doesn't have * ALLOW_SHARE_DELETE then deny. */ if ((share->desired_access & DELETE_ACCESS) && !GET_ALLOW_SHARE_DELETE(share_mode)) { DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n", fname )); unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; unix_ERR_ntstatus = NT_STATUS_SHARING_VIOLATION; return False; } /* * If desired_access doesn't contain READ_DATA,WRITE_DATA,APPEND_DATA or EXECUTE * then share modes don't conflict. Likewise with existing desired access. */ if ( !(desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || !(share->desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ) { DEBUG(5,("check_share_mode: Allowing open on file %s as desired access (0x%x) doesn't conflict with\ existing desired access (0x%x).\n", fname, (unsigned int)desired_access, (unsigned int)share->desired_access )); return True; }
static void print_share_mode(share_mode_entry *e, char *fname) { static int count; if (count==0) { d_printf("Locked files:\n"); d_printf("Pid DenyMode Access R/W Oplock Name\n"); d_printf("--------------------------------------------------------------\n"); } count++; if (Ucrit_checkPid(e->pid)) { d_printf("%-5d ",(int)e->pid); switch (GET_DENY_MODE(e->share_mode)) { case DENY_NONE: d_printf("DENY_NONE "); break; case DENY_ALL: d_printf("DENY_ALL "); break; case DENY_DOS: d_printf("DENY_DOS "); break; case DENY_READ: d_printf("DENY_READ "); break; case DENY_WRITE: printf("DENY_WRITE "); break; case DENY_FCB: d_printf("DENY_FCB "); break; } d_printf("0x%-8x ",(unsigned int)e->desired_access); switch (e->share_mode&0xF) { case 0: d_printf("RDONLY "); break; case 1: d_printf("WRONLY "); break; case 2: d_printf("RDWR "); break; } if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) d_printf("EXCLUSIVE+BATCH "); else if (e->op_type & EXCLUSIVE_OPLOCK) d_printf("EXCLUSIVE "); else if (e->op_type & BATCH_OPLOCK) d_printf("BATCH "); else if (e->op_type & LEVEL_II_OPLOCK) d_printf("LEVEL_II "); else d_printf("NONE "); d_printf(" %s %s",fname, asctime(LocalTime((time_t *)&e->time.tv_sec))); } }