示例#1
0
/**
 * XXX: This is temporary and there should be no callers of this once
 * smb_filename is plumbed through all path based operations.
 */
NTSTATUS create_synthetic_smb_fname_split(TALLOC_CTX *ctx,
					  const char *fname,
					  const SMB_STRUCT_STAT *psbuf,
					  struct smb_filename **smb_fname_out)
{
	NTSTATUS status;
	const char *stream_name = NULL;
	char *base_name = NULL;

	if (!lp_posix_pathnames()) {
		stream_name = strchr_m(fname, ':');
	}

	/* Setup the base_name/stream_name. */
	if (stream_name) {
		base_name = talloc_strndup(ctx, fname,
					   PTR_DIFF(stream_name, fname));
	} else {
		base_name = talloc_strdup(ctx, fname);
	}

	if (!base_name) {
		return NT_STATUS_NO_MEMORY;
	}

	status = create_synthetic_smb_fname(ctx, base_name, stream_name, psbuf,
					    smb_fname_out);
	TALLOC_FREE(base_name);
	return status;
}
static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
			       SMB_STRUCT_STAT *sbuf)
{
	struct smb_filename *smb_fname_base = NULL;
	NTSTATUS status;
	int ret = -1;
	struct stream_io *io = (struct stream_io *)
		VFS_FETCH_FSP_EXTENSION(handle, fsp);

	DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));

	if (io == NULL || fsp->base_fsp == NULL) {
		return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
	}

	if (!streams_xattr_recheck(io)) {
		return -1;
	}

	/* Create an smb_filename with stream_name == NULL. */
	status = create_synthetic_smb_fname(talloc_tos(),
					    io->base,
					    NULL, NULL,
					    &smb_fname_base);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		return -1;
	}

	if (lp_posix_pathnames()) {
		ret = SMB_VFS_LSTAT(handle->conn, smb_fname_base);
	} else {
		ret = SMB_VFS_STAT(handle->conn, smb_fname_base);
	}
	*sbuf = smb_fname_base->st;
	TALLOC_FREE(smb_fname_base);

	if (ret == -1) {
		return -1;
	}

	sbuf->st_ex_size = get_xattr_size(handle->conn, fsp->base_fsp,
					io->base, io->xattr_name);
	if (sbuf->st_ex_size == -1) {
		return -1;
	}

	DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf->st_ex_size));

	sbuf->st_ex_ino = stream_inode(sbuf, io->xattr_name);
	sbuf->st_ex_mode &= ~S_IFMT;
        sbuf->st_ex_mode |= S_IFREG;
        sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;

	return 0;
}
示例#3
0
NTSTATUS onefs_stream_prep_smb_fname(TALLOC_CTX *ctx,
				     const struct smb_filename *smb_fname_in,
				     struct smb_filename **smb_fname_out)
{
	char *stream_name = NULL;
	NTSTATUS status;

	/*
	 * Only attempt to strip off the trailing :$DATA if there is an actual
	 * stream there.  If it is the default stream, the smb_fname_out will
	 * just have a NULL stream so the base file is opened.
	 */
	if (smb_fname_in->stream_name &&
	    !is_ntfs_default_stream_smb_fname(smb_fname_in)) {
		char *str_tmp = smb_fname_in->stream_name;

		/* First strip off the leading ':' */
		if (str_tmp[0] == ':') {
			str_tmp++;
		}

		/* Create a new copy of the stream_name. */
		stream_name = talloc_strdup(ctx, str_tmp);
		if (stream_name == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		/* Strip off the :$DATA if one exists. */
		str_tmp = strrchr_m(stream_name, ':');
		if (str_tmp) {
			if (strcasecmp_m(str_tmp, ":$DATA") != 0) {
				return NT_STATUS_INVALID_PARAMETER;
			}
			str_tmp[0] = '\0';
		}
	}

	/*
	 * If there was a stream that wasn't the default stream the leading
	 * colon and trailing :$DATA has now been stripped off.  Create a new
	 * smb_filename to pass back.
	 */
	status = create_synthetic_smb_fname(ctx, smb_fname_in->base_name,
					    stream_name, &smb_fname_in->st,
					    smb_fname_out);
	TALLOC_FREE(stream_name);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(5, ("Failed to prep stream name for %s: %s\n",
			  *smb_fname_out ?
			  smb_fname_str_dbg(*smb_fname_out) : "NULL",
			  nt_errstr(status)));
	}
	return status;
}
示例#4
0
NTSTATUS open_np_file(struct smb_request *smb_req, const char *name,
                      struct files_struct **pfsp)
{
    struct connection_struct *conn = smb_req->conn;
    struct files_struct *fsp;
    struct smb_filename *smb_fname = NULL;
    NTSTATUS status;

    status = file_new(smb_req, conn, &fsp);
    if (!NT_STATUS_IS_OK(status)) {
        DEBUG(0, ("file_new failed: %s\n", nt_errstr(status)));
        return status;
    }

    fsp->conn = conn;
    fsp->fh->fd = -1;
    fsp->vuid = smb_req->vuid;
    fsp->can_lock = false;
    fsp->access_mask = FILE_READ_DATA | FILE_WRITE_DATA;

    status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
                                        &smb_fname);
    if (!NT_STATUS_IS_OK(status)) {
        file_free(smb_req, fsp);
        return status;
    }
    status = fsp_set_smb_fname(fsp, smb_fname);
    TALLOC_FREE(smb_fname);
    if (!NT_STATUS_IS_OK(status)) {
        file_free(smb_req, fsp);
        return status;
    }

    status = np_open(fsp, name,
                     conn->sconn->local_address,
                     conn->sconn->remote_address,
                     &conn->sconn->client_id,
                     conn->session_info,
                     conn->sconn->msg_ctx,
                     &fsp->fake_file_handle);
    if (!NT_STATUS_IS_OK(status)) {
        DEBUG(10, ("np_open(%s) returned %s\n", name,
                   nt_errstr(status)));
        file_free(smb_req, fsp);
        return status;
    }

    *pfsp = fsp;

    return NT_STATUS_OK;
}
示例#5
0
static SMB_STRUCT_DIR *dirsort_opendir(vfs_handle_struct *handle,
				       const char *fname, const char *mask,
				       uint32 attr)
{
	NTSTATUS status;
	struct dirsort_privates *data = NULL;

	/* set up our private data about this directory */
	data = talloc_zero(handle->conn, struct dirsort_privates);
	if (!data) {
		return NULL;
	}

	status = create_synthetic_smb_fname(data,
					fname,
					NULL,
					NULL,
					&data->smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(data);
		return NULL;
	}

	/* Open the underlying directory and count the number of entries */
	data->source_directory = SMB_VFS_NEXT_OPENDIR(handle, fname, mask,
						      attr);

	if (data->source_directory == NULL) {
		TALLOC_FREE(data);
		return NULL;
	}

	if (!open_and_sort_dir(handle, data)) {
		SMB_VFS_NEXT_CLOSEDIR(handle,data->source_directory);
		TALLOC_FREE(data);
		return NULL;
	}

	SMB_VFS_HANDLE_SET_DATA(handle, data, free_dirsort_privates,
				struct dirsort_privates, return NULL);

	return data->source_directory;
}
示例#6
0
connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
					int snum, user_struct *vuser,
					DATA_BLOB password,
					const char *pdev,
					NTSTATUS *pstatus)
{
	connection_struct *conn;
	struct smb_filename *smb_fname_cpath = NULL;
	fstring dev;
	int ret;
	char addr[INET6_ADDRSTRLEN];
	bool on_err_call_dis_hook = false;
	NTSTATUS status;

	fstrcpy(dev, pdev);

	if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) {
		return NULL;
	}	

	conn = conn_new(sconn);
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}

	conn->params->service = snum;

	status = create_connection_server_info(sconn,
		conn, snum, vuser ? vuser->server_info : NULL, password,
		&conn->server_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("create_connection_server_info failed: %s\n",
			  nt_errstr(status)));
		*pstatus = status;
		conn_free(conn);
		return NULL;
	}

	if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
		conn->force_user = true;
	}

	add_session_user(sconn, conn->server_info->unix_name);

	safe_strcpy(conn->client_address,
			client_addr(get_client_fd(),addr,sizeof(addr)), 
			sizeof(conn->client_address)-1);
	conn->num_files_open = 0;
	conn->lastused = conn->lastused_count = time(NULL);
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
		      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );

	/* Case options for the share. */
	if (lp_casesensitive(snum) == Auto) {
		/* We will be setting this per packet. Set to be case
		 * insensitive for now. */
		conn->case_sensitive = False;
	} else {
		conn->case_sensitive = (bool)lp_casesensitive(snum);
	}

	conn->case_preserve = lp_preservecase(snum);
	conn->short_case_preserve = lp_shortpreservecase(snum);

	conn->encrypt_level = lp_smb_encrypt(snum);

	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	conn->aio_write_behind_list = NULL;

	conn->read_only = lp_readonly(SNUM(conn));
	conn->admin_user = False;

	if (*lp_force_user(snum)) {

		/*
		 * Replace conn->server_info with a completely faked up one
		 * from the username we are forced into :-)
		 */

		char *fuser;
		struct auth_serversupplied_info *forced_serverinfo;

		fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
					  lp_servicename(snum));
		if (fuser == NULL) {
			conn_free(conn);
			*pstatus = NT_STATUS_NO_MEMORY;
			return NULL;
		}

		status = make_serverinfo_from_username(
			conn, fuser, conn->server_info->guest,
			&forced_serverinfo);
		if (!NT_STATUS_IS_OK(status)) {
			conn_free(conn);
			*pstatus = status;
			return NULL;
		}

		TALLOC_FREE(conn->server_info);
		conn->server_info = forced_serverinfo;

		conn->force_user = True;
		DEBUG(3,("Forced user %s\n", fuser));
	}

	/*
	 * If force group is true, then override
	 * any groupid stored for the connecting user.
	 */

	if (*lp_force_group(snum)) {

		status = find_forced_group(
			conn->force_user, snum, conn->server_info->unix_name,
			&conn->server_info->ptok->user_sids[1],
			&conn->server_info->utok.gid);

		if (!NT_STATUS_IS_OK(status)) {
			conn_free(conn);
			*pstatus = status;
			return NULL;
		}

		/*
		 * We need to cache this gid, to use within
 		 * change_to_user() separately from the conn->server_info
 		 * struct. We only use conn->server_info directly if
 		 * "force_user" was set.
 		 */
		conn->force_group_gid = conn->server_info->utok.gid;
	}

	conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;

	{
		char *s = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->server_info->unix_name,
					conn->connectpath,
					conn->server_info->utok.gid,
					conn->server_info->sanitized_username,
					pdb_get_domain(conn->server_info->sam_account),
					lp_pathname(snum));
		if (!s) {
			conn_free(conn);
			*pstatus = NT_STATUS_NO_MEMORY;
			return NULL;
		}

		if (!set_conn_connectpath(conn,s)) {
			TALLOC_FREE(s);
			conn_free(conn);
			*pstatus = NT_STATUS_NO_MEMORY;
			return NULL;
		}
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(snum)));
		TALLOC_FREE(s);
	}

	/*
	 * New code to check if there's a share security descripter
	 * added from NT server manager. This is done after the
	 * smb.conf checks are done as we need a uid and token. JRA.
	 *
	 */

	{
		bool can_write = False;

		can_write = share_access_check(conn->server_info->ptok,
					       lp_servicename(snum),
					       FILE_WRITE_DATA);

		if (!can_write) {
			if (!share_access_check(conn->server_info->ptok,
						lp_servicename(snum),
						FILE_READ_DATA)) {
				/* No access, read or write. */
				DEBUG(0,("make_connection: connection to %s "
					 "denied due to security "
					 "descriptor.\n",
					  lp_servicename(snum)));
				conn_free(conn);
				*pstatus = NT_STATUS_ACCESS_DENIED;
				return NULL;
			} else {
				conn->read_only = True;
			}
		}
	}
	/* Initialise VFS function pointers */

	if (!smbd_vfs_init(conn)) {
		DEBUG(0, ("vfs_init failed for service %s\n",
			  lp_servicename(snum)));
		conn_free(conn);
		*pstatus = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/*
	 * If widelinks are disallowed we need to canonicalise the connect
	 * path here to ensure we don't have any symlinks in the
	 * connectpath. We will be checking all paths on this connection are
	 * below this directory. We must do this after the VFS init as we
	 * depend on the realpath() pointer in the vfs table. JRA.
	 */
	if (!lp_widelinks(snum)) {
		if (!canonicalize_connect_path(conn)) {
			DEBUG(0, ("canonicalize_connect_path failed "
			"for service %s, path %s\n",
				lp_servicename(snum),
				conn->connectpath));
			conn_free(conn);
			*pstatus = NT_STATUS_BAD_NETWORK_NAME;
			return NULL;
		}
	}

	if ((!conn->printer) && (!conn->ipc)) {
		conn->notify_ctx = notify_init(conn, server_id_self(),
					       smbd_messaging_context(),
					       smbd_event_context(),
					       conn);
	}

/* ROOT Activities: */	
	/*
	 * Enforce the max connections parameter.
	 */

	if ((lp_max_connections(snum) > 0)
	    && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
		lp_max_connections(snum))) {

		DEBUG(1, ("Max connections (%d) exceeded for %s\n",
			  lp_max_connections(snum), lp_servicename(snum)));
		conn_free(conn);
		*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}  

	/*
	 * Get us an entry in the connections db
	 */
	if (!claim_connection(conn, lp_servicename(snum), 0)) {
		DEBUG(1, ("Could not store connections entry\n"));
		conn_free(conn);
		*pstatus = NT_STATUS_INTERNAL_DB_ERROR;
		return NULL;
	}  

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->server_info->unix_name,
					conn->connectpath,
					conn->server_info->utok.gid,
					conn->server_info->sanitized_username,
					pdb_get_domain(conn->server_info->sam_account),
					lp_rootpreexec(snum));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_rootpreexec_close(snum)) {
			DEBUG(1,("root preexec gave %d - failing "
				 "connection\n", ret));
			yield_connection(conn, lp_servicename(snum));
			conn_free(conn);
			*pstatus = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

/* USER Activites: */
	if (!change_to_user(conn, conn->vuid)) {
		/* No point continuing if they fail the basic checks */
		DEBUG(0,("Can't become connected user!\n"));
		yield_connection(conn, lp_servicename(snum));
		conn_free(conn);
		*pstatus = NT_STATUS_LOGON_FAILURE;
		return NULL;
	}

	/* Remember that a different vuid can connect later without these
	 * checks... */
	
	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */

	/* execute any "preexec = " line */
	if (*lp_preexec(snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->server_info->unix_name,
					conn->connectpath,
					conn->server_info->utok.gid,
					conn->server_info->sanitized_username,
					pdb_get_domain(conn->server_info->sam_account),
					lp_preexec(snum));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			*pstatus = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

#ifdef WITH_FAKE_KASERVER
	if (lp_afs_share(snum)) {
		afs_login(conn);
	}
#endif
	
	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(snum));
		set_namearray( &conn->hide_list, lp_hide_files(snum));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
		set_namearray( &conn->aio_write_behind_list,
				lp_aio_write_behind(snum));
	}
	
	/* Invoke VFS make connection hook - do this before the VFS_STAT call
	   to allow any filesystems needing user credentials to initialize
	   themselves. */

	if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
			    conn->server_info->unix_name) < 0) {
		DEBUG(0,("make_connection: VFS make connection failed!\n"));
		*pstatus = NT_STATUS_UNSUCCESSFUL;
		goto err_root_exit;
	}

	/* Any error exit after here needs to call the disconnect hook. */
	on_err_call_dis_hook = true;

	status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
					    NULL, NULL, &smb_fname_cpath);
	if (!NT_STATUS_IS_OK(status)) {
		*pstatus = status;
		goto err_root_exit;
	}

	/* win2000 does not check the permissions on the directory
	   during the tree connect, instead relying on permission
	   check during individual operations. To match this behaviour
	   I have disabled this chdir check (tridge) */
	/* the alternative is just to check the directory exists */
	if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
	    !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
		if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
			DEBUG(0,("'%s' is not a directory, when connecting to "
				 "[%s]\n", conn->connectpath,
				 lp_servicename(snum)));
		} else {
			DEBUG(0,("'%s' does not exist or permission denied "
				 "when connecting to [%s] Error was %s\n",
				 conn->connectpath, lp_servicename(snum),
				 strerror(errno) ));
		}
		*pstatus = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}

	string_set(&conn->origpath,conn->connectpath);

#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early if possible */
	if (vfs_ChDir(conn,conn->connectpath) == 0) {
		TALLOC_CTX *ctx = talloc_tos();
		char *s = vfs_GetWd(ctx,s);
		if (!s) {
			*status = map_nt_error_from_unix(errno);
			goto err_root_exit;
		}
		if (!set_conn_connectpath(conn,s)) {
			*status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}
		vfs_ChDir(conn,conn->connectpath);
	}
#endif

	if (lp_unix_extensions() && lp_widelinks(snum)) {
		DEBUG(0,("Share '%s' has wide links and unix extensions enabled. "
			"These parameters are incompatible. "
			"Disabling wide links for this share.\n",
			lp_servicename(snum) ));
		lp_do_parameter(snum, "wide links", "False");
	}

	/* Figure out the characteristics of the underlying filesystem. This
	 * assumes that all the filesystem mounted withing a share path have
	 * the same characteristics, which is likely but not guaranteed.
	 */

	conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using
	 * (at least initially).
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", get_remote_machine_name(),
			 conn->client_address );
		dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : "");
		dbgtext( "connect to service %s ", lp_servicename(snum) );
		dbgtext( "initially as user %s ",
			 conn->server_info->unix_name );
		dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
		dbgtext( "(pid %d)\n", (int)sys_getpid() );
	}

	/* we've finished with the user stuff - go back to root */
	change_to_root_user();
	return(conn);

  err_root_exit:
	TALLOC_FREE(smb_fname_cpath);
	change_to_root_user();
	if (on_err_call_dis_hook) {
		/* Call VFS disconnect hook */
		SMB_VFS_DISCONNECT(conn);
	}
	yield_connection(conn, lp_servicename(snum));
	conn_free(conn);
	return NULL;
}
示例#7
0
static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
{
	connection_struct *conn = fsp->conn;
	struct smb_filename *smb_dname = fsp->fsp_name;
	int ret;

	SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));

	/* Might be a symlink. */
	if(SMB_VFS_LSTAT(conn, smb_dname) != 0) {
		return map_nt_error_from_unix(errno);
	}

	if (S_ISLNK(smb_dname->st.st_ex_mode)) {
		/* Is what it points to a directory ? */
		if(SMB_VFS_STAT(conn, smb_dname) != 0) {
			return map_nt_error_from_unix(errno);
		}
		if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
			return NT_STATUS_NOT_A_DIRECTORY;
		}
		ret = SMB_VFS_UNLINK(conn, smb_dname);
	} else {
		ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
	}
	if (ret == 0) {
		notify_fname(conn, NOTIFY_ACTION_REMOVED,
			     FILE_NOTIFY_CHANGE_DIR_NAME,
			     smb_dname->base_name);
		return NT_STATUS_OK;
	}

	if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
		/*
		 * Check to see if the only thing in this directory are
		 * vetoed files/directories. If so then delete them and
		 * retry. If we fail to delete any of them (and we *don't*
		 * do a recursive delete) then fail the rmdir.
		 */
		SMB_STRUCT_STAT st;
		const char *dname = NULL;
		char *talloced = NULL;
		long dirpos = 0;
		struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
						  smb_dname->base_name, NULL,
						  0);

		if(dir_hnd == NULL) {
			errno = ENOTEMPTY;
			goto err;
		}

		while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
					    &talloced)) != NULL) {
			if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
				TALLOC_FREE(talloced);
				continue;
			}
			if (!is_visible_file(conn, smb_dname->base_name, dname,
					     &st, false)) {
				TALLOC_FREE(talloced);
				continue;
			}
			if(!IS_VETO_PATH(conn, dname)) {
				TALLOC_FREE(dir_hnd);
				TALLOC_FREE(talloced);
				errno = ENOTEMPTY;
				goto err;
			}
			TALLOC_FREE(talloced);
		}

		/* We only have veto files/directories.
		 * Are we allowed to delete them ? */

		if(!lp_recursive_veto_delete(SNUM(conn))) {
			TALLOC_FREE(dir_hnd);
			errno = ENOTEMPTY;
			goto err;
		}

		/* Do a recursive delete. */
		RewindDir(dir_hnd,&dirpos);
		while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
					    &talloced)) != NULL) {
			struct smb_filename *smb_dname_full = NULL;
			char *fullname = NULL;
			bool do_break = true;
			NTSTATUS status;

			if (ISDOT(dname) || ISDOTDOT(dname)) {
				TALLOC_FREE(talloced);
				continue;
			}
			if (!is_visible_file(conn, smb_dname->base_name, dname,
					     &st, false)) {
				TALLOC_FREE(talloced);
				continue;
			}

			fullname = talloc_asprintf(ctx,
					"%s/%s",
					smb_dname->base_name,
					dname);

			if(!fullname) {
				errno = ENOMEM;
				goto err_break;
			}

			status = create_synthetic_smb_fname(talloc_tos(),
							    fullname, NULL,
							    NULL,
							    &smb_dname_full);
			if (!NT_STATUS_IS_OK(status)) {
				errno = map_errno_from_nt_status(status);
				goto err_break;
			}

			if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
				goto err_break;
			}
			if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
				if(!recursive_rmdir(ctx, conn,
						    smb_dname_full)) {
					goto err_break;
				}
				if(SMB_VFS_RMDIR(conn,
					smb_dname_full->base_name) != 0) {
					goto err_break;
				}
			} else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
				goto err_break;
			}

			/* Successful iteration. */
			do_break = false;

		 err_break:
			TALLOC_FREE(fullname);
			TALLOC_FREE(smb_dname_full);
			TALLOC_FREE(talloced);
			if (do_break)
				break;
		}
		TALLOC_FREE(dir_hnd);
		/* Retry the rmdir */
		ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
	}

  err:

	if (ret != 0) {
		DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
			 "%s\n", smb_fname_str_dbg(smb_dname),
			 strerror(errno)));
		return map_nt_error_from_unix(errno);
	}

	notify_fname(conn, NOTIFY_ACTION_REMOVED,
		     FILE_NOTIFY_CHANGE_DIR_NAME,
		     smb_dname->base_name);

	return NT_STATUS_OK;
}
示例#8
0
static bool recursive_rmdir(TALLOC_CTX *ctx,
			connection_struct *conn,
			struct smb_filename *smb_dname)
{
	const char *dname = NULL;
	char *talloced = NULL;
	bool ret = True;
	long offset = 0;
	SMB_STRUCT_STAT st;
	struct smb_Dir *dir_hnd;

	SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));

	dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
	if(dir_hnd == NULL)
		return False;

	while((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
		struct smb_filename *smb_dname_full = NULL;
		char *fullname = NULL;
		bool do_break = true;
		NTSTATUS status;

		if (ISDOT(dname) || ISDOTDOT(dname)) {
			TALLOC_FREE(talloced);
			continue;
		}

		if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
				     false)) {
			TALLOC_FREE(talloced);
			continue;
		}

		/* Construct the full name. */
		fullname = talloc_asprintf(ctx,
				"%s/%s",
				smb_dname->base_name,
				dname);
		if (!fullname) {
			errno = ENOMEM;
			goto err_break;
		}

		status = create_synthetic_smb_fname(talloc_tos(), fullname,
						    NULL, NULL,
						    &smb_dname_full);
		if (!NT_STATUS_IS_OK(status)) {
			goto err_break;
		}

		if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
			goto err_break;
		}

		if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
			if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
				goto err_break;
			}
			if(SMB_VFS_RMDIR(conn,
					 smb_dname_full->base_name) != 0) {
				goto err_break;
			}
		} else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
			goto err_break;
		}

		/* Successful iteration. */
		do_break = false;

	 err_break:
		TALLOC_FREE(smb_dname_full);
		TALLOC_FREE(fullname);
		TALLOC_FREE(talloced);
		if (do_break) {
			ret = false;
			break;
		}
	}
	TALLOC_FREE(dir_hnd);
	return ret;
}
示例#9
0
NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
{
	struct stream_struct *stream_info = NULL;
	int i;
	unsigned int num_streams = 0;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
				&num_streams, &stream_info);

	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
		DEBUG(10, ("no streams around\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_OK;
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("vfs_streaminfo failed: %s\n",
			   nt_errstr(status)));
		goto fail;
	}

	DEBUG(10, ("delete_all_streams found %d streams\n",
		   num_streams));

	if (num_streams == 0) {
		TALLOC_FREE(frame);
		return NT_STATUS_OK;
	}

	for (i=0; i<num_streams; i++) {
		int res;
		struct smb_filename *smb_fname_stream = NULL;

		if (strequal(stream_info[i].name, "::$DATA")) {
			continue;
		}

		status = create_synthetic_smb_fname(talloc_tos(), fname,
						    stream_info[i].name, NULL,
						    &smb_fname_stream);

		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("talloc_aprintf failed\n"));
			goto fail;
		}

		res = SMB_VFS_UNLINK(conn, smb_fname_stream);

		if (res == -1) {
			status = map_nt_error_from_unix(errno);
			DEBUG(10, ("Could not delete stream %s: %s\n",
				   smb_fname_str_dbg(smb_fname_stream),
				   strerror(errno)));
			TALLOC_FREE(smb_fname_stream);
			break;
		}
		TALLOC_FREE(smb_fname_stream);
	}

 fail:
	TALLOC_FREE(frame);
	return status;
}
示例#10
0
bool can_delete_file_in_directory(connection_struct *conn,
				  const struct smb_filename *smb_fname)
{
	TALLOC_CTX *ctx = talloc_tos();
	char *dname = NULL;
	struct smb_filename *smb_fname_parent = NULL;
	NTSTATUS status;
	bool ret;

	if (!CAN_WRITE(conn)) {
		return False;
	}

	if (!lp_acl_check_permissions(SNUM(conn))) {
		/* This option means don't check. */
		return true;
	}

	/* Get the parent directory permission mask and owners. */
	if (!parent_dirname(ctx, smb_fname->base_name, &dname, NULL)) {
		return False;
	}

	status = create_synthetic_smb_fname(ctx, dname, NULL, NULL,
					    &smb_fname_parent);
	if (!NT_STATUS_IS_OK(status)) {
		ret = false;
		goto out;
	}

	if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
		ret = false;
		goto out;
	}

	/* fast paths first */

	if (!S_ISDIR(smb_fname_parent->st.st_ex_mode)) {
		ret = false;
		goto out;
	}
	if (get_current_uid(conn) == (uid_t)0) {
		/* I'm sorry sir, I didn't know you were root... */
		ret = true;
		goto out;
	}

#ifdef S_ISVTX
	/* sticky bit means delete only by owner of file or by root or
	 * by owner of directory. */
	if (smb_fname_parent->st.st_ex_mode & S_ISVTX) {
		if (!VALID_STAT(smb_fname->st)) {
			/* If the file doesn't already exist then
			 * yes we'll be able to delete it. */
			ret = true;
			goto out;
		}

		/*
		 * Patch from SATOH Fumiyasu <*****@*****.**>
		 * for bug #3348. Don't assume owning sticky bit
		 * directory means write access allowed.
		 * Fail to delete if we're not the owner of the file,
		 * or the owner of the directory as we have no possible
		 * chance of deleting. Otherwise, go on and check the ACL.
		 */
		if ((get_current_uid(conn) !=
			smb_fname_parent->st.st_ex_uid) &&
		    (get_current_uid(conn) != smb_fname->st.st_ex_uid)) {
			DEBUG(10,("can_delete_file_in_directory: not "
				  "owner of file %s or directory %s",
				  smb_fname_str_dbg(smb_fname),
				  smb_fname_str_dbg(smb_fname_parent)));
			ret = false;
			goto out;
		}
	}
#endif

	/* now for ACL checks */

	/*
	 * There's two ways to get the permission to delete a file: First by
	 * having the DELETE bit on the file itself and second if that does
	 * not help, by the DELETE_CHILD bit on the containing directory.
	 *
	 * Here we only check the directory permissions, we will
	 * check the file DELETE permission separately.
	 */

	ret = NT_STATUS_IS_OK(smbd_check_access_rights(conn,
				smb_fname_parent,
				FILE_DELETE_CHILD));
 out:
	TALLOC_FREE(dname);
	TALLOC_FREE(smb_fname_parent);
	return ret;
}
示例#11
0
int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle,
			     const char *name,
			     SMB_ACL_TYPE_T type,
			     SMB_ACL_T theacl)
{
	int ret = -1;
	HPUX_ACL_T hpux_acl = NULL;
	int count;
	struct smb_filename *smb_fname = NULL;
	NTSTATUS status;

	DEBUG(10, ("hpuxacl_sys_acl_set_file called for file '%s'\n",
		   name));

	status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
					    &smb_fname);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	if(hpux_acl_call_present() == False) {
		/* Looks like we don't have the acl() system call on HPUX. 
		 * May be the system doesn't have the latest version of JFS.
		 */
		goto done;
	}

	if ((type != SMB_ACL_TYPE_ACCESS) && (type != SMB_ACL_TYPE_DEFAULT)) {
		errno = EINVAL;
		DEBUG(10, ("invalid smb acl type given (%d).\n", type));
		goto done;
	}
	DEBUGADD(10, ("setting %s acl\n", 
		      ((type == SMB_ACL_TYPE_ACCESS) ? "access" : "default")));

	if(!smb_acl_to_hpux_acl(theacl, &hpux_acl, &count, type)) {
		DEBUG(10, ("conversion smb_acl -> hpux_acl failed (%s).\n",
			   strerror(errno)));
                goto done;
	}

	/*
	 * if the file is a directory, there is extra work to do:
	 * since the hpux acl call stores both the access acl and 
	 * the default acl as provided, we have to get the acl part 
	 * that has _not_ been specified in "type" from the file first 
	 * and concatenate it with the acl provided.
	 */
	if (lp_posix_pathnames()) {
		ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
	} else {
		ret = SMB_VFS_STAT(handle->conn, smb_fname);
	}
	if (ret != 0) {
		DEBUG(10, ("Error in stat call: %s\n", strerror(errno)));
		goto done;
	}
	if (S_ISDIR(smb_fname->st.st_ex_mode)) {
		HPUX_ACL_T other_acl; 
		int other_count;
		SMB_ACL_TYPE_T other_type;

		other_type = (type == SMB_ACL_TYPE_ACCESS) 
			? SMB_ACL_TYPE_DEFAULT
			: SMB_ACL_TYPE_ACCESS;
		DEBUGADD(10, ("getting acl from filesystem\n"));
		if (!hpux_acl_get_file(smb_fname->base_name, &other_acl,
				       &other_count)) {
			DEBUG(10, ("error getting acl from directory\n"));
			goto done;
		}
		DEBUG(10, ("adding %s part of fs acl to given acl\n",
			   ((other_type == SMB_ACL_TYPE_ACCESS) 
			    ? "access"
			    : "default")));
		if (!hpux_add_to_acl(&hpux_acl, &count, other_acl,
					other_count, other_type)) 
		{
			DEBUG(10, ("error adding other acl.\n"));
			SAFE_FREE(other_acl);
			goto done;
		}
		SAFE_FREE(other_acl);
	}
	else if (type != SMB_ACL_TYPE_ACCESS) {
		errno = EINVAL;
		goto done;
	}

	if (!hpux_acl_sort(hpux_acl, count)) {
		DEBUG(10, ("resulting acl is not valid!\n"));
		goto done;
	}
	DEBUG(10, ("resulting acl is valid.\n"));

	ret = acl(discard_const_p(char, smb_fname->base_name), ACL_SET, count,
		  hpux_acl);
	if (ret != 0) {
		DEBUG(0, ("ERROR calling acl: %s\n", strerror(errno)));
	}

 done:
	DEBUG(10, ("hpuxacl_sys_acl_set_file %s.\n",
		   ((ret != 0) ? "failed" : "succeeded")));
	TALLOC_FREE(smb_fname);
	SAFE_FREE(hpux_acl);
	return ret;
}
示例#12
0
文件: files.c 项目: 0x24bin/winexe-1
NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
		  files_struct **result)
{
	int i;
	files_struct *fsp;
	NTSTATUS status;

	/* we want to give out file handles differently on each new
	   connection because of a common bug in MS clients where they try to
	   reuse a file descriptor from an earlier smb connection. This code
	   increases the chance that the errant client will get an error rather
	   than causing corruption */
	if (first_file == 0) {
		first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
	}

	/* TODO: Port the id-tree implementation from Samba4 */

	i = bitmap_find(file_bmap, first_file);
	if (i == -1) {
		DEBUG(0,("ERROR! Out of file structures\n"));
		/* TODO: We have to unconditionally return a DOS error here,
		 * W2k3 even returns ERRDOS/ERRnofids for ntcreate&x with
		 * NTSTATUS negotiated */
		return NT_STATUS_TOO_MANY_OPENED_FILES;
	}

	/*
	 * Make a child of the connection_struct as an fsp can't exist
	 * indepenedent of a connection.
	 */
	fsp = talloc_zero(conn, struct files_struct);
	if (!fsp) {
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * This can't be a child of fsp because the file_handle can be ref'd
	 * when doing a dos/fcb open, which will then share the file_handle
	 * across multiple fsps.
	 */
	fsp->fh = talloc_zero(conn, struct fd_handle);
	if (!fsp->fh) {
		TALLOC_FREE(fsp);
		return NT_STATUS_NO_MEMORY;
	}

	fsp->fh->ref_count = 1;
	fsp->fh->fd = -1;

	fsp->conn = conn;
	fsp->fh->gen_id = get_gen_count();
	GetTimeOfDay(&fsp->open_time);

	first_file = (i+1) % real_max_open_files;

	bitmap_set(file_bmap, i);
	files_used++;

	fsp->fnum = i + FILE_HANDLE_OFFSET;
	SMB_ASSERT(fsp->fnum < 65536);

	/*
	 * Create an smb_filename with "" for the base_name.  There are very
	 * few NULL checks, so make sure it's initialized with something. to
	 * be safe until an audit can be done.
	 */
	status = create_synthetic_smb_fname(fsp, "", NULL, NULL,
					    &fsp->fsp_name);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(fsp);
		TALLOC_FREE(fsp->fh);
	}

	DLIST_ADD(Files, fsp);

	DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
		 i, fsp->fnum, files_used));

	if (req != NULL) {
		req->chain_fsp = fsp;
	}

	/* A new fsp invalidates the positive and
	  negative fsp_fi_cache as the new fsp is pushed
	  at the start of the list and we search from
	  a cache hit to the *end* of the list. */

	ZERO_STRUCT(fsp_fi_cache);

	conn->num_files_open++;

	*result = fsp;
	return NT_STATUS_OK;
}
示例#13
0
NTSTATUS print_spool_open(files_struct *fsp,
			  const char *fname,
			  uint16_t current_vuid)
{
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx;
	struct print_file_data *pf;
	struct dcerpc_binding_handle *b = NULL;
	struct spoolss_DevmodeContainer devmode_ctr;
	union spoolss_DocumentInfo info;
	int fd = -1;
	WERROR werr;

	tmp_ctx = talloc_new(fsp);
	if (!tmp_ctx) {
		return NT_STATUS_NO_MEMORY;
	}

	pf = talloc_zero(fsp, struct print_file_data);
	if (!pf) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	pf->svcname = talloc_strdup(pf, lp_servicename(SNUM(fsp->conn)));

	/* the document name is derived from the file name.
	 * "Remote Downlevel Document" is added in front to
	 * mimic what windows does in this case */
	pf->docname = talloc_strdup(pf, DOCNAME_DEFAULT);
	if (!pf->docname) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	if (fname) {
		const char *p = strrchr(fname, '/');
		if (!p) {
			p = fname;
		}
		pf->docname = talloc_asprintf_append(pf->docname, " %s", p);
		if (!pf->docname) {
			status = NT_STATUS_NO_MEMORY;
			goto done;
		}
	}

	/*
	 * Ok, now we have to open an actual file.
	 * Here is the reason:
	 * We want to write the spool job to this file in
	 * smbd for scalability reason (and also because
	 * apparently window printer drivers can seek when
	 * spooling to a file).
	 * So we first create a file, and then we pass it
	 * to spoolss in output_file so it can monitor and
	 * take over once we call EndDocPrinter().
	 * Of course we will not start writing until
	 * StartDocPrinter() actually gives the ok.
	 * smbd spooler files do not include a print jobid
	 * path component, as the jobid is only known after
	 * calling StartDocPrinter().
	 */

	pf->filename = talloc_asprintf(pf, "%s/%sXXXXXX",
					lp_pathname(SNUM(fsp->conn)),
					PRINT_SPOOL_PREFIX);
	if (!pf->filename) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	errno = 0;
	fd = mkstemp(pf->filename);
	if (fd == -1) {
		if (errno == EACCES) {
			/* Common setup error, force a report. */
			DEBUG(0, ("Insufficient permissions "
				  "to open spool file %s.\n",
				  pf->filename));
		} else {
			/* Normal case, report at level 3 and above. */
			DEBUG(3, ("can't open spool file %s,\n",
				  pf->filename));
			DEBUGADD(3, ("errno = %d (%s).\n",
				     errno, strerror(errno)));
		}
		status = map_nt_error_from_unix(errno);
		goto done;
	}

	/* now open a document over spoolss so that it does
	 * all printer verification, and eventually assigns
	 * a job id */

	status = rpc_pipe_open_interface(fsp->conn,
					 &ndr_table_spoolss.syntax_id,
					 fsp->conn->session_info,
					 &fsp->conn->sconn->client_id,
					 fsp->conn->sconn->msg_ctx,
					 &fsp->conn->spoolss_pipe);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}
	b = fsp->conn->spoolss_pipe->binding_handle;

	ZERO_STRUCT(devmode_ctr);

	status = dcerpc_spoolss_OpenPrinter(b, pf, pf->svcname,
					    "RAW", devmode_ctr,
					    SEC_FLAG_MAXIMUM_ALLOWED,
					    &pf->handle, &werr);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}
	if (!W_ERROR_IS_OK(werr)) {
		status = werror_to_ntstatus(werr);
		goto done;
	}

	info.info1 = talloc(tmp_ctx, struct spoolss_DocumentInfo1);
	if (!info.info1) {
		status = NT_STATUS_NO_MEMORY;
		goto done;
	}
	info.info1->document_name = pf->docname;
	info.info1->output_file = pf->filename;
	info.info1->datatype = "RAW";

	status = dcerpc_spoolss_StartDocPrinter(b, tmp_ctx, &pf->handle,
						1, info, &pf->jobid, &werr);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}
	if (!W_ERROR_IS_OK(werr)) {
		status = werror_to_ntstatus(werr);
		goto done;
	}

	/* Convert to RAP id. */
	pf->rap_jobid = pjobid_to_rap(pf->svcname, pf->jobid);
	if (pf->rap_jobid == 0) {
		/* No errno around here */
		status = NT_STATUS_ACCESS_DENIED;
		goto done;
	}

	/* setup a full fsp */
	status = create_synthetic_smb_fname(fsp, pf->filename, NULL,
					    NULL, &fsp->fsp_name);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	if (sys_fstat(fd, &fsp->fsp_name->st, false) != 0) {
		status = map_nt_error_from_unix(errno);
		goto done;
	}

	fsp->file_id = vfs_file_id_from_sbuf(fsp->conn, &fsp->fsp_name->st);
	fsp->mode = fsp->fsp_name->st.st_ex_mode;
	fsp->fh->fd = fd;

	fsp->vuid = current_vuid;
	fsp->can_lock = false;
	fsp->can_read = false;
	fsp->access_mask = FILE_GENERIC_WRITE;
	fsp->can_write = true;
	fsp->modified = false;
	fsp->oplock_type = NO_OPLOCK;
	fsp->sent_oplock_break = NO_BREAK_SENT;
	fsp->is_directory = false;

	fsp->print_file = pf;

	status = NT_STATUS_OK;
done:
	if (!NT_STATUS_IS_OK(status)) {
		if (fd != -1) {
			close(fd);
			if (fsp->print_file) {
				unlink(fsp->print_file->filename);
			}
		}
		/* We need to delete the job from spoolss too */
		if (pf->jobid) {
			print_spool_terminate(fsp->conn, pf);
		}
	}
	talloc_free(tmp_ctx);
	return status;
}
示例#14
0
/**
 * Check if file should be recycled
 **/
static int recycle_unlink(vfs_handle_struct *handle,
    const struct smb_filename *smb_fname)
{
	connection_struct *conn = handle->conn;
	char *path_name = NULL;
       	char *temp_name = NULL;
	char *final_name = NULL;
	struct smb_filename *smb_fname_final = NULL;
	const char *base;
	char *repository = NULL;
	int i = 1;
	SMB_OFF_T maxsize, minsize;
	SMB_OFF_T file_size; /* space_avail;	*/
	bool exist;
	NTSTATUS status;
	int rc = -1;

	repository = talloc_sub_advanced(NULL, lp_servicename(SNUM(conn)),
					conn->session_info->unix_name,
					conn->connectpath,
					conn->session_info->utok.gid,
					conn->session_info->sanitized_username,
					conn->session_info->info3->base.domain.string,
					recycle_repository(handle));
	ALLOC_CHECK(repository, done);
	/* shouldn't we allow absolute path names here? --metze */
	/* Yes :-). JRA. */
	trim_char(repository, '\0', '/');

	if(!repository || *(repository) == '\0') {
		DEBUG(3, ("recycle: repository path not set, purging %s...\n",
			  smb_fname_str_dbg(smb_fname)));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	/* we don't recycle the recycle bin... */
	if (strncmp(smb_fname->base_name, repository,
		    strlen(repository)) == 0) {
		DEBUG(3, ("recycle: File is within recycling bin, unlinking ...\n"));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	file_size = recycle_get_file_size(handle, smb_fname);
	/* it is wrong to purge filenames only because they are empty imho
	 *   --- simo
	 *
	if(fsize == 0) {
		DEBUG(3, ("recycle: File %s is empty, purging...\n", file_name));
		rc = SMB_VFS_NEXT_UNLINK(handle,file_name);
		goto done;
	}
	 */

	/* FIXME: this is wrong, we should check the whole size of the recycle bin is
	 * not greater then maxsize, not the size of the single file, also it is better
	 * to remove older files
	 */
	maxsize = recycle_maxsize(handle);
	if(maxsize > 0 && file_size > maxsize) {
		DEBUG(3, ("recycle: File %s exceeds maximum recycle size, "
			  "purging... \n", smb_fname_str_dbg(smb_fname)));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}
	minsize = recycle_minsize(handle);
	if(minsize > 0 && file_size < minsize) {
		DEBUG(3, ("recycle: File %s lowers minimum recycle size, "
			  "purging... \n", smb_fname_str_dbg(smb_fname)));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	/* FIXME: this is wrong: moving files with rename does not change the disk space
	 * allocation
	 *
	space_avail = SMB_VFS_NEXT_DISK_FREE(handle, ".", True, &bsize, &dfree, &dsize) * 1024L;
	DEBUG(5, ("space_avail = %Lu, file_size = %Lu\n", space_avail, file_size));
	if(space_avail < file_size) {
		DEBUG(3, ("recycle: Not enough diskspace, purging file %s\n", file_name));
		rc = SMB_VFS_NEXT_UNLINK(handle, file_name);
		goto done;
	}
	 */

	/* extract filename and path */
	base = strrchr(smb_fname->base_name, '/');
	if (base == NULL) {
		base = smb_fname->base_name;
		path_name = SMB_STRDUP("/");
		ALLOC_CHECK(path_name, done);
	}
	else {
		path_name = SMB_STRDUP(smb_fname->base_name);
		ALLOC_CHECK(path_name, done);
		path_name[base - smb_fname->base_name] = '\0';
		base++;
	}

	/* original filename with path */
	DEBUG(10, ("recycle: fname = %s\n", smb_fname_str_dbg(smb_fname)));
	/* original path */
	DEBUG(10, ("recycle: fpath = %s\n", path_name));
	/* filename without path */
	DEBUG(10, ("recycle: base = %s\n", base));

	if (matchparam(recycle_exclude(handle), base)) {
		DEBUG(3, ("recycle: file %s is excluded \n", base));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	if (matchdirparam(recycle_exclude_dir(handle), path_name)) {
		DEBUG(3, ("recycle: directory %s is excluded \n", path_name));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	if (recycle_keep_dir_tree(handle) == True) {
		if (asprintf(&temp_name, "%s/%s", repository, path_name) == -1) {
			ALLOC_CHECK(temp_name, done);
		}
	} else {
		temp_name = SMB_STRDUP(repository);
	}
	ALLOC_CHECK(temp_name, done);

	exist = recycle_directory_exist(handle, temp_name);
	if (exist) {
		DEBUG(10, ("recycle: Directory already exists\n"));
	} else {
		DEBUG(10, ("recycle: Creating directory %s\n", temp_name));
		if (recycle_create_dir(handle, temp_name) == False) {
			DEBUG(3, ("recycle: Could not create directory, "
				  "purging %s...\n",
				  smb_fname_str_dbg(smb_fname)));
			rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
			goto done;
		}
	}

	if (asprintf(&final_name, "%s/%s", temp_name, base) == -1) {
		ALLOC_CHECK(final_name, done);
	}

	/* Create smb_fname with final base name and orig stream name. */
	status = create_synthetic_smb_fname(talloc_tos(), final_name,
					    smb_fname->stream_name, NULL,
					    &smb_fname_final);
	if (!NT_STATUS_IS_OK(status)) {
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	/* new filename with path */
	DEBUG(10, ("recycle: recycled file name: %s\n",
		   smb_fname_str_dbg(smb_fname_final)));

	/* check if we should delete file from recycle bin */
	if (recycle_file_exist(handle, smb_fname_final)) {
		if (recycle_versions(handle) == False || matchparam(recycle_noversions(handle), base) == True) {
			DEBUG(3, ("recycle: Removing old file %s from recycle "
				  "bin\n", smb_fname_str_dbg(smb_fname_final)));
			if (SMB_VFS_NEXT_UNLINK(handle,
						smb_fname_final) != 0) {
				DEBUG(1, ("recycle: Error deleting old file: %s\n", strerror(errno)));
			}
		}
	}

	/* rename file we move to recycle bin */
	i = 1;
	while (recycle_file_exist(handle, smb_fname_final)) {
		SAFE_FREE(final_name);
		if (asprintf(&final_name, "%s/Copy #%d of %s", temp_name, i++, base) == -1) {
			ALLOC_CHECK(final_name, done);
		}
		TALLOC_FREE(smb_fname_final->base_name);
		smb_fname_final->base_name = talloc_strdup(smb_fname_final,
							   final_name);
		if (smb_fname_final->base_name == NULL) {
			rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
			goto done;
		}
	}

	DEBUG(10, ("recycle: Moving %s to %s\n", smb_fname_str_dbg(smb_fname),
		smb_fname_str_dbg(smb_fname_final)));
	rc = SMB_VFS_NEXT_RENAME(handle, smb_fname, smb_fname_final);
	if (rc != 0) {
		DEBUG(3, ("recycle: Move error %d (%s), purging file %s "
			  "(%s)\n", errno, strerror(errno),
			  smb_fname_str_dbg(smb_fname),
			  smb_fname_str_dbg(smb_fname_final)));
		rc = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
		goto done;
	}

	/* touch access date of moved file */
	if (recycle_touch(handle) == True || recycle_touch_mtime(handle))
		recycle_do_touch(handle, smb_fname_final,
				 recycle_touch_mtime(handle));

done:
	SAFE_FREE(path_name);
	SAFE_FREE(temp_name);
	SAFE_FREE(final_name);
	TALLOC_FREE(smb_fname_final);
	TALLOC_FREE(repository);
	return rc;
}
示例#15
0
connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
					int snum, user_struct *vuser,
					DATA_BLOB password,
					const char *pdev,
					NTSTATUS *pstatus)
{
	connection_struct *conn = NULL;
	struct smb_filename *smb_fname_cpath = NULL;
	fstring dev;
	int ret;
	bool on_err_call_dis_hook = false;
	bool claimed_connection = false;
	uid_t effuid;
	gid_t effgid;
	NTSTATUS status;

	fstrcpy(dev, pdev);

	*pstatus = share_sanity_checks(sconn->remote_address,
				       sconn->remote_hostname,
				       snum,
				       dev);
	if (NT_STATUS_IS_ERR(*pstatus)) {
		goto err_root_exit;
	}

	conn = conn_new(sconn);
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
		goto err_root_exit;
	}

	conn->params->service = snum;

	status = create_connection_session_info(sconn,
		conn, snum, vuser ? vuser->session_info : NULL, password,
		&conn->session_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("create_connection_session_info failed: %s\n",
			  nt_errstr(status)));
		*pstatus = status;
		goto err_root_exit;
	}

	if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
		conn->force_user = true;
	}

	add_session_user(sconn, conn->session_info->unix_info->unix_name);

	conn->num_files_open = 0;
	conn->lastused = conn->lastused_count = time(NULL);
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
		      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );

	/* Case options for the share. */
	if (lp_casesensitive(snum) == Auto) {
		/* We will be setting this per packet. Set to be case
		 * insensitive for now. */
		conn->case_sensitive = False;
	} else {
		conn->case_sensitive = (bool)lp_casesensitive(snum);
	}

	conn->case_preserve = lp_preservecase(snum);
	conn->short_case_preserve = lp_shortpreservecase(snum);

	conn->encrypt_level = lp_smb_encrypt(snum);

	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	conn->aio_write_behind_list = NULL;

	conn->read_only = lp_readonly(SNUM(conn));

	status = set_conn_force_user_group(conn, snum);
	if (!NT_STATUS_IS_OK(status)) {
		conn_free(conn);
		*pstatus = status;
		return NULL;
	}

	conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;

	{
		char *s = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_pathname(snum));
		if (!s) {
			*pstatus = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}

		if (!set_conn_connectpath(conn,s)) {
			TALLOC_FREE(s);
			*pstatus = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(snum)));
		TALLOC_FREE(s);
	}

	/*
	 * New code to check if there's a share security descripter
	 * added from NT server manager. This is done after the
	 * smb.conf checks are done as we need a uid and token. JRA.
	 *
	 */

	share_access_check(conn->session_info->security_token,
			   lp_servicename(snum), MAXIMUM_ALLOWED_ACCESS,
			   &conn->share_access);

	if ((conn->share_access & FILE_WRITE_DATA) == 0) {
		if ((conn->share_access & FILE_READ_DATA) == 0) {
			/* No access, read or write. */
			DEBUG(0,("make_connection: connection to %s "
				 "denied due to security "
				 "descriptor.\n",
				 lp_servicename(snum)));
			*pstatus = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		} else {
			conn->read_only = True;
		}
	}
	/* Initialise VFS function pointers */

	if (!smbd_vfs_init(conn)) {
		DEBUG(0, ("vfs_init failed for service %s\n",
			  lp_servicename(snum)));
		*pstatus = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}

/* ROOT Activities: */
	/* explicitly check widelinks here so that we can correctly warn
	 * in the logs. */
	widelinks_warning(snum);

	/*
	 * Enforce the max connections parameter.
	 */

	if ((lp_max_connections(snum) > 0)
	    && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
		lp_max_connections(snum))) {

		DEBUG(1, ("Max connections (%d) exceeded for %s\n",
			  lp_max_connections(snum), lp_servicename(snum)));
		*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
		goto err_root_exit;
	}

	/*
	 * Get us an entry in the connections db
	 */
	if (!claim_connection(conn, lp_servicename(snum))) {
		DEBUG(1, ("Could not store connections entry\n"));
		*pstatus = NT_STATUS_INTERNAL_DB_ERROR;
		goto err_root_exit;
	}
	claimed_connection = true;

	/* Invoke VFS make connection hook - this must be the first
	   filesystem operation that we do. */

	if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
			    conn->session_info->unix_info->unix_name) < 0) {
		DEBUG(0,("make_connection: VFS make connection failed!\n"));
		*pstatus = NT_STATUS_UNSUCCESSFUL;
		goto err_root_exit;
	}

	/* Any error exit after here needs to call the disconnect hook. */
	on_err_call_dis_hook = true;

	if ((!conn->printer) && (!conn->ipc)) {
		conn->notify_ctx = notify_init(conn,
					       messaging_server_id(sconn->msg_ctx),
					       sconn->msg_ctx,
					       sconn->ev_ctx,
					       conn);
	}

	/*
	 * Fix compatibility issue pointed out by Volker.
	 * We pass the conn->connectpath to the preexec
	 * scripts as a parameter, so attempt to canonicalize
	 * it here before calling the preexec scripts.
	 * We ignore errors here, as it is possible that
	 * the conn->connectpath doesn't exist yet and
	 * the preexec scripts will create them.
	 */

	(void)canonicalize_connect_path(conn);

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_rootpreexec(snum));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_rootpreexec_close(snum)) {
			DEBUG(1,("root preexec gave %d - failing "
				 "connection\n", ret));
			*pstatus = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

/* USER Activites: */
	if (!change_to_user(conn, conn->vuid)) {
		/* No point continuing if they fail the basic checks */
		DEBUG(0,("Can't become connected user!\n"));
		*pstatus = NT_STATUS_LOGON_FAILURE;
		goto err_root_exit;
	}

	effuid = geteuid();
	effgid = getegid();

	/* Remember that a different vuid can connect later without these
	 * checks... */

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */

	/* execute any "preexec = " line */
	if (*lp_preexec(snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_preexec(snum));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			*pstatus = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

#ifdef WITH_FAKE_KASERVER
	if (lp_afs_share(snum)) {
		afs_login(conn);
	}
#endif

	/*
	 * we've finished with the user stuff - go back to root
	 * so the SMB_VFS_STAT call will only fail on path errors,
	 * not permission problems.
	 */
	change_to_root_user();
/* ROOT Activites: */

	/*
	 * If widelinks are disallowed we need to canonicalise the connect
	 * path here to ensure we don't have any symlinks in the
	 * connectpath. We will be checking all paths on this connection are
	 * below this directory. We must do this after the VFS init as we
	 * depend on the realpath() pointer in the vfs table. JRA.
	 */
	if (!lp_widelinks(snum)) {
		if (!canonicalize_connect_path(conn)) {
			DEBUG(0, ("canonicalize_connect_path failed "
			"for service %s, path %s\n",
				lp_servicename(snum),
				conn->connectpath));
			*pstatus = NT_STATUS_BAD_NETWORK_NAME;
			goto err_root_exit;
		}
	}

	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(snum));
		set_namearray( &conn->hide_list, lp_hide_files(snum));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
		set_namearray( &conn->aio_write_behind_list,
				lp_aio_write_behind(snum));
	}
	status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
					    NULL, NULL, &smb_fname_cpath);
	if (!NT_STATUS_IS_OK(status)) {
		*pstatus = status;
		goto err_root_exit;
	}

	/* win2000 does not check the permissions on the directory
	   during the tree connect, instead relying on permission
	   check during individual operations. To match this behaviour
	   I have disabled this chdir check (tridge) */
	/* the alternative is just to check the directory exists */

	if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
	    !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
		if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
			DEBUG(0,("'%s' is not a directory, when connecting to "
				 "[%s]\n", conn->connectpath,
				 lp_servicename(snum)));
		} else {
			DEBUG(0,("'%s' does not exist or permission denied "
				 "when connecting to [%s] Error was %s\n",
				 conn->connectpath, lp_servicename(snum),
				 strerror(errno) ));
		}
		*pstatus = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}
	conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;

	string_set(&conn->origpath,conn->connectpath);

	/* Figure out the characteristics of the underlying filesystem. This
	 * assumes that all the filesystem mounted withing a share path have
	 * the same characteristics, which is likely but not guaranteed.
	 */

	conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using
	 * (at least initially).
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", get_remote_machine_name(),
			 tsocket_address_string(conn->sconn->remote_address,
						talloc_tos()) );
		dbgtext( "%s", srv_is_signing_active(sconn) ? "signed " : "");
		dbgtext( "connect to service %s ", lp_servicename(snum) );
		dbgtext( "initially as user %s ",
			 conn->session_info->unix_info->unix_name );
		dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
		dbgtext( "(pid %d)\n", (int)sys_getpid() );
	}

	return(conn);

  err_root_exit:
	TALLOC_FREE(smb_fname_cpath);
	/* We must exit this function as root. */
	if (geteuid() != 0) {
		change_to_root_user();
	}
	if (on_err_call_dis_hook) {
		/* Call VFS disconnect hook */
		SMB_VFS_DISCONNECT(conn);
	}
	if (claimed_connection) {
		yield_connection(conn, lp_servicename(snum));
	}
	if (conn) {
		conn_free(conn);
	}
	return NULL;
}
示例#16
0
static ssize_t vfs_my_module_pwrite(vfs_handle_struct *handle, files_struct *fsp,
			    const void *data, size_t n,
			    off_t offset)
{		connection_struct *conn = handle->conn;
	char *path_name = NULL;
       	char *temp_name = NULL;
	char *final_name = NULL;
	const struct smb_filename *smb_fname = fsp->fsp_name;
	struct smb_filename *smb_fname_final = NULL;
	const char *base;
	char *repository,*repositoryTemp = NULL;
	int i = 1;
	SMB_OFF_T maxsize, minsize;
	SMB_OFF_T file_size; /* space_avail;	*/
	bool exist;
	NTSTATUS status;
	ssize_t rc = -1;
    int count = 0;
    const char *share = "/mnt/share";
	repository = talloc_sub_advanced(NULL, lp_servicename(SNUM(conn)),
					conn->session_info->unix_name,
					conn->connectpath,
					conn->session_info->utok.gid,
					conn->session_info->sanitized_username,
					conn->session_info->info3->base.domain.string,
					sharevolume(handle));
	ALLOC_CHECK(repository, done);

	trim_char(repository, '\0', '/');

	if(!repository || *(repository) == '\0') {
		rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);
		goto done;
	}

    file_size = vfs_my_module_get_file_size(handle, smb_fname);
    maxsize = vfs_my_module_maxsize(handle);

    if(maxsize > 0 && file_size > maxsize){
    repository = talloc_sub_advanced(NULL, lp_servicename(SNUM(conn)),
					conn->session_info->unix_name,
					conn->connectpath,
					conn->session_info->utok.gid,
					conn->session_info->sanitized_username,
					conn->session_info->info3->base.domain.string,
					stripevolume(handle));
	ALLOC_CHECK(repository, done);

	trim_char(repository, '\0', '/');

	if(!repository || *(repository) == '\0') {
		rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);
		goto done;
	}
    }

	if (strncmp(smb_fname->base_name, repository,
		    strlen(repository)) == 0) {
		rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);
		goto done;
	}

	base = strrchr(smb_fname->base_name, '/');
	if (base == NULL) {
		base = smb_fname->base_name;
		path_name = SMB_STRDUP("/");
		ALLOC_CHECK(path_name, done);
	}
	else {
		path_name = SMB_STRDUP(smb_fname->base_name);
		ALLOC_CHECK(path_name, done);
		path_name[base - smb_fname->base_name] = '\0';
		base++;
	}

	/* original filename with path */
	DEBUG(10, ("file transaction: fname = %s\n", smb_fname_str_dbg(smb_fname)));
	/* original path */
	DEBUG(10, ("file transaction: fpath = %s\n", path_name));
	/* filename without path */
	DEBUG(10, ("file transaction: base = %s\n", base));

    if (vfs_my_module_keep_dir_tree(handle) == True) {
		if (asprintf(&temp_name, "%s/%s", repository, path_name) == -1) {
			ALLOC_CHECK(temp_name, done);
		}
	} else {
		temp_name = SMB_STRDUP(repository);
	}

	ALLOC_CHECK(temp_name, done);
	exist = vfs_my_module_directory_exist(handle, temp_name);
	if (exist) {
		DEBUG(10, ("file transaction: Directory already exists\n"));
	} else {
		DEBUG(10, ("file transaction: Creating directory %s\n", temp_name));
		count = vfs_my_module_create_dir(handle, temp_name, smb_fname);
	}
	if (asprintf(&final_name, "%s/%s", temp_name, base) == -1) {
		ALLOC_CHECK(final_name, done);
	}

	/* Create smb_fname with final base name and orig stream name. */
	status = create_synthetic_smb_fname(talloc_tos(), final_name,
					    smb_fname->stream_name, NULL,
					    &smb_fname_final);
	if (!NT_STATUS_IS_OK(status)) {
		rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);
		goto done;
	}

		TALLOC_FREE(smb_fname_final->base_name);
		smb_fname_final->base_name = talloc_strdup(smb_fname_final,
							   final_name);
		if (smb_fname_final->base_name == NULL) {
			rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);
			goto done;
		}

	SMB_VFS_NEXT_RENAME(handle, smb_fname, smb_fname_final);
	rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);

	if (rc != 0) {
		rc = SMB_VFS_NEXT_PWRITE(handle, fsp,data,n,offset);
		goto done;
	}

done:
    vfs_my_module_delete_dir(handle,path_name,smb_fname);
    while(count !=0){
    vfs_my_module_delete_dir(handle,path_name,smb_fname);
    SMB_VFS_NEXT_RMDIR(handle, path_name);
    count--;
    }
	SAFE_FREE(path_name);
	SAFE_FREE(temp_name);
	SAFE_FREE(final_name);
	TALLOC_FREE(smb_fname_final);
	TALLOC_FREE(repository);
	return rc;
}