示例#1
0
文件: locking.c 项目: rchicoli/samba
static struct share_mode_entry *find_share_mode_entry(struct share_mode_data *d,
						      struct share_mode_entry *entry)
{
	int i;

	for (i=0; i<d->num_share_modes; i++) {
		struct share_mode_entry *e = &d->share_modes[i];
		if (is_valid_share_mode_entry(entry) &&
		    is_valid_share_mode_entry(e) &&
		    share_modes_identical(e, entry)) {
			return e;
		}
	}
	return NULL;
}
示例#2
0
static void print_share_mode(const struct share_mode_entry *e,
			     const char *sharepath,
			     const char *fname,
			     void *dummy)
{
	char           *utf8_fname;
	int deny_mode;

	if (!is_valid_share_mode_entry(e)) {
		return;
	}

	deny_mode = map_share_mode_to_deny_mode(e->share_access,
						    e->private_options);

	printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid)));
	printf("<td>%u</td>",(unsigned int)e->uid);
	printf("<td>");
	switch ((deny_mode>>4)&0xF) {
	case DENY_NONE: printf("DENY_NONE"); break;
	case DENY_ALL:  printf("DENY_ALL   "); break;
	case DENY_DOS:  printf("DENY_DOS   "); break;
	case DENY_FCB:  printf("DENY_FCB   "); break;
	case DENY_READ: printf("DENY_READ  "); break;
	case DENY_WRITE:printf("DENY_WRITE "); break;
	}
	printf("</td>");

	printf("<td>");
	if (e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA)) {
		printf("%s", _("RDWR       "));
	} else if (e->access_mask & FILE_WRITE_DATA) {
		printf("%s", _("WRONLY     "));
	} else {
		printf("%s", _("RDONLY     "));
	}
	printf("</td>");

	printf("<td>");
	if((e->op_type & 
	    (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == 
	   (EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
		printf("EXCLUSIVE+BATCH ");
	else if (e->op_type & EXCLUSIVE_OPLOCK)
		printf("EXCLUSIVE       ");
	else if (e->op_type & BATCH_OPLOCK)
		printf("BATCH           ");
	else if (e->op_type & LEVEL_II_OPLOCK)
		printf("LEVEL_II        ");
	else
		printf("NONE            ");
	printf("</td>");

	push_utf8_allocate(&utf8_fname, fname);
	printf("<td>%s</td><td>%s</td></tr>\n",
	       utf8_fname,tstring(talloc_tos(),e->time.tv_sec));
	SAFE_FREE(utf8_fname);
}
示例#3
0
文件: status.c 项目: srimalik/samba
static void print_share_mode(const struct share_mode_entry *e,
			     const char *sharepath,
			     const char *fname,
			     void *dummy)
{
	static int count;

	if (!is_valid_share_mode_entry(e)) {
		return;
	}

	if (!process_exists(e->pid)) {
		return;
	}

	if (count==0) {
		d_printf("Locked files:\n");
		d_printf("Pid          Uid        DenyMode   Access      R/W        Oplock           SharePath   Name   Time\n");
		d_printf("--------------------------------------------------------------------------------------------------\n");
	}
	count++;

	if (Ucrit_checkPid(e->pid)) {
		d_printf("%-11s  ",procid_str_static(&e->pid));
		d_printf("%-9u  ", (unsigned int)e->uid);
		switch (map_share_mode_to_deny_mode(e->share_access,
						    e->private_options)) {
			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;
			default: {
				d_printf("unknown-please report ! "
					 "e->share_access = 0x%x, "
					 "e->private_options = 0x%x\n",
					 (unsigned int)e->share_access,
					 (unsigned int)e->private_options );
				break;
			}
		}
		d_printf("0x%-8x  ",(unsigned int)e->access_mask);
		if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
				(FILE_READ_DATA|FILE_WRITE_DATA)) {
			d_printf("RDWR       ");
		} else if (e->access_mask & FILE_WRITE_DATA) {
			d_printf("WRONLY     ");
		} else {
			d_printf("RDONLY     ");
		}

		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   %s",sharepath, fname, time_to_asc((time_t)e->time.tv_sec));
	}
}
示例#4
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
					enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	struct server_id self = messaging_server_id(conn->sconn->msg_ctx);
	bool delete_file = false;
	bool changed_user = false;
	struct share_mode_lock *lck = NULL;
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS tmp_status;
	struct file_id id;
	const struct security_unix_token *del_token = NULL;
	const struct security_token *del_nt_token = NULL;
	bool got_tokens = false;
	bool normal_close;
	int ret_flock, retries = 1;

	/* Ensure any pending write time updates are done. */
	if (fsp->update_write_time_event) {
		update_write_time_handler(fsp->conn->sconn->ev_ctx,
					fsp->update_write_time_event,
					timeval_current(),
					(void *)fsp);
	}

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
	if (lck == NULL) {
		DEBUG(0, ("close_remove_share_mode: Could not get share mode "
			  "lock for file %s\n", fsp_str_dbg(fsp)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp->write_time_forced) {
		DEBUG(10,("close_remove_share_mode: write time forced "
			"for file %s\n",
			fsp_str_dbg(fsp)));
		set_close_write_time(fsp, lck->data->changed_write_time);
	} else if (fsp->update_write_time_on_close) {
		/* Someone had a pending write. */
		if (null_timespec(fsp->close_write_time)) {
			DEBUG(10,("close_remove_share_mode: update to current time "
				"for file %s\n",
				fsp_str_dbg(fsp)));
			/* Update to current time due to "normal" write. */
			set_close_write_time(fsp, timespec_current());
		} else {
			DEBUG(10,("close_remove_share_mode: write time pending "
				"for file %s\n",
				fsp_str_dbg(fsp)));
			/* Update to time set on close call. */
			set_close_write_time(fsp, fsp->close_write_time);
		}
	}

	if (fsp->initial_delete_on_close &&
			!is_delete_on_close_set(lck, fsp->name_hash)) {
		bool became_user = False;

		/* Initial delete on close was set and no one else
		 * wrote a real delete on close. */

		if (get_current_vuid(conn) != fsp->vuid) {
			become_user(conn, fsp->vuid);
			became_user = True;
		}
		fsp->delete_on_close = true;
		set_delete_on_close_lck(fsp, lck,
				get_current_nttok(conn),
				get_current_utok(conn));
		if (became_user) {
			unbecome_user();
		}
	}

	delete_file = is_delete_on_close_set(lck, fsp->name_hash);

	if (delete_file) {
		int i;
		/* See if others still have the file open via this pathname.
		   If this is the case, then don't delete. If all opens are
		   POSIX delete now. */
		for (i=0; i<lck->data->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->data->share_modes[i];

			if (!is_valid_share_mode_entry(e)) {
				continue;
			}
			if (e->name_hash != fsp->name_hash) {
				continue;
			}
			if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN)
			    && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
				continue;
			}
			if (serverid_equal(&self, &e->pid) &&
			    (e->share_file_id == fsp->fh->gen_id)) {
				continue;
			}
			if (share_mode_stale_pid(lck->data, i)) {
				continue;
			}
			delete_file = False;
			break;
		}
	}

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE);

	if (!normal_close || !delete_file) {
		status = NT_STATUS_OK;
		goto done;
	}

	/*
	 * Ok, we have to delete the file
	 */

	DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
		 "- deleting file.\n", fsp_str_dbg(fsp)));

	/*
	 * Don't try to update the write time when we delete the file
	 */
	fsp->update_write_time_on_close = false;

	got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
					&del_nt_token, &del_token);
	SMB_ASSERT(got_tokens);

	if (!unix_token_equal(del_token, get_current_utok(conn))) {
		/* Become the user who requested the delete. */

		DEBUG(5,("close_remove_share_mode: file %s. "
			"Change user to uid %u\n",
			fsp_str_dbg(fsp),
			(unsigned int)del_token->uid));

		if (!push_sec_ctx()) {
			smb_panic("close_remove_share_mode: file %s. failed to push "
				  "sec_ctx.\n");
		}

		set_sec_ctx(del_token->uid,
			    del_token->gid,
			    del_token->ngroups,
			    del_token->groups,
			    del_nt_token);

		changed_user = true;
	}

	/* We can only delete the file if the name we have is still valid and
	   hasn't been renamed. */

	tmp_status = vfs_stat_fsp(fsp);
	if (!NT_STATUS_IS_OK(tmp_status)) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and stat failed with error %s\n",
			 fsp_str_dbg(fsp), nt_errstr(tmp_status)));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);

	if (!file_id_equal(&fsp->file_id, &id)) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and dev and/or inode does not match\n",
			 fsp_str_dbg(fsp)));
		DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
			 "stat file_id %s\n",
			 fsp_str_dbg(fsp),
			 file_id_string_tos(&fsp->file_id),
			 file_id_string_tos(&id)));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
	    && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

		status = delete_all_streams(conn, fsp->fsp_name->base_name);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(5, ("delete_all_streams failed: %s\n",
				  nt_errstr(status)));
			goto done;
		}
	}

retry_delete:
	/* temporary files with delete on close set will not be deleted on a
	 * cifs share using a netapp backend since they are opened with
	 * read + write access mask.
	 * close the file to allow the delete.
	 */
	if (fsp->can_write && !S_ISDIR(fsp->fsp_name->st.st_ex_mode) &&
	    fsp->fh->ref_count == 1 && retries) {
		status = fd_close(fsp);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3, ("close_remove_share_mode: Error %s closing %s\n",
				nt_errstr(status),
				smb_fname_str_dbg(fsp->fsp_name)));
			goto skip_retry;
		}
		if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
			/*
			* This call can potentially fail as another smbd may
			* have had the file open with delete on close set and
			* deleted it when its last reference to this file
			* went away. Hence we log this but not at debug level
			* zero.
			*/

			DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
				 "was set and unlink failed with error %s\n",
				 fsp_str_dbg(fsp), strerror(errno)));

			status = map_nt_error_from_unix(errno);
			retries = 0;
			goto retry_delete;
		}
	} else {
		if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
			/*
			 * This call can potentially fail as another smbd may
			 * have had the file open with delete on close set and
			 * deleted it when its last reference to this file
			 * went away. Hence we log this but not at debug level
			 * zero.
			 */

			DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
				 "was set and unlink failed with error %s\n",
				 fsp_str_dbg(fsp), strerror(errno)));

			status = map_nt_error_from_unix(errno);
		}
	}

	/* As we now have POSIX opens which can unlink
 	 * with other open files we may have taken
 	 * this code path with more than one share mode
 	 * entry - ensure we only delete once by resetting
 	 * the delete on close flag. JRA.
 	 */

skip_retry:
	fsp->delete_on_close = false;
	reset_delete_on_close_lck(fsp, lck);

 done:

	if (changed_user) {
		/* unbecome user. */
		pop_sec_ctx();
	}

	/* remove filesystem sharemodes */
	ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, 0, 0);
	if (ret_flock == -1) {
		DEBUG(2, ("close_remove_share_mode: removing kernel flock for "
					"%s failed: %s\n", fsp_str_dbg(fsp),
					strerror(errno)));
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_remove_share_mode: Could not delete share "
			  "entry for file %s\n", fsp_str_dbg(fsp)));
	}

	TALLOC_FREE(lck);

	if (delete_file) {
		/*
		 * Do the notification after we released the share
		 * mode lock. Inside notify_fname we take out another
		 * tdb lock. With ctdb also accessing our databases,
		 * this can lead to deadlocks. Putting this notify
		 * after the TALLOC_FREE(lck) above we avoid locking
		 * two records simultaneously. Notifies are async and
		 * informational only, so calling the notify_fname
		 * without holding the share mode lock should not do
		 * any harm.
		 */
		notify_fname(conn, NOTIFY_ACTION_REMOVED,
			     FILE_NOTIFY_CHANGE_FILE_NAME,
			     fsp->fsp_name->base_name);
	}

	return status;
}
示例#5
0
static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
				enum file_close_type close_type)
{
	struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx);
	struct share_mode_lock *lck = NULL;
	bool delete_dir = False;
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS status1 = NT_STATUS_OK;
	const struct security_token *del_nt_token = NULL;
	const struct security_unix_token *del_token = NULL;
	NTSTATUS notify_status;

	if (fsp->conn->sconn->using_smb2) {
		notify_status = STATUS_NOTIFY_CLEANUP;
	} else {
		notify_status = NT_STATUS_OK;
	}

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a directory also.
	 */

	lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
	if (lck == NULL) {
		DEBUG(0, ("close_directory: Could not get share mode lock for "
			  "%s\n", fsp_str_dbg(fsp)));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (fsp->initial_delete_on_close) {
		bool became_user = False;

		/* Initial delete on close was set - for
		 * directories we don't care if anyone else
		 * wrote a real delete on close. */

		if (get_current_vuid(fsp->conn) != fsp->vuid) {
			become_user(fsp->conn, fsp->vuid);
			became_user = True;
		}
		send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
					       fsp->fsp_name->base_name);
		set_delete_on_close_lck(fsp, lck,
				get_current_nttok(fsp->conn),
				get_current_utok(fsp->conn));
		fsp->delete_on_close = true;
		if (became_user) {
			unbecome_user();
		}
	}

	delete_dir = get_delete_on_close_token(lck, fsp->name_hash,
					&del_nt_token, &del_token);

	if (delete_dir) {
		int i;
		/* See if others still have the dir open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->data->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->data->share_modes[i];
			if (is_valid_share_mode_entry(e) &&
					e->name_hash == fsp->name_hash) {
				if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
				    (e->flags & SHARE_MODE_FLAG_POSIX_OPEN))
				{
					continue;
				}
				if (serverid_equal(&self, &e->pid) &&
				    (e->share_file_id == fsp->fh->gen_id)) {
					continue;
				}
				if (share_mode_stale_pid(lck->data, i)) {
					continue;
				}
				delete_dir = False;
				break;
			}
		}
	}

	if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
				delete_dir) {
	
		/* Become the user who requested the delete. */

		if (!push_sec_ctx()) {
			smb_panic("close_directory: failed to push sec_ctx.\n");
		}

		set_sec_ctx(del_token->uid,
				del_token->gid,
				del_token->ngroups,
				del_token->groups,
				del_nt_token);

		if (!del_share_mode(lck, fsp)) {
			DEBUG(0, ("close_directory: Could not delete share entry for "
				  "%s\n", fsp_str_dbg(fsp)));
		}

		TALLOC_FREE(lck);

		if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS)
		    && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

			status = delete_all_streams(fsp->conn, fsp->fsp_name->base_name);
			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(5, ("delete_all_streams failed: %s\n",
					  nt_errstr(status)));
				return status;
			}
		}

		status = rmdir_internals(talloc_tos(), fsp);

		DEBUG(5,("close_directory: %s. Delete on close was set - "
			 "deleting directory returned %s.\n",
			 fsp_str_dbg(fsp), nt_errstr(status)));

		/* unbecome user. */
		pop_sec_ctx();

		/*
		 * Ensure we remove any change notify requests that would
		 * now fail as the directory has been deleted.
		 */

		if (NT_STATUS_IS_OK(status)) {
			notify_status = NT_STATUS_DELETE_PENDING;
		}
	} else {
		if (!del_share_mode(lck, fsp)) {
			DEBUG(0, ("close_directory: Could not delete share entry for "
				  "%s\n", fsp_str_dbg(fsp)));
		}

		TALLOC_FREE(lck);
	}

	remove_pending_change_notify_requests_by_fid(fsp, notify_status);

	status1 = fd_close(fsp);

	if (!NT_STATUS_IS_OK(status1)) {
		DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
			  fsp_str_dbg(fsp), fsp->fh->fd, errno,
			  strerror(errno)));
	}

	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(req, fsp);

	if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
		status = status1;
	}
	return status;
}
示例#6
0
BOOL rename_share_filename(struct share_mode_lock *lck,
			const char *servicepath,
			const char *newname)
{
	size_t sp_len;
	size_t fn_len;
	size_t msg_len;
	char *frm = NULL;
	int i;

	if (!lck) {
		return False;
	}

	DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
		servicepath, newname));

	/*
	 * rename_internal_fsp() and rename_internals() add './' to
	 * head of newname if newname does not contain a '/'.
	 */
	while (newname[0] && newname[1] && newname[0] == '.' && newname[1] == '/') {
		newname += 2;
	}

	lck->servicepath = talloc_strdup(lck, servicepath);
	lck->filename = talloc_strdup(lck, newname);
	if (lck->filename == NULL || lck->servicepath == NULL) {
		DEBUG(0, ("rename_share_filename: talloc failed\n"));
		return False;
	}
	lck->modified = True;

	sp_len = strlen(lck->servicepath);
	fn_len = strlen(lck->filename);

	msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + fn_len + 1;

	/* Set up the name changed message. */
	frm = TALLOC(lck, msg_len);
	if (!frm) {
		return False;
	}

	SDEV_T_VAL(frm,0,lck->dev);
	SINO_T_VAL(frm,8,lck->ino);

	DEBUG(10,("rename_share_filename: msg_len = %u\n", (unsigned int)msg_len ));

	safe_strcpy(&frm[16], lck->servicepath, sp_len);
	safe_strcpy(&frm[16 + sp_len + 1], lck->filename, fn_len);

	/* Send the messages. */
	for (i=0; i<lck->num_share_modes; i++) {
		struct share_mode_entry *se = &lck->share_modes[i];
		if (!is_valid_share_mode_entry(se)) {
			continue;
		}
		/* But not to ourselves... */
		if (procid_is_me(&se->pid)) {
			continue;
		}

		DEBUG(10,("rename_share_filename: sending rename message to pid %u "
			"dev %x, inode  %.0f sharepath %s newname %s\n",
			(unsigned int)procid_to_pid(&se->pid),
			(unsigned int)lck->dev, (double)lck->ino,
			lck->servicepath, lck->filename ));

		become_root();
		message_send_pid(se->pid, MSG_SMB_FILE_RENAME,
				frm, msg_len, True);
		unbecome_root();
	}

	return True;
}
示例#7
0
static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type)
{
	struct share_mode_lock *lck = 0;
	BOOL delete_dir = False;
	NTSTATUS status = NT_STATUS_OK;

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a directory also.
	 */

	lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name));
	}

	if (fsp->initial_delete_on_close) {
		BOOL became_user = False;

		/* Initial delete on close was set - for
		 * directories we don't care if anyone else
		 * wrote a real delete on close. */

		if (current_user.vuid != fsp->vuid) {
			become_user(fsp->conn, fsp->vuid);
			became_user = True;
		}
		send_stat_cache_delete_message(fsp->fsp_name);
		set_delete_on_close_lck(lck, True, &current_user.ut);
		if (became_user) {
			unbecome_user();
		}
	}

	delete_dir = lck->delete_on_close;

	if (delete_dir) {
		int i;
		/* See if others still have the dir open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->share_modes[i];
			if (is_valid_share_mode_entry(e)) {
				if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
					continue;
				}
				delete_dir = False;
				break;
			}
		}
	}

	if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
				delete_dir &&
				lck->delete_token) {
	
		/* Become the user who requested the delete. */

		if (!push_sec_ctx()) {
			smb_panic("close_directory: failed to push sec_ctx.\n");
		}

		set_sec_ctx(lck->delete_token->uid,
				lck->delete_token->gid,
				lck->delete_token->ngroups,
				lck->delete_token->groups,
				NULL);

		TALLOC_FREE(lck);

		status = rmdir_internals(fsp->conn, fsp->fsp_name);

		DEBUG(5,("close_directory: %s. Delete on close was set - "
			 "deleting directory returned %s.\n",
			 fsp->fsp_name, nt_errstr(status)));

		/* unbecome user. */
		pop_sec_ctx();

		/*
		 * Ensure we remove any change notify requests that would
		 * now fail as the directory has been deleted.
		 */

		if(NT_STATUS_IS_OK(status)) {
			remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
		}
	} else {
		TALLOC_FREE(lck);
		remove_pending_change_notify_requests_by_fid(
			fsp, NT_STATUS_OK);
	}

	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(fsp);
	return status;
}
示例#8
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
					enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	BOOL delete_file = False;
	struct share_mode_lock *lck;
	SMB_STRUCT_STAT sbuf;
	NTSTATUS status = NT_STATUS_OK;
	int ret;

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_remove_share_mode: Could not get share mode "
			  "lock for file %s\n", fsp->fsp_name));
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_remove_share_mode: Could not delete share "
			  "entry for file %s\n", fsp->fsp_name));
	}

	if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
		BOOL became_user = False;

		/* Initial delete on close was set and no one else
		 * wrote a real delete on close. */

		if (current_user.vuid != fsp->vuid) {
			become_user(conn, fsp->vuid);
			became_user = True;
		}
		set_delete_on_close_lck(lck, True, &current_user.ut);
		if (became_user) {
			unbecome_user();
		}
	}

	delete_file = lck->delete_on_close;

	if (delete_file) {
		int i;
		/* See if others still have the file open. If this is the
		 * case, then don't delete. If all opens are POSIX delete now. */
		for (i=0; i<lck->num_share_modes; i++) {
			struct share_mode_entry *e = &lck->share_modes[i];
			if (is_valid_share_mode_entry(e)) {
				if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
					continue;
				}
				delete_file = False;
				break;
			}
		}
	}

	/* Notify any deferred opens waiting on this close. */
	notify_deferred_opens(lck);
	reply_to_oplock_break_requests(fsp);

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
	    || !delete_file
	    || (lck->delete_token == NULL)) {
		TALLOC_FREE(lck);
		return NT_STATUS_OK;
	}

	/*
	 * Ok, we have to delete the file
	 */

	DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
		 "- deleting file.\n", fsp->fsp_name));

	/* Become the user who requested the delete. */

	if (!push_sec_ctx()) {
		smb_panic("close_remove_share_mode: file %s. failed to push "
			  "sec_ctx.\n");
	}

	set_sec_ctx(lck->delete_token->uid,
		    lck->delete_token->gid,
		    lck->delete_token->ngroups,
		    lck->delete_token->groups,
		    NULL);

	/* We can only delete the file if the name we have is still valid and
	   hasn't been renamed. */

	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 != 0) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and stat failed with error %s\n",
			 fsp->fsp_name, strerror(errno) ));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if(sbuf.st_dev != fsp->dev || sbuf.st_ino != fsp->inode) {
		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and dev and/or inode does not match\n",
			 fsp->fsp_name ));
		DEBUG(5,("close_remove_share_mode: file %s. stored dev = %x, "
			 "inode = %.0f stat dev = %x, inode = %.0f\n",
			 fsp->fsp_name,
			 (unsigned int)fsp->dev, (double)fsp->inode,
			 (unsigned int)sbuf.st_dev, (double)sbuf.st_ino ));
		/*
		 * Don't save the errno here, we ignore this error
		 */
		goto done;
	}

	if (SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
		/*
		 * This call can potentially fail as another smbd may
		 * have had the file open with delete on close set and
		 * deleted it when its last reference to this file
		 * went away. Hence we log this but not at debug level
		 * zero.
		 */

		DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
			 "was set and unlink failed with error %s\n",
			 fsp->fsp_name, strerror(errno) ));

		status = map_nt_error_from_unix(errno);
	}

	notify_fname(conn, NOTIFY_ACTION_REMOVED,
		     FILE_NOTIFY_CHANGE_FILE_NAME,
		     fsp->fsp_name);

	/* As we now have POSIX opens which can unlink
 	 * with other open files we may have taken
 	 * this code path with more than one share mode
 	 * entry - ensure we only delete once by resetting
 	 * the delete on close flag. JRA.
 	 */

	set_delete_on_close_lck(lck, False, NULL);

 done:

	/* unbecome user. */
	pop_sec_ctx();
	
	TALLOC_FREE(lck);
	return status;
}
示例#9
0
static NTSTATUS close_remove_share_mode(files_struct *fsp,
                                        enum file_close_type close_type)
{
    connection_struct *conn = fsp->conn;
    bool delete_file = false;
    bool changed_user = false;
    struct share_mode_lock *lck = NULL;
    NTSTATUS status = NT_STATUS_OK;
    NTSTATUS tmp_status;
    struct file_id id;

    /* Ensure any pending write time updates are done. */
    if (fsp->update_write_time_event) {
        update_write_time_handler(smbd_event_context(),
                                  fsp->update_write_time_event,
                                  timeval_current(),
                                  (void *)fsp);
    }

    /*
     * Lock the share entries, and determine if we should delete
     * on close. If so delete whilst the lock is still in effect.
     * This prevents race conditions with the file being created. JRA.
     */

    lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
                              NULL);

    if (lck == NULL) {
        DEBUG(0, ("close_remove_share_mode: Could not get share mode "
                  "lock for file %s\n", fsp_str_dbg(fsp)));
        status = NT_STATUS_INVALID_PARAMETER;
        goto done;
    }

    if (fsp->write_time_forced) {
        DEBUG(10,("close_remove_share_mode: write time forced "
                  "for file %s\n",
                  fsp_str_dbg(fsp)));
        set_close_write_time(fsp, lck->changed_write_time);
    } else if (fsp->update_write_time_on_close) {
        /* Someone had a pending write. */
        if (null_timespec(fsp->close_write_time)) {
            DEBUG(10,("close_remove_share_mode: update to current time "
                      "for file %s\n",
                      fsp_str_dbg(fsp)));
            /* Update to current time due to "normal" write. */
            set_close_write_time(fsp, timespec_current());
        } else {
            DEBUG(10,("close_remove_share_mode: write time pending "
                      "for file %s\n",
                      fsp_str_dbg(fsp)));
            /* Update to time set on close call. */
            set_close_write_time(fsp, fsp->close_write_time);
        }
    }

    if (!del_share_mode(lck, fsp)) {
        DEBUG(0, ("close_remove_share_mode: Could not delete share "
                  "entry for file %s\n",
                  fsp_str_dbg(fsp)));
    }

    if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
        bool became_user = False;

        /* Initial delete on close was set and no one else
         * wrote a real delete on close. */

        if (current_user.vuid != fsp->vuid) {
            become_user(conn, fsp->vuid);
            became_user = True;
        }
        fsp->delete_on_close = true;
        set_delete_on_close_lck(lck, True, &current_user.ut);
        if (became_user) {
            unbecome_user();
        }
    }

    delete_file = lck->delete_on_close;

    if (delete_file) {
        int i;
        /* See if others still have the file open. If this is the
         * case, then don't delete. If all opens are POSIX delete now. */
        for (i=0; i<lck->num_share_modes; i++) {
            struct share_mode_entry *e = &lck->share_modes[i];
            if (is_valid_share_mode_entry(e)) {
                if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
                    continue;
                }
                delete_file = False;
                break;
            }
        }
    }

    /* Notify any deferred opens waiting on this close. */
    notify_deferred_opens(lck);
    reply_to_oplock_break_requests(fsp);

    /*
     * NT can set delete_on_close of the last open
     * reference to a file.
     */

    if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
            || !delete_file
            || (lck->delete_token == NULL)) {
        TALLOC_FREE(lck);
        return NT_STATUS_OK;
    }

    /*
     * Ok, we have to delete the file
     */

    DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
             "- deleting file.\n", fsp_str_dbg(fsp)));

    /*
     * Don't try to update the write time when we delete the file
     */
    fsp->update_write_time_on_close = false;

    if (!unix_token_equal(lck->delete_token, &current_user.ut)) {
        /* Become the user who requested the delete. */

        DEBUG(5,("close_remove_share_mode: file %s. "
                 "Change user to uid %u\n",
                 fsp_str_dbg(fsp),
                 (unsigned int)lck->delete_token->uid));

        if (!push_sec_ctx()) {
            smb_panic("close_remove_share_mode: file %s. failed to push "
                      "sec_ctx.\n");
        }

        set_sec_ctx(lck->delete_token->uid,
                    lck->delete_token->gid,
                    lck->delete_token->ngroups,
                    lck->delete_token->groups,
                    NULL);

        changed_user = true;
    }

    /* We can only delete the file if the name we have is still valid and
       hasn't been renamed. */

    tmp_status = vfs_stat_fsp(fsp);
    if (!NT_STATUS_IS_OK(tmp_status)) {
        DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
                 "was set and stat failed with error %s\n",
                 fsp_str_dbg(fsp), nt_errstr(tmp_status)));
        /*
         * Don't save the errno here, we ignore this error
         */
        goto done;
    }

    id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);

    if (!file_id_equal(&fsp->file_id, &id)) {
        DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
                 "was set and dev and/or inode does not match\n",
                 fsp_str_dbg(fsp)));
        DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
                 "stat file_id %s\n",
                 fsp_str_dbg(fsp),
                 file_id_string_tos(&fsp->file_id),
                 file_id_string_tos(&id)));
        /*
         * Don't save the errno here, we ignore this error
         */
        goto done;
    }

    if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
            && !is_ntfs_stream_smb_fname(fsp->fsp_name)) {

        status = delete_all_streams(conn, fsp->fsp_name->base_name);

        if (!NT_STATUS_IS_OK(status)) {
            DEBUG(5, ("delete_all_streams failed: %s\n",
                      nt_errstr(status)));
            goto done;
        }
    }


    if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
        /*
         * This call can potentially fail as another smbd may
         * have had the file open with delete on close set and
         * deleted it when its last reference to this file
         * went away. Hence we log this but not at debug level
         * zero.
         */

        DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
                 "was set and unlink failed with error %s\n",
                 fsp_str_dbg(fsp), strerror(errno)));

        status = map_nt_error_from_unix(errno);
    }

    notify_fname(conn, NOTIFY_ACTION_REMOVED,
                 FILE_NOTIFY_CHANGE_FILE_NAME,
                 fsp->fsp_name->base_name);

    /* As we now have POSIX opens which can unlink
     * with other open files we may have taken
     * this code path with more than one share mode
     * entry - ensure we only delete once by resetting
     * the delete on close flag. JRA.
     */

    fsp->delete_on_close = false;
    set_delete_on_close_lck(lck, False, NULL);

done:

    if (changed_user) {
        /* unbecome user. */
        pop_sec_ctx();
    }

    TALLOC_FREE(lck);
    return status;
}
示例#10
0
文件: locking.c 项目: rchicoli/samba
bool rename_share_filename(struct messaging_context *msg_ctx,
			struct share_mode_lock *lck,
			const char *servicepath,
			uint32_t orig_name_hash,
			uint32_t new_name_hash,
			const struct smb_filename *smb_fname_dst)
{
	struct share_mode_data *d = lck->data;
	size_t sp_len;
	size_t bn_len;
	size_t sn_len;
	size_t msg_len;
	char *frm = NULL;
	int i;
	bool strip_two_chars = false;
	bool has_stream = smb_fname_dst->stream_name != NULL;
	struct server_id self_pid = messaging_server_id(msg_ctx);

	DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
		   servicepath, smb_fname_dst->base_name));

	/*
	 * rename_internal_fsp() and rename_internals() add './' to
	 * head of newname if newname does not contain a '/'.
	 */
	if (smb_fname_dst->base_name[0] &&
	    smb_fname_dst->base_name[1] &&
	    smb_fname_dst->base_name[0] == '.' &&
	    smb_fname_dst->base_name[1] == '/') {
		strip_two_chars = true;
	}

	d->servicepath = talloc_strdup(d, servicepath);
	d->base_name = talloc_strdup(d, smb_fname_dst->base_name +
				       (strip_two_chars ? 2 : 0));
	d->stream_name = talloc_strdup(d, smb_fname_dst->stream_name);
	if (d->base_name == NULL ||
	    (has_stream && d->stream_name == NULL) ||
	    d->servicepath == NULL) {
		DEBUG(0, ("rename_share_filename: talloc failed\n"));
		return False;
	}
	d->modified = True;

	sp_len = strlen(d->servicepath);
	bn_len = strlen(d->base_name);
	sn_len = has_stream ? strlen(d->stream_name) : 0;

	msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + bn_len + 1 +
	    sn_len + 1;

	/* Set up the name changed message. */
	frm = talloc_array(d, char, msg_len);
	if (!frm) {
		return False;
	}

	push_file_id_24(frm, &d->id);

	DEBUG(10,("rename_share_filename: msg_len = %u\n", (unsigned int)msg_len ));

	strlcpy(&frm[24],
		d->servicepath ? d->servicepath : "",
		sp_len+1);
	strlcpy(&frm[24 + sp_len + 1],
		d->base_name ? d->base_name : "",
		bn_len+1);
	strlcpy(&frm[24 + sp_len + 1 + bn_len + 1],
		d->stream_name ? d->stream_name : "",
		sn_len+1);

	/* Send the messages. */
	for (i=0; i<d->num_share_modes; i++) {
		struct share_mode_entry *se = &d->share_modes[i];
		if (!is_valid_share_mode_entry(se)) {
			continue;
		}

		/* If this is a hardlink to the inode
		   with a different name, skip this. */
		if (se->name_hash != orig_name_hash) {
			continue;
		}

		se->name_hash = new_name_hash;

		/* But not to ourselves... */
		if (serverid_equal(&se->pid, &self_pid)) {
			continue;
		}

		if (share_mode_stale_pid(d, i)) {
			continue;
		}

		DEBUG(10,("rename_share_filename: sending rename message to "
			  "pid %s file_id %s sharepath %s base_name %s "
			  "stream_name %s\n",
			  procid_str_static(&se->pid),
			  file_id_string_tos(&d->id),
			  d->servicepath, d->base_name,
			has_stream ? d->stream_name : ""));

		messaging_send_buf(msg_ctx, se->pid, MSG_SMB_FILE_RENAME,
				   (uint8 *)frm, msg_len);
	}

	return True;
}
示例#11
0
static int close_remove_share_mode(files_struct *fsp, enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	BOOL delete_file = False;
	struct share_mode_lock *lck;

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);

	if (lck == NULL) {
		DEBUG(0, ("close_remove_share_mode: Could not get share mode lock for file %s\n", fsp->fsp_name));
		return EINVAL;
	}

	if (!del_share_mode(lck, fsp)) {
		DEBUG(0, ("close_remove_share_mode: Could not delete share entry for file %s\n", fsp->fsp_name));
	}

	delete_file = (lck->delete_on_close | lck->initial_delete_on_close);

	if (delete_file) {
		int i;
		/* See if others still have the file open. If this is the
		 * case, then don't delete */
		for (i=0; i<lck->num_share_modes; i++) {
			if (is_valid_share_mode_entry(&lck->share_modes[i])) {
				delete_file = False;
				break;
			}
		}
	}

	/* Notify any deferred opens waiting on this close. */
	notify_deferred_opens(lck);
	reply_to_oplock_break_requests(fsp);

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
				delete_file &&
				lck->delete_token) {
		SMB_STRUCT_STAT sbuf;

		DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set - deleting file.\n",
			fsp->fsp_name));

		/* Become the user who requested the delete. */

		if (!push_sec_ctx()) {
			smb_panic("close_remove_share_mode: file %s. failed to push sec_ctx.\n");
		}

		set_sec_ctx(lck->delete_token->uid,
				lck->delete_token->gid,
				lck->delete_token->ngroups,
				lck->delete_token->groups,
				NULL);

		/* We can only delete the file if the name we have
		   is still valid and hasn't been renamed. */
	
		if(SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) != 0) {
			DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
				"and stat failed with error %s\n",
				fsp->fsp_name, strerror(errno) ));
		} else {
			if(sbuf.st_dev != fsp->dev || sbuf.st_ino != fsp->inode) {
				DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set and "
					"dev and/or inode does not match\n",
					fsp->fsp_name ));
				DEBUG(5,("close_remove_share_mode: file %s. stored dev = %x, inode = %.0f "
					"stat dev = %x, inode = %.0f\n",
					fsp->fsp_name,
					(unsigned int)fsp->dev, (double)fsp->inode,
					(unsigned int)sbuf.st_dev, (double)sbuf.st_ino ));

			} else if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
				/*
				 * This call can potentially fail as another smbd may have
				 * had the file open with delete on close set and deleted
				 * it when its last reference to this file went away. Hence
				 * we log this but not at debug level zero.
				 */

				DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set "
					"and unlink failed with error %s\n",
					fsp->fsp_name, strerror(errno) ));
			}
		}
		/* unbecome user. */
		pop_sec_ctx();
	
		process_pending_change_notify_queue((time_t)0);
	}

	TALLOC_FREE(lck);
	return 0;
}
示例#12
0
static int print_share_mode(const struct share_mode_entry *e,
			    const char *sharepath,
			    const char *fname,
			    const char *sname,
			    void *dummy)
{
	static int count;

	if (do_checks && !is_valid_share_mode_entry(e)) {
		return 0;
	}

	if (count==0) {
		d_printf("Locked files:\n");
		d_printf("Pid          Uid        DenyMode   Access      R/W        Oplock           SharePath   Name   Time\n");
		d_printf("--------------------------------------------------------------------------------------------------\n");
	}
	count++;

	if (do_checks && !serverid_exists(&e->pid)) {
		/* the process for this entry does not exist any more */
		return 0;
	}

	if (Ucrit_checkPid(e->pid)) {
		struct server_id_buf tmp;
		d_printf("%-11s  ", server_id_str_buf(e->pid, &tmp));
		d_printf("%-9u  ", (unsigned int)e->uid);
		switch (map_share_mode_to_deny_mode(e->share_access,
						    e->private_options)) {
			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;
			default: {
				d_printf("unknown-please report ! "
					 "e->share_access = 0x%x, "
					 "e->private_options = 0x%x\n",
					 (unsigned int)e->share_access,
					 (unsigned int)e->private_options );
				break;
			}
		}
		d_printf("0x%-8x  ",(unsigned int)e->access_mask);
		if ((e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))==
				(FILE_READ_DATA|FILE_WRITE_DATA)) {
			d_printf("RDWR       ");
		} else if (e->access_mask & FILE_WRITE_DATA) {
			d_printf("WRONLY     ");
		} else {
			d_printf("RDONLY     ");
		}

		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 if (e->op_type == LEASE_OPLOCK) {
			uint32_t lstate = e->lease->current_state;
			d_printf("LEASE(%s%s%s)%s%s%s      ",
				 (lstate & SMB2_LEASE_READ)?"R":"",
				 (lstate & SMB2_LEASE_WRITE)?"W":"",
				 (lstate & SMB2_LEASE_HANDLE)?"H":"",
				 (lstate & SMB2_LEASE_READ)?"":" ",
				 (lstate & SMB2_LEASE_WRITE)?"":" ",
				 (lstate & SMB2_LEASE_HANDLE)?"":" ");
		} else {
			d_printf("NONE            ");
		}

		d_printf(" %s   %s%s   %s",
			 sharepath, fname,
			 sname ? sname : "",
			 time_to_asc((time_t)e->time.tv_sec));
	}

	return 0;
}