ipa_sudo.c revision 4ddd5591c50e27dffa55f03fbce0dcc85cd50a8b
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/*
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Authors:
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Pavel Březina <pbrezina@redhat.com>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen Copyright (C) 2015 Red Hat
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen This program is free software; you can redistribute it and/or modify
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen it under the terms of the GNU General Public License as published by
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen the Free Software Foundation; either version 3 of the License, or
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (at your option) any later version.
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen This program is distributed in the hope that it will be useful,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen GNU General Public License for more details.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen You should have received a copy of the GNU General Public License
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen*/
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "providers/ipa/ipa_opts.h"
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen#include "providers/ipa/ipa_common.h"
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen#include "providers/ldap/sdap_sudo.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "providers/ipa/ipa_sudo.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "db/sysdb_sudo.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void ipa_sudo_handler(struct be_req *breq);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct bet_ops ipa_sudo_ops = {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen .handler = ipa_sudo_handler,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen .finalize = NULL,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenenum sudo_schema {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen SUDO_SCHEMA_IPA,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen SUDO_SCHEMA_LDAP
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic errno_t
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenipa_sudo_choose_schema(struct dp_option *ipa_opts,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct dp_option *sdap_opts,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen enum sudo_schema *_schema)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen TALLOC_CTX *tmp_ctx;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen char *ipa_search_base;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen char *search_base;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen char *basedn;
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen errno_t ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen tmp_ctx = talloc_new(NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (tmp_ctx == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ENOMEM;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = domain_to_basedn(tmp_ctx, dp_opt_get_string(ipa_opts,
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen IPA_KRB5_REALM), &basedn);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ret != EOK) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Unable to obtain basedn\n");
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen goto done;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ipa_search_base = talloc_asprintf(tmp_ctx, "cn=sudo,%s", basedn);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ipa_search_base == NULL) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ret = ENOMEM;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen goto done;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen search_base = dp_opt_get_string(sdap_opts, SDAP_SUDO_SEARCH_BASE);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (search_base == NULL) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ret = dp_opt_set_string(sdap_opts, SDAP_SUDO_SEARCH_BASE,
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ipa_search_base);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ret != EOK) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen goto done;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen DEBUG(SSSDBG_TRACE_FUNC, "Option %s set to %s\n",
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen sdap_opts[SDAP_SUDO_SEARCH_BASE].opt_name, ipa_search_base);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen search_base = ipa_search_base;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen /* Use IPA schema only if search base is cn=sudo,$dc. */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (strcmp(ipa_search_base, search_base) == 0) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen *_schema = SUDO_SCHEMA_IPA;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen } else {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen *_schema = SUDO_SCHEMA_LDAP;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ret = EOK;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainendone:
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen talloc_free(tmp_ctx);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainenstatic int
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenipa_sudo_init_ipa_schema(struct be_ctx *be_ctx,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct ipa_id_ctx *id_ctx,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen struct bet_ops **ops,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen void **pvt_data)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen{
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen struct ipa_sudo_ctx *sudo_ctx;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen errno_t ret;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen sudo_ctx = talloc_zero(be_ctx, struct ipa_sudo_ctx);
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (sudo_ctx == NULL) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return ENOMEM;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen sudo_ctx->id_ctx = id_ctx->sdap_id_ctx;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen sudo_ctx->ipa_opts = id_ctx->ipa_options;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen sudo_ctx->sdap_opts = id_ctx->sdap_id_ctx->opts;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen ret = sdap_get_map(sudo_ctx, be_ctx->cdb, be_ctx->conf_path,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen ipa_sudorule_map, IPA_OPTS_SUDORULE,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen &sudo_ctx->sudorule_map);
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (ret != EOK) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map "
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen "[%d]: %s\n", ret, sss_strerror(ret));
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen goto done;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen }
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen ret = sdap_get_map(sudo_ctx, be_ctx->cdb, be_ctx->conf_path,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen ipa_sudocmdgroup_map, IPA_OPTS_SUDOCMDGROUP,
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen &sudo_ctx->sudocmdgroup_map);
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (ret != EOK) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map "
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "[%d]: %s\n", ret, sss_strerror(ret));
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen goto done;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ret = sdap_get_map(sudo_ctx, be_ctx->cdb, be_ctx->conf_path,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ipa_sudocmd_map, IPA_OPTS_SUDOCMD,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen &sudo_ctx->sudocmd_map);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret != EOK) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse attribute map "
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen "[%d]: %s\n", ret, sss_strerror(ret));
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen goto done;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ret = sdap_parse_search_base(sudo_ctx, sudo_ctx->sdap_opts->basic,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen SDAP_SUDO_SEARCH_BASE,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen &sudo_ctx->sudo_sb);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret != EOK) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen DEBUG(SSSDBG_OP_FAILURE, "Could not parse sudo search base\n");
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return ret;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen *ops = &ipa_sudo_ops;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen *pvt_data = sudo_ctx;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen ret = EOK;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainendone:
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret != EOK) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen talloc_free(sudo_ctx);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return ret;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenint ipa_sudo_init(struct be_ctx *be_ctx,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct ipa_id_ctx *id_ctx,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen struct bet_ops **ops,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen void **pvt_data)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen enum sudo_schema schema;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen errno_t ret;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL, "Initializing IPA sudo back end\n");
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ret = ipa_sudo_choose_schema(id_ctx->ipa_options->basic,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen id_ctx->ipa_options->id->basic,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen &schema);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret != EOK) {
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Unable to choose sudo schema [%d]: %s\n",
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ret, sss_strerror(ret));
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return ret;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen switch (schema) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen case SUDO_SCHEMA_IPA:
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen DEBUG(SSSDBG_TRACE_FUNC, "Using IPA schema for sudo\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = ipa_sudo_init_ipa_schema(be_ctx, id_ctx, ops, pvt_data);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen case SUDO_SCHEMA_LDAP:
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen DEBUG(SSSDBG_TRACE_FUNC, "Using LDAP schema for sudo\n");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = sdap_sudo_init(be_ctx, id_ctx->sdap_id_ctx, ops, pvt_data);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret != EOK) {
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize sudo provider"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "[%d]: %s\n", ret, sss_strerror(ret));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
242abe3ad2423776e9cf05e1304eb8fda4831b23Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return EOK;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainenstatic void
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenipa_sudo_handler(struct be_req *be_req)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen sdap_handler_done(be_req, DP_ERR_FATAL, ERR_INTERNAL, "Not implemented yet.");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen