예제 #1
0
/*
 * Mapper function is used to avoid multiple connections for each session
 * write or read requests. After processing the request, it does not close
 * the connection, but waits for the next request.
 */
static int
on_mp_write_session_mapper(struct query_state *qstate)
{
	ssize_t	result;
	int		elem_type;

	TRACE_IN(on_mp_write_session_mapper);
	if (qstate->kevent_watermark == 0) {
		qstate->kevent_watermark = sizeof(int);
	} else {
		result = qstate->read_func(qstate, &elem_type, sizeof(int));
		if (result != sizeof(int)) {
			LOG_ERR_3("on_mp_write_session_mapper",
				"read failed");
			TRACE_OUT(on_mp_write_session_mapper);
			return (-1);
		}

		switch (elem_type) {
		case CET_MP_WRITE_SESSION_WRITE_REQUEST:
			qstate->kevent_watermark = sizeof(size_t);
			qstate->process_func =
				on_mp_write_session_write_request_read1;
			break;
		case CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION:
			qstate->kevent_watermark = 0;
			qstate->process_func =
				on_mp_write_session_abandon_notification;
			break;
		case CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION:
			qstate->kevent_watermark = 0;
			qstate->process_func =
				on_mp_write_session_close_notification;
			break;
		default:
			qstate->kevent_watermark = 0;
			qstate->process_func = NULL;
			LOG_ERR_2("on_mp_write_session_mapper",
				"unknown element type");
			TRACE_OUT(on_mp_write_session_mapper);
			return (-1);
		}
	}
	TRACE_OUT(on_mp_write_session_mapper);
	return (0);
}
예제 #2
0
static int
on_transform_request_process(struct query_state *qstate)
{
	struct cache_transform_request *transform_request;
	struct cache_transform_response *transform_response;
	struct configuration_entry *config_entry;
	size_t	i, size;

	TRACE_IN(on_transform_request_process);
	init_comm_element(&qstate->response, CET_TRANSFORM_RESPONSE);
	transform_response = get_cache_transform_response(&qstate->response);
	transform_request = get_cache_transform_request(&qstate->request);

	switch (transform_request->transformation_type) {
	case TT_USER:
		if (transform_request->entry == NULL) {
			size = configuration_get_entries_size(s_configuration);
			for (i = 0; i < size; ++i) {
			    config_entry = configuration_get_entry(
				s_configuration, i);

			    if (config_entry->perform_actual_lookups == 0)
				clear_config_entry_part(config_entry,
				    qstate->eid_str, qstate->eid_str_length);
			}
		} else {
			qstate->config_entry = configuration_find_entry(
				s_configuration, transform_request->entry);

			if (qstate->config_entry == NULL) {
				LOG_ERR_2("transform_request",
					"can't find configuration"
					" entry '%s'. aborting request",
					transform_request->entry);
				transform_response->error_code = -1;
				goto fin;
			}

			if (qstate->config_entry->perform_actual_lookups != 0) {
				LOG_ERR_2("transform_request",
					"can't transform the cache entry %s"
					", because it ised for actual lookups",
					transform_request->entry);
				transform_response->error_code = -1;
				goto fin;
			}

			clear_config_entry_part(qstate->config_entry,
				qstate->eid_str, qstate->eid_str_length);
		}
		break;
	case TT_ALL:
		if (qstate->euid != 0)
			transform_response->error_code = -1;
		else {
			if (transform_request->entry == NULL) {
				size = configuration_get_entries_size(
					s_configuration);
				for (i = 0; i < size; ++i) {
				    clear_config_entry(
					configuration_get_entry(
						s_configuration, i));
				}
			} else {
				qstate->config_entry = configuration_find_entry(
					s_configuration,
					transform_request->entry);

				if (qstate->config_entry == NULL) {
					LOG_ERR_2("transform_request",
						"can't find configuration"
						" entry '%s'. aborting request",
						transform_request->entry);
					transform_response->error_code = -1;
					goto fin;
				}

				clear_config_entry(qstate->config_entry);
			}
		}
		break;
	default:
		transform_response->error_code = -1;
	}

fin:
	qstate->kevent_watermark = 0;
	qstate->process_func = on_transform_response_write1;
	TRACE_OUT(on_transform_request_process);
	return (0);
}
예제 #3
0
static int
on_read_request_process(struct query_state *qstate)
{
	struct cache_read_request *read_request;
	struct cache_read_response *read_response;
	cache_entry	c_entry, neg_c_entry;

	struct agent	*lookup_agent;
	struct common_agent *c_agent;
	int res;

	TRACE_IN(on_read_request_process);
	init_comm_element(&qstate->response, CET_READ_RESPONSE);
	read_response = get_cache_read_response(&qstate->response);
	read_request = get_cache_read_request(&qstate->request);

	qstate->config_entry = configuration_find_entry(
		s_configuration, read_request->entry);
	if (qstate->config_entry == NULL) {
		read_response->error_code = ENOENT;

		LOG_ERR_2("read_request",
			"can't find configuration "
			"entry '%s'. aborting request", read_request->entry);
		goto fin;
	}

	if (qstate->config_entry->enabled == 0) {
		read_response->error_code = EACCES;

		LOG_ERR_2("read_request",
			"configuration entry '%s' is disabled",
			read_request->entry);
		goto fin;
	}

	/*
	 * if we perform lookups by ourselves, then we don't need to separate
	 * cache entries by euid and egid
	 */
	if (qstate->config_entry->perform_actual_lookups != 0)
		memset(read_request->cache_key, 0, qstate->eid_str_length);
	else {
#ifdef NS_NSCD_EID_CHECKING
		if (check_query_eids(qstate) != 0) {
		/* if the lookup is not self-performing, we check for clients euid/egid */
			read_response->error_code = EPERM;
			goto fin;
		}
#endif
	}

	configuration_lock_rdlock(s_configuration);
	c_entry = find_cache_entry(s_cache,
		qstate->config_entry->positive_cache_params.entry_name);
	neg_c_entry = find_cache_entry(s_cache,
		qstate->config_entry->negative_cache_params.entry_name);
	configuration_unlock(s_configuration);
	if ((c_entry != NULL) && (neg_c_entry != NULL)) {
		configuration_lock_entry(qstate->config_entry, CELT_POSITIVE);
		qstate->config_entry->positive_cache_entry = c_entry;
		read_response->error_code = cache_read(c_entry,
			read_request->cache_key,
			read_request->cache_key_size, NULL,
			&read_response->data_size);

		if (read_response->error_code == -2) {
			read_response->data = (char *)malloc(
				read_response->data_size);
			assert(read_response != NULL);
			read_response->error_code = cache_read(c_entry,
				read_request->cache_key,
				read_request->cache_key_size,
				read_response->data,
				&read_response->data_size);
		}
		configuration_unlock_entry(qstate->config_entry, CELT_POSITIVE);

		configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
		qstate->config_entry->negative_cache_entry = neg_c_entry;
		if (read_response->error_code == -1) {
			read_response->error_code = cache_read(neg_c_entry,
				read_request->cache_key,
				read_request->cache_key_size, NULL,
				&read_response->data_size);

			if (read_response->error_code == -2) {
				read_response->error_code = 0;
				read_response->data = NULL;
				read_response->data_size = 0;
			}
		}
		configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);

		if ((read_response->error_code == -1) &&
			(qstate->config_entry->perform_actual_lookups != 0)) {
			free(read_response->data);
			read_response->data = NULL;
			read_response->data_size = 0;

			lookup_agent = find_agent(s_agent_table,
				read_request->entry, COMMON_AGENT);

			if ((lookup_agent != NULL) &&
			(lookup_agent->type == COMMON_AGENT)) {
				c_agent = (struct common_agent *)lookup_agent;
				res = c_agent->lookup_func(
					read_request->cache_key +
						qstate->eid_str_length,
					read_request->cache_key_size -
						qstate->eid_str_length,
					&read_response->data,
					&read_response->data_size);

				if (res == NS_SUCCESS) {
					read_response->error_code = 0;
					configuration_lock_entry(
						qstate->config_entry,
						CELT_POSITIVE);
					cache_write(c_entry,
						read_request->cache_key,
						read_request->cache_key_size,
						read_response->data,
						read_response->data_size);
					configuration_unlock_entry(
						qstate->config_entry,
						CELT_POSITIVE);
				} else if ((res == NS_NOTFOUND) ||
					  (res == NS_RETURN)) {
					configuration_lock_entry(
						  qstate->config_entry,
						  CELT_NEGATIVE);
					cache_write(neg_c_entry,
						read_request->cache_key,
						read_request->cache_key_size,
						negative_data,
						sizeof(negative_data));
					configuration_unlock_entry(
						  qstate->config_entry,
						  CELT_NEGATIVE);

					read_response->error_code = 0;
					read_response->data = NULL;
					read_response->data_size = 0;
				}
			}
		}

		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
			memcpy(&qstate->timeout,
				&qstate->config_entry->common_query_timeout,
				sizeof(struct timeval));
	} else
		read_response->error_code = -1;

fin:
	qstate->kevent_filter = EVFILT_WRITE;
	if (read_response->error_code == 0)
		qstate->kevent_watermark = sizeof(int) + sizeof(size_t);
	else
		qstate->kevent_watermark = sizeof(int);
	qstate->process_func = on_read_response_write1;

	TRACE_OUT(on_read_request_process);
	return (0);
}
예제 #4
0
static int
on_negative_write_request_process(struct query_state *qstate)
{
	struct cache_write_request	*write_request;
	struct cache_write_response	*write_response;
	cache_entry c_entry;

	TRACE_IN(on_negative_write_request_process);
	init_comm_element(&qstate->response, CET_WRITE_RESPONSE);
	write_response = get_cache_write_response(&qstate->response);
	write_request = get_cache_write_request(&qstate->request);

	qstate->config_entry = configuration_find_entry(
		s_configuration, write_request->entry);

	if (qstate->config_entry == NULL) {
		write_response->error_code = ENOENT;

		LOG_ERR_2("negative_write_request",
			"can't find configuration"
			" entry '%s'. aborting request", write_request->entry);
		goto fin;
	}

	if (qstate->config_entry->enabled == 0) {
		write_response->error_code = EACCES;

		LOG_ERR_2("negative_write_request",
			"configuration entry '%s' is disabled",
			write_request->entry);
		goto fin;
	}

	if (qstate->config_entry->perform_actual_lookups != 0) {
		write_response->error_code = EOPNOTSUPP;

		LOG_ERR_2("negative_write_request",
			"entry '%s' performs lookups by itself: "
			"can't write to it", write_request->entry);
		goto fin;
	} else {
#ifdef NS_NSCD_EID_CHECKING
		if (check_query_eids(qstate) != 0) {
			write_response->error_code = EPERM;
			goto fin;
		}
#endif
	}

	configuration_lock_rdlock(s_configuration);
	c_entry = find_cache_entry(s_cache,
		qstate->config_entry->negative_cache_params.entry_name);
	configuration_unlock(s_configuration);
	if (c_entry != NULL) {
		configuration_lock_entry(qstate->config_entry, CELT_NEGATIVE);
		qstate->config_entry->negative_cache_entry = c_entry;
		write_response->error_code = cache_write(c_entry,
			write_request->cache_key,
			write_request->cache_key_size,
			negative_data,
			sizeof(negative_data));
		configuration_unlock_entry(qstate->config_entry, CELT_NEGATIVE);

		if ((qstate->config_entry->common_query_timeout.tv_sec != 0) ||
		    (qstate->config_entry->common_query_timeout.tv_usec != 0))
			memcpy(&qstate->timeout,
				&qstate->config_entry->common_query_timeout,
				sizeof(struct timeval));
	} else
		write_response->error_code = -1;

fin:
	qstate->kevent_filter = EVFILT_WRITE;
	qstate->kevent_watermark = sizeof(int);
	qstate->process_func = on_write_response_write1;

	TRACE_OUT(on_negative_write_request_process);
	return (0);
}
예제 #5
0
static int
on_mp_write_session_request_process(struct query_state *qstate)
{
	struct cache_mp_write_session_request	*c_mp_ws_request;
	struct cache_mp_write_session_response	*c_mp_ws_response;
	cache_mp_write_session	ws;
	cache_entry	c_entry;
	char	*dec_cache_entry_name;

	TRACE_IN(on_mp_write_session_request_process);
	init_comm_element(&qstate->response, CET_MP_WRITE_SESSION_RESPONSE);
	c_mp_ws_response = get_cache_mp_write_session_response(
		&qstate->response);
	c_mp_ws_request = get_cache_mp_write_session_request(&qstate->request);

	qstate->config_entry = configuration_find_entry(
		s_configuration, c_mp_ws_request->entry);
	if (qstate->config_entry == NULL) {
		c_mp_ws_response->error_code = ENOENT;

		LOG_ERR_2("write_session_request",
			"can't find configuration entry '%s'. "
	    		"aborting request", c_mp_ws_request->entry);
	    	goto fin;
	}

	if (qstate->config_entry->enabled == 0) {
		c_mp_ws_response->error_code = EACCES;

		LOG_ERR_2("write_session_request",
			"configuration entry '%s' is disabled",
			c_mp_ws_request->entry);
		goto fin;
	}

	if (qstate->config_entry->perform_actual_lookups != 0) {
		c_mp_ws_response->error_code = EOPNOTSUPP;

		LOG_ERR_2("write_session_request",
			"entry '%s' performs lookups by itself: "
			"can't write to it", c_mp_ws_request->entry);
		goto fin;
	} else {
#ifdef NS_NSCD_EID_CHECKING
		if (check_query_eids(qstate) != 0) {
			c_mp_ws_response->error_code = EPERM;
			goto fin;
		}
#endif
	}

	/*
	 * All multipart entries are separated by their name decorations.
	 * For one configuration entry there will be a lot of multipart
	 * cache entries - each with its own decorated name.
	 */
	asprintf(&dec_cache_entry_name, "%s%s", qstate->eid_str,
		qstate->config_entry->mp_cache_params.cep.entry_name);
	assert(dec_cache_entry_name != NULL);

	configuration_lock_rdlock(s_configuration);
	c_entry = find_cache_entry(s_cache,
		dec_cache_entry_name);
	configuration_unlock(s_configuration);

	if (c_entry == INVALID_CACHE_ENTRY)
		c_entry = register_new_mp_cache_entry(qstate,
			dec_cache_entry_name);

	free(dec_cache_entry_name);

	assert(c_entry != NULL);
	configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
	ws = open_cache_mp_write_session(c_entry);
	if (ws == INVALID_CACHE_MP_WRITE_SESSION)
		c_mp_ws_response->error_code = -1;
	else {
		qstate->mdata = ws;
		qstate->destroy_func = on_mp_write_session_destroy;

		if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) ||
		    (qstate->config_entry->mp_query_timeout.tv_usec != 0))
			memcpy(&qstate->timeout,
				&qstate->config_entry->mp_query_timeout,
				sizeof(struct timeval));
	}
	configuration_unlock_entry(qstate->config_entry, CELT_MULTIPART);

fin:
	qstate->process_func = on_mp_write_session_response_write1;
	qstate->kevent_watermark = sizeof(int);
	qstate->kevent_filter = EVFILT_WRITE;

	TRACE_OUT(on_mp_write_session_request_process);
	return (0);
}
예제 #6
0
파일: parser.c 프로젝트: 2asoft/freebsd
/*
 * The main configuration routine. Its implementation is hugely inspired by the
 * the same routine implementation in Solaris NSCD.
 */
int
parse_config_file(struct configuration *config,
	const char *fname, char const **error_str, int *error_line)
{
	FILE	*fin;
	char	buffer[255];
	char	*fields[128];
	int	field_count, line_num, value;
	int	res;

	TRACE_IN(parse_config_file);
	assert(config != NULL);
	assert(fname != NULL);

	fin = fopen(fname, "r");
	if (fin == NULL) {
		TRACE_OUT(parse_config_file);
		return (-1);
	}

	res = 0;
	line_num = 0;
	memset(buffer, 0, sizeof(buffer));
	while ((res == 0) && (fgets(buffer, sizeof(buffer) - 1, fin) != NULL)) {
		field_count = strbreak(buffer, fields, sizeof(fields));
		++line_num;

		if (field_count == 0)
			continue;

		switch (fields[0][0]) {
		case '#':
		case '\0':
			continue;
		case 'e':
			if ((field_count == 3) &&
			(strcmp(fields[0], "enable-cache") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_yesno(fields[2])) != -1)) {
				enable_cache(config, fields[1], value);
				continue;
			}
			break;
		case 'd':
			if ((field_count == 2) &&
			(strcmp(fields[0], "debug-level") == 0) &&
			((value = get_number(fields[1], 0, 10)) != -1)) {
				continue;
			}
			break;
		case 'p':
			if ((field_count == 3) &&
			(strcmp(fields[0], "positive-time-to-live") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_number(fields[2], 0, -1)) != -1)) {
				set_positive_time_to_live(config,
					fields[1], value);
				continue;
			} else if ((field_count == 3) &&
			(strcmp(fields[0], "positive-confidence-threshold") == 0) &&
			((value = get_number(fields[2], 1, -1)) != -1)) {
				set_positive_confidence_threshold(config,
					fields[1], value);
				continue;
			} else if ((field_count == 3) &&
			(strcmp(fields[0], "positive-policy") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_policy(fields[2])) != -1)) {
				set_positive_policy(config, fields[1], value);
				continue;
			} else if ((field_count == 3) &&
			(strcmp(fields[0], "perform-actual-lookups") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_yesno(fields[2])) != -1)) {
				set_perform_actual_lookups(config, fields[1],
					value);
				continue;
			}
			break;
		case 'n':
			if ((field_count == 3) &&
			(strcmp(fields[0], "negative-time-to-live") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_number(fields[2], 0, -1)) != -1)) {
				set_negative_time_to_live(config,
					fields[1], value);
				continue;
			} else if ((field_count == 3) &&
			(strcmp(fields[0], "negative-confidence-threshold") == 0) &&
			((value = get_number(fields[2], 1, -1)) != -1)) {
				set_negative_confidence_threshold(config,
					fields[1], value);
				continue;
			} else if ((field_count == 3) &&
			(strcmp(fields[0], "negative-policy") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_policy(fields[2])) != -1)) {
				set_negative_policy(config,
					fields[1], value);
				continue;
			}
			break;
		case 's':
			if ((field_count == 3) &&
			(strcmp(fields[0], "suggested-size") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_number(fields[2], 1, -1)) != -1)) {
				set_suggested_size(config, fields[1], value);
				continue;
			}
			break;
		case 't':
			if ((field_count == 2) &&
			(strcmp(fields[0], "threads") == 0) &&
			((value = get_number(fields[1], 1, -1)) != -1)) {
				set_threads_num(config, value);
				continue;
			}
			break;
		case 'k':
			if ((field_count == 3) &&
			(strcmp(fields[0], "keep-hot-count") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_number(fields[2], 0, -1)) != -1)) {
				set_keep_hot_count(config,
					fields[1], value);
				continue;
			}
			break;
		case 'c':
			if ((field_count == 3) &&
			(strcmp(fields[0], "check-files") == 0) &&
			(check_cachename(fields[1]) == 0) &&
			((value = get_yesno(fields[2])) != -1)) {
				check_files(config,
					fields[1], value);
				continue;
			}
			break;
		default:
			break;
		}

		LOG_ERR_2("config file parser", "error in file "
			"%s on line %d", fname, line_num);
		*error_str = "syntax error";
		*error_line = line_num;
		res = -1;
	}
	fclose(fin);

	TRACE_OUT(parse_config_file);
	return (res);
}
예제 #7
0
static struct configuration_entry *
create_configuration_entry(const char *name,
	struct timeval const *common_timeout,
	struct timeval const *mp_timeout,
	struct common_cache_entry_params const *positive_params,
	struct common_cache_entry_params const *negative_params,
	struct mp_cache_entry_params const *mp_params)
{
	struct configuration_entry *retval;
	size_t	size;
	int res;

	TRACE_IN(create_configuration_entry);
	assert(name != NULL);
	assert(positive_params != NULL);
	assert(negative_params != NULL);
	assert(mp_params != NULL);

	retval = calloc(1,
		sizeof(*retval));
	assert(retval != NULL);

	res = pthread_mutex_init(&retval->positive_cache_lock, NULL);
	if (res != 0) {
		free(retval);
		LOG_ERR_2("create_configuration_entry",
			"can't create positive cache lock");
		TRACE_OUT(create_configuration_entry);
		return (NULL);
	}

	res = pthread_mutex_init(&retval->negative_cache_lock, NULL);
	if (res != 0) {
		pthread_mutex_destroy(&retval->positive_cache_lock);
		free(retval);
		LOG_ERR_2("create_configuration_entry",
			"can't create negative cache lock");
		TRACE_OUT(create_configuration_entry);
		return (NULL);
	}

	res = pthread_mutex_init(&retval->mp_cache_lock, NULL);
	if (res != 0) {
		pthread_mutex_destroy(&retval->positive_cache_lock);
		pthread_mutex_destroy(&retval->negative_cache_lock);
		free(retval);
		LOG_ERR_2("create_configuration_entry",
			"can't create negative cache lock");
		TRACE_OUT(create_configuration_entry);
		return (NULL);
	}

	memcpy(&retval->positive_cache_params, positive_params,
		sizeof(struct common_cache_entry_params));
	memcpy(&retval->negative_cache_params, negative_params,
		sizeof(struct common_cache_entry_params));
	memcpy(&retval->mp_cache_params, mp_params,
		sizeof(struct mp_cache_entry_params));

	size = strlen(name);
	retval->name = calloc(1, size + 1);
	assert(retval->name != NULL);
	memcpy(retval->name, name, size);

	memcpy(&retval->common_query_timeout, common_timeout,
		sizeof(struct timeval));
	memcpy(&retval->mp_query_timeout, mp_timeout,
		sizeof(struct timeval));

	asprintf(&retval->positive_cache_params.cep.entry_name, "%s+", name);
	assert(retval->positive_cache_params.cep.entry_name != NULL);

	asprintf(&retval->negative_cache_params.cep.entry_name, "%s-", name);
	assert(retval->negative_cache_params.cep.entry_name != NULL);

	asprintf(&retval->mp_cache_params.cep.entry_name, "%s*", name);
	assert(retval->mp_cache_params.cep.entry_name != NULL);

	TRACE_OUT(create_configuration_entry);
	return (retval);
}
예제 #8
0
static int
on_mp_read_session_request_process(struct query_state *qstate)
{
	struct cache_mp_read_session_request	*c_mp_rs_request;
	struct cache_mp_read_session_response	*c_mp_rs_response;
	cache_mp_read_session	rs;
	cache_entry	c_entry;
	char	*dec_cache_entry_name;

	char *buffer;
	size_t buffer_size;
	cache_mp_write_session ws;
	struct agent	*lookup_agent;
	struct multipart_agent *mp_agent;
	void *mdata;
	int res;

	TRACE_IN(on_mp_read_session_request_process);
	init_comm_element(&qstate->response, CET_MP_READ_SESSION_RESPONSE);
	c_mp_rs_response = get_cache_mp_read_session_response(
		&qstate->response);
	c_mp_rs_request = get_cache_mp_read_session_request(&qstate->request);

	qstate->config_entry = configuration_find_entry(
		s_configuration, c_mp_rs_request->entry);
	if (qstate->config_entry == NULL) {
		c_mp_rs_response->error_code = ENOENT;

		LOG_ERR_2("read_session_request",
			"can't find configuration entry '%s'."
			" aborting request", c_mp_rs_request->entry);
		goto fin;
	}

	if (qstate->config_entry->enabled == 0) {
		c_mp_rs_response->error_code = EACCES;

		LOG_ERR_2("read_session_request",
			"configuration entry '%s' is disabled",
			c_mp_rs_request->entry);
		goto fin;
	}

	if (qstate->config_entry->perform_actual_lookups != 0)
		dec_cache_entry_name = strdup(
			qstate->config_entry->mp_cache_params.cep.entry_name);
	else {
#ifdef NS_NSCD_EID_CHECKING
		if (check_query_eids(qstate) != 0) {
			c_mp_rs_response->error_code = EPERM;
			goto fin;
		}
#endif

		asprintf(&dec_cache_entry_name, "%s%s", qstate->eid_str,
			qstate->config_entry->mp_cache_params.cep.entry_name);
	}

	assert(dec_cache_entry_name != NULL);

	configuration_lock_rdlock(s_configuration);
	c_entry = find_cache_entry(s_cache, dec_cache_entry_name);
	configuration_unlock(s_configuration);

	if ((c_entry == INVALID_CACHE) &&
	   (qstate->config_entry->perform_actual_lookups != 0))
		c_entry = register_new_mp_cache_entry(qstate,
			dec_cache_entry_name);

	free(dec_cache_entry_name);

	if (c_entry != INVALID_CACHE_ENTRY) {
		configuration_lock_entry(qstate->config_entry, CELT_MULTIPART);
		rs = open_cache_mp_read_session(c_entry);
		configuration_unlock_entry(qstate->config_entry,
			CELT_MULTIPART);

		if ((rs == INVALID_CACHE_MP_READ_SESSION) &&
		   (qstate->config_entry->perform_actual_lookups != 0)) {
			lookup_agent = find_agent(s_agent_table,
				c_mp_rs_request->entry, MULTIPART_AGENT);

			if ((lookup_agent != NULL) &&
			(lookup_agent->type == MULTIPART_AGENT)) {
				mp_agent = (struct multipart_agent *)
					lookup_agent;
				mdata = mp_agent->mp_init_func();

				/*
				 * Multipart agents read the whole snapshot
				 * of the data at one time.
				 */
				configuration_lock_entry(qstate->config_entry,
					CELT_MULTIPART);
				ws = open_cache_mp_write_session(c_entry);
				configuration_unlock_entry(qstate->config_entry,
					CELT_MULTIPART);
				if (ws != NULL) {
				    do {
					buffer = NULL;
					res = mp_agent->mp_lookup_func(&buffer,
						&buffer_size,
						mdata);

					if ((res & NS_TERMINATE) &&
					   (buffer != NULL)) {
						configuration_lock_entry(
							qstate->config_entry,
						   	CELT_MULTIPART);
						if (cache_mp_write(ws, buffer,
						    buffer_size) != 0) {
							abandon_cache_mp_write_session(ws);
							ws = NULL;
						}
						configuration_unlock_entry(
							qstate->config_entry,
							CELT_MULTIPART);

						free(buffer);
						buffer = NULL;
					} else {
						configuration_lock_entry(
							qstate->config_entry,
							CELT_MULTIPART);
						close_cache_mp_write_session(ws);
						configuration_unlock_entry(
							qstate->config_entry,
							CELT_MULTIPART);

						free(buffer);
						buffer = NULL;
					}
				    } while ((res & NS_TERMINATE) &&
				    	    (ws != NULL));
				}

				configuration_lock_entry(qstate->config_entry,
					CELT_MULTIPART);
				rs = open_cache_mp_read_session(c_entry);
				configuration_unlock_entry(qstate->config_entry,
					CELT_MULTIPART);
			}
		}

		if (rs == INVALID_CACHE_MP_READ_SESSION)
			c_mp_rs_response->error_code = -1;
		else {
		    qstate->mdata = rs;
		    qstate->destroy_func = on_mp_read_session_destroy;

		    configuration_lock_entry(qstate->config_entry,
			CELT_MULTIPART);
		    if ((qstate->config_entry->mp_query_timeout.tv_sec != 0) ||
		    (qstate->config_entry->mp_query_timeout.tv_usec != 0))
			memcpy(&qstate->timeout,
			    &qstate->config_entry->mp_query_timeout,
			    sizeof(struct timeval));
		    configuration_unlock_entry(qstate->config_entry,
			CELT_MULTIPART);
		}
	} else
		c_mp_rs_response->error_code = -1;

fin:
	qstate->process_func = on_mp_read_session_response_write1;
	qstate->kevent_watermark = sizeof(int);
	qstate->kevent_filter = EVFILT_WRITE;

	TRACE_OUT(on_mp_read_session_request_process);
	return (0);
}