static int
user_verify_restricted_uid(struct auth_request *auth_request)
{
	struct auth_master_connection *conn = auth_request->master;
	struct auth_fields *reply = auth_request->userdb_reply;
	const char *value, *reason;
	uid_t uid;

	if (conn->userdb_restricted_uid == 0)
		return 0;

	value = auth_fields_find(reply, "uid");
	if (value == NULL)
		reason = "userdb reply doesn't contain uid";
	else if (str_to_uid(value, &uid) < 0)
		reason = "userdb reply contains invalid uid";
	else if (uid != conn->userdb_restricted_uid) {
		reason = t_strdup_printf(
			"userdb uid (%s) doesn't match peer uid (%s)",
			dec2str(uid), dec2str(conn->userdb_restricted_uid));
	} else {
		return 0;
	}

	auth_request_log_error(auth_request, "userdb",
		"client doesn't have lookup permissions for this user: %s "
		"(to bypass this check, set: service auth { unix_listener %s { mode=0777 } })",
		reason, conn->path);
	return -1;
}
static void
user_callback(enum userdb_result result,
	      struct auth_request *auth_request)
{
	struct auth_master_connection *conn = auth_request->master;
	string_t *str;
	const char *value;

	if (auth_request->userdb_lookup_tempfailed)
		result = USERDB_RESULT_INTERNAL_FAILURE;

	if (result == USERDB_RESULT_OK) {
		if (user_verify_restricted_uid(auth_request) < 0)
			result = USERDB_RESULT_INTERNAL_FAILURE;
	}

	str = t_str_new(128);
	switch (result) {
	case USERDB_RESULT_INTERNAL_FAILURE:
		str_printfa(str, "FAIL\t%u", auth_request->id);
		if (auth_request->userdb_lookup_tempfailed) {
			value = auth_fields_find(auth_request->userdb_reply,
						 "reason");
			if (value != NULL)
				str_printfa(str, "\treason=%s", value);
		}
		break;
	case USERDB_RESULT_USER_UNKNOWN:
		str_printfa(str, "NOTFOUND\t%u", auth_request->id);
		break;
	case USERDB_RESULT_OK:
		str_printfa(str, "USER\t%u\t", auth_request->id);
		str_append_tabescaped(str, auth_request->user);
		str_append_c(str, '\t');
		auth_fields_append(auth_request->userdb_reply, str,
				   AUTH_FIELD_FLAG_HIDDEN, 0);
		break;
	}

	if (conn->auth->set->debug) {
		i_debug("userdb out: %s",
			auth_master_reply_hide_passwords(conn, str_c(str)));
	}

	str_append_c(str, '\n');
	o_stream_nsend(conn->output, str_data(str), str_len(str));

	auth_request_unref(&auth_request);
	auth_master_connection_unref(&conn);
}
static void
user_callback(enum userdb_result result, struct auth_request *auth_request)
{
	struct auth_postfix_connection *conn = auth_request->context;
	string_t *str;
	const char *value;

	if (auth_request->userdb_lookup_tempfailed)
		result = USERDB_RESULT_INTERNAL_FAILURE;

	str = t_str_new(128);
	switch (result) {
	case USERDB_RESULT_INTERNAL_FAILURE:
		if (auth_request->userdb_lookup_tempfailed)
			value = auth_fields_find(auth_request->userdb_reply, "reason");
		else
			value = NULL;
		str_printfa(str, "400 %s",
			    value != NULL ? value: "Internal failure");
		break;
	case USERDB_RESULT_USER_UNKNOWN:
		str_append(str, "500 User not found");
		break;
	case USERDB_RESULT_OK:
		str_append(str, "200 1");
		break;
	}

	if (conn->auth->set->debug)
		i_debug("postfix out: %s", str_c(str));

	str_append_c(str, '\n');
	o_stream_nsend(conn->output, str_data(str), str_len(str));

	i_assert(conn->io == NULL);
	if (!conn->destroyed)
		conn->io = io_add(conn->fd, IO_READ, postfix_input, conn);

	auth_request_unref(&auth_request);
	auth_postfix_connection_unref(&conn);
}
static void userdb_callback(enum userdb_result result,
			    struct auth_request *request)
{
        struct auth_request_handler *handler = request->handler;
	string_t *str;
	const char *value;

	i_assert(request->state == AUTH_REQUEST_STATE_USERDB);

	auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);

	if (request->userdb_lookup_tempfailed)
		result = USERDB_RESULT_INTERNAL_FAILURE;

	str = t_str_new(128);
	switch (result) {
	case USERDB_RESULT_INTERNAL_FAILURE:
		str_printfa(str, "FAIL\t%u", request->id);
		if (request->userdb_lookup_tempfailed) {
			value = auth_fields_find(request->userdb_reply, "reason");
			if (value != NULL)
				auth_str_add_keyvalue(str, "reason", value);
		}
		break;
	case USERDB_RESULT_USER_UNKNOWN:
		str_printfa(str, "NOTFOUND\t%u", request->id);
		break;
	case USERDB_RESULT_OK:
		str_printfa(str, "USER\t%u\t", request->id);
		str_append_tabescaped(str, request->user);
		auth_str_append_userdb_extra_fields(request, str);
		break;
	}
	handler->master_callback(str_c(str), request->master);

	auth_master_connection_unref(&request->master);
	auth_request_unref(&request);
        auth_request_handler_unref(&handler);
}
bool auth_fields_exists(struct auth_fields *fields, const char *key)
{
	return auth_fields_find(fields, key) != NULL;
}