Example #1
0
//static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_BIG_UINT pos,size_t n)
/*  modified end pling 11/25/2009 */
{
	write_cache *wcp = fsp->wcp;

	if(!wcp)
		return False;

	if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size)
		return False;

	memcpy(data, wcp->data + (pos - wcp->offset), n);

	DO_PROFILE_INC(writecache_read_hits);

	return True;
}
Example #2
0
static bool read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n)
{
	write_cache *wcp = fsp->wcp;

	if(!wcp) {
		return False;
	}

	if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) {
		return False;
	}

	memcpy(data, wcp->data + (pos - wcp->offset), n);

	DO_PROFILE_INC(writecache_read_hits);

	return True;
}
static bool become_uid(uid_t uid)
{
	/* Check for dodgy uid values */

	if (uid == (uid_t)-1 || 
	    ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) {
		if (!become_uid_done) {
			DEBUG(1,("WARNING: using uid %d is a security risk\n",
				 (int)uid));
			become_uid_done = true;
		}
	}

	/* Set effective user id */

	set_effective_uid(uid);

	DO_PROFILE_INC(uid_changes);
	return True;
}
Example #4
0
ssize_t write_file(struct smb_request *req,
			files_struct *fsp,
			const char *data,
			SMB_OFF_T pos,
			size_t n)
{
	write_cache *wcp = fsp->wcp;
	ssize_t total_written = 0;
	int write_path = -1;

	if (fsp->print_file) {
		uint32_t t;
		int ret;

		ret = print_spool_write(fsp, data, n, pos, &t);
		if (ret) {
			errno = ret;
			return -1;
		}
		return t;
	}

	if (!fsp->can_write) {
		errno = EPERM;
		return -1;
	}

	if (!fsp->modified) {
		fsp->modified = True;

		if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) {
			trigger_write_time_update(fsp);
			if (!fsp->posix_open &&
					(lp_store_dos_attributes(SNUM(fsp->conn)) ||
					MAP_ARCHIVE(fsp->conn))) {
				int dosmode = dos_mode(fsp->conn, fsp->fsp_name);
				if (!IS_DOS_ARCHIVE(dosmode)) {
					file_set_dosmode(fsp->conn, fsp->fsp_name,
						 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
				}
			}

			/*
			 * If this is the first write and we have an exclusive oplock then setup
			 * the write cache.
			 */

			if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
				setup_write_cache(fsp,
						 fsp->fsp_name->st.st_ex_size);
				wcp = fsp->wcp;
			}
		}
	}

#ifdef WITH_PROFILE
	DO_PROFILE_INC(writecache_total_writes);
	if (!fsp->oplock_type) {
		DO_PROFILE_INC(writecache_non_oplock_writes);
	}
#endif

	/*
	 * If this file is level II oplocked then we need
	 * to grab the shared memory lock and inform all
	 * other files with a level II lock that they need
	 * to flush their read caches. We keep the lock over
	 * the shared memory area whilst doing this.
	 */

	/* This should actually be improved to span the write. */
	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);

#ifdef WITH_PROFILE
	if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
		DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
			profile_p->writecache_init_writes,
			profile_p->writecache_abutted_writes,
			profile_p->writecache_total_writes,
			profile_p->writecache_non_oplock_writes,
			profile_p->writecache_allocated_write_caches,
			profile_p->writecache_num_write_caches,
			profile_p->writecache_direct_writes,
			profile_p->writecache_num_perfect_writes,
			profile_p->writecache_read_hits ));

		DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
			profile_p->writecache_flushed_writes[SEEK_FLUSH],
			profile_p->writecache_flushed_writes[READ_FLUSH],
			profile_p->writecache_flushed_writes[WRITE_FLUSH],
			profile_p->writecache_flushed_writes[READRAW_FLUSH],
			profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
			profile_p->writecache_flushed_writes[CLOSE_FLUSH],
			profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
	}
Example #5
0
static void exit_server_common(enum server_exit_reason how,
	const char *reason)
{
	struct smbXsrv_client *client = global_smbXsrv_client;
	struct smbXsrv_connection *xconn = NULL;
	struct smbd_server_connection *sconn = NULL;
	struct messaging_context *msg_ctx = server_messaging_context();

	if (client != NULL) {
		sconn = client->sconn;
		/*
		 * Here we typically have just one connection
		 */
		xconn = client->connections;
	}

	if (!exit_firsttime)
		exit(0);
	exit_firsttime = false;

	change_to_root_user();

	if (xconn != NULL) {
		/*
		 * This is typically the disconnect for the only
		 * (or with multi-channel last) connection of the client
		 */
		if (NT_STATUS_IS_OK(xconn->transport.status)) {
			switch (how) {
			case SERVER_EXIT_ABNORMAL:
				xconn->transport.status = NT_STATUS_INTERNAL_ERROR;
				break;
			case SERVER_EXIT_NORMAL:
				xconn->transport.status = NT_STATUS_LOCAL_DISCONNECT;
				break;
			}
		}

		TALLOC_FREE(xconn->smb1.negprot.auth_context);
	}

	change_to_root_user();

	if (sconn != NULL) {
		if (lp_log_writeable_files_on_exit()) {
			bool found = false;
			files_forall(sconn, log_writeable_file_fn, &found);
		}
	}

	change_to_root_user();

	if (xconn != NULL) {
		NTSTATUS status;

		/*
		 * Note: this is a no-op for smb2 as
		 * conn->tcon_table is empty
		 */
		status = smb1srv_tcon_disconnect_all(xconn);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0,("Server exit (%s)\n",
				(reason ? reason : "normal exit")));
			DEBUG(0, ("exit_server_common: "
				  "smb1srv_tcon_disconnect_all() failed (%s) - "
				  "triggering cleanup\n", nt_errstr(status)));
		}

		status = smbXsrv_session_logoff_all(xconn);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0,("Server exit (%s)\n",
				(reason ? reason : "normal exit")));
			DEBUG(0, ("exit_server_common: "
				  "smbXsrv_session_logoff_all() failed (%s) - "
				  "triggering cleanup\n", nt_errstr(status)));
		}
	}

	change_to_root_user();

	/* 3 second timeout. */
	print_notify_send_messages(msg_ctx, 3);

#ifdef USE_DMAPI
	/* Destroy Samba DMAPI session only if we are master smbd process */
	if (am_parent) {
		if (!dmapi_destroy_session()) {
			DEBUG(0,("Unable to close Samba DMAPI session\n"));
		}
	}
#endif

	if (am_parent) {
		rpc_wkssvc_shutdown();
		rpc_dssetup_shutdown();
#ifdef DEVELOPER
		rpc_rpcecho_shutdown();
#endif
		rpc_netdfs_shutdown();
		rpc_initshutdown_shutdown();
		rpc_eventlog_shutdown();
		rpc_ntsvcs_shutdown();
		rpc_svcctl_shutdown();
		rpc_spoolss_shutdown();

		rpc_srvsvc_shutdown();
		rpc_winreg_shutdown();

		rpc_netlogon_shutdown();
		rpc_samr_shutdown();
		rpc_lsarpc_shutdown();
	}

	/*
	 * we need to force the order of freeing the following,
	 * because smbd_msg_ctx is not a talloc child of smbd_server_conn.
	 */
	if (client != NULL) {
		struct smbXsrv_connection *next;

		for (; xconn != NULL; xconn = next) {
			next = xconn->next;
			DLIST_REMOVE(client->connections, xconn);
			talloc_free(xconn);
			DO_PROFILE_INC(disconnect);
		}
		TALLOC_FREE(client->sconn);
	}
	sconn = NULL;
	xconn = NULL;
	client = NULL;
	netlogon_creds_cli_close_global_db();
	TALLOC_FREE(global_smbXsrv_client);
	smbprofile_dump();
	server_messaging_context_free();
	server_event_context_free();
	TALLOC_FREE(smbd_memcache_ctx);

	locking_end();
	printing_end();

	if (how != SERVER_EXIT_NORMAL) {

		smb_panic(reason);

		/* Notreached. */
		exit(1);
	} else {
		DEBUG(3,("Server exit (%s)\n",
			(reason ? reason : "normal exit")));
		if (am_parent) {
			pidfile_unlink(lp_pid_directory(), "smbd");
		}
		gencache_stabilize();
	}

	exit(0);
}
Example #6
0
ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n)
{
    write_cache *wcp = fsp->wcp;
    ssize_t total_written = 0;
    int write_path = -1;

    if (fsp->print_file) {
#ifdef AVM_NO_PRINTING
        errno = EBADF;
        return -1;
#else
        fstring sharename;
        uint32 jobid;

        if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
            DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
                     (unsigned int)fsp->rap_print_jobid ));
            errno = EBADF;
            return -1;
        }

        return print_job_write(SNUM(fsp->conn), jobid, data, pos, n);
#endif /* AVM_NO_PRINTING */
    }

    if (!fsp->can_write) {
        errno = EPERM;
        return(0);
    }

    if (!fsp->modified) {
        SMB_STRUCT_STAT st;
        fsp->modified = True;

        if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
            int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
            if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) {
                file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False);
            }

            /*
             * If this is the first write and we have an exclusive oplock then setup
             * the write cache.
             */

            if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
                setup_write_cache(fsp, st.st_size);
                wcp = fsp->wcp;
            }
        }
    }

#ifdef WITH_PROFILE
    DO_PROFILE_INC(writecache_total_writes);
    if (!fsp->oplock_type) {
        DO_PROFILE_INC(writecache_non_oplock_writes);
    }
#endif

    /*
     * If this file is level II oplocked then we need
     * to grab the shared memory lock and inform all
     * other files with a level II lock that they need
     * to flush their read caches. We keep the lock over
     * the shared memory area whilst doing this.
     */

    release_level_2_oplocks_on_change(fsp);

#ifdef WITH_PROFILE
    if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
        DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
                 profile_p->writecache_init_writes,
                 profile_p->writecache_abutted_writes,
                 profile_p->writecache_total_writes,
                 profile_p->writecache_non_oplock_writes,
                 profile_p->writecache_allocated_write_caches,
                 profile_p->writecache_num_write_caches,
                 profile_p->writecache_direct_writes,
                 profile_p->writecache_num_perfect_writes,
                 profile_p->writecache_read_hits ));

        DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
                 profile_p->writecache_flushed_writes[SEEK_FLUSH],
                 profile_p->writecache_flushed_writes[READ_FLUSH],
                 profile_p->writecache_flushed_writes[WRITE_FLUSH],
                 profile_p->writecache_flushed_writes[READRAW_FLUSH],
                 profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
                 profile_p->writecache_flushed_writes[CLOSE_FLUSH],
                 profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
    }
ssize_t write_file(struct smb_request *req,
			files_struct *fsp,
			const char *data,
			off_t pos,
			size_t n)
{
	struct write_cache *wcp = fsp->wcp;
	ssize_t total_written = 0;
	int write_path = -1;

	if (fsp->print_file) {
		uint32_t t;
		int ret;

		ret = print_spool_write(fsp, data, n, pos, &t);
		if (ret) {
			errno = ret;
			return -1;
		}
		return t;
	}

	if (!fsp->can_write) {
		errno = EPERM;
		return -1;
	}

	/*
	 * If this is the first write and we have an exclusive oplock
	 * then setup the write cache.
	 */

	if (!fsp->modified &&
	    EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
	    (wcp == NULL)) {
		setup_write_cache(fsp, fsp->fsp_name->st.st_ex_size);
		wcp = fsp->wcp;
	}

	mark_file_modified(fsp);

#ifdef WITH_PROFILE
	DO_PROFILE_INC(writecache_total_writes);
	if (!fsp->oplock_type) {
		DO_PROFILE_INC(writecache_non_oplock_writes);
	}
#endif

	/*
	 * If this file is level II oplocked then we need
	 * to grab the shared memory lock and inform all
	 * other files with a level II lock that they need
	 * to flush their read caches. We keep the lock over
	 * the shared memory area whilst doing this.
	 */

	/* This should actually be improved to span the write. */
	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);

#ifdef WITH_PROFILE
	if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
		DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
			profile_p->writecache_init_writes,
			profile_p->writecache_abutted_writes,
			profile_p->writecache_total_writes,
			profile_p->writecache_non_oplock_writes,
			profile_p->writecache_allocated_write_caches,
			profile_p->writecache_num_write_caches,
			profile_p->writecache_direct_writes,
			profile_p->writecache_num_perfect_writes,
			profile_p->writecache_read_hits ));

		DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
			profile_p->writecache_flushed_writes[SEEK_FLUSH],
			profile_p->writecache_flushed_writes[READ_FLUSH],
			profile_p->writecache_flushed_writes[WRITE_FLUSH],
			profile_p->writecache_flushed_writes[READRAW_FLUSH],
			profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
			profile_p->writecache_flushed_writes[CLOSE_FLUSH],
			profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
	}
Example #8
0
bool stat_cache_lookup(connection_struct *conn,
			bool posix_paths,
			char **pp_name,
			char **pp_dirpath,
			char **pp_start,
			SMB_STRUCT_STAT *pst)
{
	char *chk_name;
	size_t namelen;
	bool sizechanged = False;
	unsigned int num_components = 0;
	char *translated_path;
	size_t translated_path_length;
	DATA_BLOB data_val;
	char *name;
	TALLOC_CTX *ctx = talloc_tos();
	struct smb_filename smb_fname;
	int ret;

	*pp_dirpath = NULL;
	*pp_start = *pp_name;

	if (!lp_stat_cache()) {
		return False;
	}

	name = *pp_name;
	namelen = strlen(name);

	DO_PROFILE_INC(statcache_lookups);

	/*
	 * Don't lookup trivial valid directory entries.
	 */
	if ((*name == '\0') || ISDOT(name) || ISDOTDOT(name)) {
		return False;
	}

	if (conn->case_sensitive) {
		chk_name = talloc_strdup(ctx,name);
		if (!chk_name) {
			DEBUG(0, ("stat_cache_lookup: strdup failed!\n"));
			return False;
		}

	} else {
		chk_name = talloc_strdup_upper(ctx,name);
		if (!chk_name) {
			DEBUG(0, ("stat_cache_lookup: talloc_strdup_upper failed!\n"));
			return False;
		}

		/*
		 * In some language encodings the length changes
		 * if we uppercase. We need to treat this differently
		 * below.
		 */
		if (strlen(chk_name) != namelen) {
			sizechanged = True;
		}
	}

	while (1) {
		char *sp;

		data_val = data_blob_null;

		if (memcache_lookup(
			    smbd_memcache(), STAT_CACHE,
			    data_blob_const(chk_name, strlen(chk_name)),
			    &data_val)) {
			break;
		}

		DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n",
				chk_name ));
		/*
		 * Didn't find it - remove last component for next try.
		 */
		if (!(sp = strrchr_m(chk_name, '/'))) {
			/*
			 * We reached the end of the name - no match.
			 */
			DO_PROFILE_INC(statcache_misses);
			TALLOC_FREE(chk_name);
			return False;
		}

		*sp = '\0';

		/*
		 * Count the number of times we have done this, we'll
		 * need it when reconstructing the string.
		 */

		if (sizechanged) {
			num_components++;
		}

		if ((*chk_name == '\0')
		    || ISDOT(chk_name) || ISDOTDOT(chk_name)) {
			DO_PROFILE_INC(statcache_misses);
			TALLOC_FREE(chk_name);
			return False;
		}
	}

	translated_path = talloc_strdup(ctx,(char *)data_val.data);
	if (!translated_path) {
		smb_panic("talloc failed");
	}
	translated_path_length = data_val.length - 1;

	DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] "
		  "-> [%s]\n", chk_name, translated_path ));
	DO_PROFILE_INC(statcache_hits);

	ZERO_STRUCT(smb_fname);
	smb_fname.base_name = translated_path;

	if (posix_paths) {
		ret = SMB_VFS_LSTAT(conn, &smb_fname);
	} else {
		ret = SMB_VFS_STAT(conn, &smb_fname);
	}

	if (ret != 0) {
		/* Discard this entry - it doesn't exist in the filesystem. */
		memcache_delete(smbd_memcache(), STAT_CACHE,
				data_blob_const(chk_name, strlen(chk_name)));
		TALLOC_FREE(chk_name);
		TALLOC_FREE(translated_path);
		return False;
	}
	*pst = smb_fname.st;

	if (!sizechanged) {
		memcpy(*pp_name, translated_path,
		       MIN(namelen, translated_path_length));
	} else {
		if (num_components == 0) {
			name = talloc_strndup(ctx, translated_path,
					   translated_path_length);
		} else {
			char *sp;

			sp = strnrchr_m(name, '/', num_components);
			if (sp) {
				name = talloc_asprintf(ctx,"%.*s%s",
					 (int)translated_path_length,
					 translated_path, sp);
			} else {
				name = talloc_strndup(ctx,
						translated_path,
						translated_path_length);
			}
		}
		if (name == NULL) {
			/*
			 * TODO: Get us out of here with a real error message
			 */
			smb_panic("talloc failed");
		}
		TALLOC_FREE(*pp_name);
		*pp_name = name;
	}


	/* set pointer for 'where to start' on fixing the rest of the name */
	*pp_start = &name[translated_path_length];
	if (**pp_start == '/') {
		++*pp_start;
	}

	*pp_dirpath = translated_path;
	TALLOC_FREE(chk_name);
	return (namelen == translated_path_length);
}