From: Stephan Bosch Date: Sun, 26 Mar 2023 23:41:16 +0000 (+0200) Subject: auth: Use the new sasl-server global-level mechanism registration API X-Git-Tag: 2.4.2~203 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=230269a050b8b26089886af03a2e8f6f6c2f2b5d;p=thirdparty%2Fdovecot%2Fcore.git auth: Use the new sasl-server global-level mechanism registration API --- diff --git a/src/auth/auth-client-connection.c b/src/auth/auth-client-connection.c index 28de892951..cbc4339274 100644 --- a/src/auth/auth-client-connection.c +++ b/src/auth/auth-client-connection.c @@ -11,6 +11,7 @@ #include "randgen.h" #include "master-service.h" #include "sasl-server-protected.h" // FIXME: remove +#include "auth-sasl.h" #include "auth-request-handler.h" #include "auth-client-interface.h" #include "auth-client-connection.h" @@ -195,11 +196,9 @@ static void auth_client_finish_handshake(struct auth_client_connection *conn) mechanisms = t_strconcat("MECH\t", mech_dovecot_token.name, "\tprivate\n", NULL); } else { - mechanisms = str_c(conn->auth->reg->handshake); - if (conn->conn.minor_version >= AUTH_CLIENT_MINOR_VERSION_CHANNEL_BINDING) { - mechanisms_cbind = - str_c(conn->auth->reg->handshake_cbind); - } + mechanisms = auth_sasl_mechs_get_handshake(); + if (conn->conn.minor_version >= AUTH_CLIENT_MINOR_VERSION_CHANNEL_BINDING) + mechanisms_cbind = auth_sasl_mechs_get_handshake_cbind(); } str = t_str_new(128); diff --git a/src/auth/auth-request-handler.c b/src/auth/auth-request-handler.c index 0a2f5c1e0b..769d1e45f5 100644 --- a/src/auth/auth-request-handler.c +++ b/src/auth/auth-request-handler.c @@ -569,14 +569,16 @@ auth_penalty_callback(unsigned int penalty, struct auth_request *request) static int auth_request_handler_find_mech(struct auth_request_handler *handler, + struct auth_request *request, const char *mech_name, - const struct sasl_server_mech_def **mech_r) + const struct sasl_server_mech **mech_r) { - const struct sasl_server_mech_def *mech; + struct auth *auth = auth_request_get_auth(request); + const struct sasl_server_mech *mech; if (handler->token_auth) { - mech = &mech_dovecot_token; - if (strcmp(mech_name, mech->name) == 0) { + mech = auth->sasl_mech_dovecot_token; + if (strcmp(sasl_server_mech_get_name(mech), mech_name) == 0) { *mech_r = mech; return 0; } @@ -589,9 +591,7 @@ auth_request_handler_find_mech(struct auth_request_handler *handler, return -1; } - struct auth *auth_default = auth_default_protocol(); - - mech = mech_register_find(auth_default->reg, mech_name); + mech = sasl_server_mech_find(auth->sasl_inst, mech_name); if (mech == NULL) { /* unsupported mechanism */ e_error(handler->conn->conn.event, @@ -679,9 +679,10 @@ int auth_request_handler_auth_begin(struct auth_request_handler *handler, return -1; } - const struct sasl_server_mech_def *mech; + const struct sasl_server_mech *mech; - if (auth_request_handler_find_mech(handler, mech_name, &mech) < 0) + if (auth_request_handler_find_mech(handler, request, mech_name, + &mech) < 0) return -1; auth_request_init_sasl(request, mech); @@ -850,7 +851,7 @@ static void auth_str_append_userdb_extra_fields(struct auth_request *request, auth_str_add_keyvalue(dest, "master_user", request->fields.master_user); } - auth_str_add_keyvalue(dest, "auth_mech", request->mech->name); + auth_str_add_keyvalue(dest, "auth_mech", request->fields.mech_name); if (*request->set->anonymous_username != '\0' && strcmp(request->fields.user, request->set->anonymous_username) == 0) { /* this is an anonymous login, either via ANONYMOUS diff --git a/src/auth/auth-request.c b/src/auth/auth-request.c index d955868b03..8767491046 100644 --- a/src/auth/auth-request.c +++ b/src/auth/auth-request.c @@ -192,9 +192,9 @@ void auth_request_init(struct auth_request *request) } void auth_request_init_sasl(struct auth_request *request, - const struct sasl_server_mech_def *mech) + const struct sasl_server_mech *mech) { - request->mech = mech; + request->mech = mech->def; const char *prefix = t_strconcat( t_str_lcase(request->mech->name), ": ", NULL); diff --git a/src/auth/auth-request.h b/src/auth/auth-request.h index 42a7434a65..5bd496caed 100644 --- a/src/auth/auth-request.h +++ b/src/auth/auth-request.h @@ -262,7 +262,7 @@ struct auth_request *auth_request_new_dummy(struct event *parent_event); void auth_request_init(struct auth_request *request); void auth_request_init_sasl(struct auth_request *request, - const struct sasl_server_mech_def *mech); + const struct sasl_server_mech *mech); struct auth *auth_request_get_auth(struct auth_request *request); diff --git a/src/auth/auth-sasl.c b/src/auth/auth-sasl.c index cb5999fb65..3be72cbf00 100644 --- a/src/auth/auth-sasl.c +++ b/src/auth/auth-sasl.c @@ -15,6 +15,9 @@ static struct sasl_server *auth_sasl_server; +static char *auth_sasl_mechs_handshake; +static char *auth_sasl_mechs_handshake_cbind; + /* * Request */ @@ -293,15 +296,8 @@ auth_sasl_translate_protocol_name(struct auth_request *request) } void auth_sasl_request_init(struct auth_request *request, - const struct sasl_server_mech_def *mech_def) + const struct sasl_server_mech *mech) { - struct auth *auth = auth_request_get_auth(request); - const struct sasl_server_mech *mech; - - mech = sasl_server_mech_find(auth->sasl_inst, mech_def->name); - if (mech == NULL) - mech = sasl_server_mech_register(auth->sasl_inst, mech_def); - i_assert(mech != NULL); sasl_server_request_create(&request->sasl.req, mech, auth_sasl_translate_protocol_name(request), request->mech_event); @@ -380,10 +376,22 @@ auth_sasl_mech_module_find(const char *name) return NULL; } +const char *auth_sasl_mechs_get_handshake(void) +{ + return auth_sasl_mechs_handshake; +} + +const char *auth_sasl_mechs_get_handshake_cbind(void) +{ + return auth_sasl_mechs_handshake_cbind; +} + /* * Instance */ +static const char *auth_sasl_mech_get_plugin_name(const char *name); + void auth_sasl_instance_init(struct auth *auth, const struct auth_settings *set) { @@ -395,28 +403,9 @@ void auth_sasl_instance_init(struct auth *auth, auth->sasl_inst = sasl_server_instance_create(auth_sasl_server, &sasl_set); -} -const char *mech_get_plugin_name(const char *name); -void mech_register_add(struct mechanisms_register *reg, - const struct sasl_server_mech_def *mech); - -struct mechanisms_register * -mech_register_init(const struct auth_settings *set); -struct mechanisms_register * -mech_register_init(const struct auth_settings *set) -{ - struct mechanisms_register *reg; const struct sasl_server_mech_def *mech; const char *name; - pool_t pool; - - pool = pool_alloconly_create("mechanisms register", 1024); - reg = p_new(pool, struct mechanisms_register, 1); - reg->pool = pool; - reg->set = set; - reg->handshake = str_new(pool, 512); - reg->handshake_cbind = str_new(pool, 256); if (array_is_empty(&set->mechanisms)) i_fatal("No authentication mechanisms configured"); @@ -433,14 +422,16 @@ mech_register_init(const struct auth_settings *set) mech = mech_module_find(name); if (mech == NULL) { /* maybe it's a plugin. try to load it. */ - auth_module_load(mech_get_plugin_name(name)); + auth_module_load(auth_sasl_mech_get_plugin_name(name)); mech = mech_module_find(name); } if (mech == NULL) i_fatal("Unknown authentication mechanism '%s'", name); - mech_register_add(reg, mech); + sasl_server_mech_register(auth->sasl_inst, mech); } - return reg; + + auth->sasl_mech_dovecot_token = + sasl_server_mech_register(auth->sasl_inst, &mech_dovecot_token); } static bool @@ -471,23 +462,25 @@ auth_sasl_mech_verify_passdb(const struct auth *auth, void auth_sasl_instance_verify(const struct auth *auth) { - const struct mech_module_list *list; + struct sasl_server_mech_iter *mech_iter; - for (list = auth->reg->modules; list != NULL; list = list->next) { - if (!auth_sasl_mech_verify_passdb( - auth, list->module->passdb_need)) + mech_iter = sasl_server_instance_mech_iter_new(auth->sasl_inst); + while (sasl_server_mech_iter_next(mech_iter)) { + if (!auth_sasl_mech_verify_passdb(auth, mech_iter->passdb_need)) break; } - if (list != NULL) { + if (!sasl_server_mech_iter_ended(mech_iter)) { if (auth->passdbs == NULL) { i_fatal("No passdbs specified in configuration file. " "%s mechanism needs one", - list->module->name); + mech_iter->name); } i_fatal("%s mechanism can't be supported with given passdbs", - list->module->name); + mech_iter->name); } + + sasl_server_mech_iter_free(&mech_iter); } void auth_sasl_instance_deinit(struct auth *auth) @@ -499,44 +492,53 @@ void auth_sasl_instance_deinit(struct auth *auth) * Global */ -void mech_register_add(struct mechanisms_register *reg, - const struct sasl_server_mech_def *mech) -{ - struct mech_module_list *list; - string_t *handshake; - - list = p_new(reg->pool, struct mech_module_list, 1); - list->module = mech; - - if ((mech->flags & SASL_MECH_SEC_CHANNEL_BINDING) != 0) - handshake = reg->handshake_cbind; - else - handshake = reg->handshake; - - str_printfa(handshake, "MECH\t%s", mech->name); - if ((mech->flags & SASL_MECH_SEC_PRIVATE) != 0) - str_append(handshake, "\tprivate"); - if ((mech->flags & SASL_MECH_SEC_ANONYMOUS) != 0) - str_append(handshake, "\tanonymous"); - if ((mech->flags & SASL_MECH_SEC_PLAINTEXT) != 0) - str_append(handshake, "\tplaintext"); - if ((mech->flags & SASL_MECH_SEC_DICTIONARY) != 0) - str_append(handshake, "\tdictionary"); - if ((mech->flags & SASL_MECH_SEC_ACTIVE) != 0) - str_append(handshake, "\tactive"); - if ((mech->flags & SASL_MECH_SEC_FORWARD_SECRECY) != 0) - str_append(handshake, "\tforward-secrecy"); - if ((mech->flags & SASL_MECH_SEC_MUTUAL_AUTH) != 0) - str_append(handshake, "\tmutual-auth"); - if ((mech->flags & SASL_MECH_SEC_CHANNEL_BINDING) != 0) - str_append(handshake, "\tchannel-binding"); - str_append_c(handshake, '\n'); - - list->next = reg->modules; - reg->modules = list; -} - -const char *mech_get_plugin_name(const char *name) +static void auth_sasl_mechs_handshake_init(void) +{ + struct sasl_server_mech_iter *iter; + string_t *handshake_buf = t_str_new(512); + string_t *handshake_buf_cbind = t_str_new(256); + + iter = sasl_server_mech_iter_new(auth_sasl_server); + while (sasl_server_mech_iter_next(iter)) { + string_t *handshake; + + if ((iter->flags & SASL_MECH_SEC_CHANNEL_BINDING) != 0) + handshake = handshake_buf_cbind; + else + handshake = handshake_buf; + + str_printfa(handshake, "MECH\t%s", iter->name); + if ((iter->flags & SASL_MECH_SEC_PRIVATE) != 0) + str_append(handshake, "\tprivate"); + if ((iter->flags & SASL_MECH_SEC_ANONYMOUS) != 0) + str_append(handshake, "\tanonymous"); + if ((iter->flags & SASL_MECH_SEC_PLAINTEXT) != 0) + str_append(handshake, "\tplaintext"); + if ((iter->flags & SASL_MECH_SEC_DICTIONARY) != 0) + str_append(handshake, "\tdictionary"); + if ((iter->flags & SASL_MECH_SEC_ACTIVE) != 0) + str_append(handshake, "\tactive"); + if ((iter->flags & SASL_MECH_SEC_FORWARD_SECRECY) != 0) + str_append(handshake, "\tforward-secrecy"); + if ((iter->flags & SASL_MECH_SEC_MUTUAL_AUTH) != 0) + str_append(handshake, "\tmutual-auth"); + if ((iter->flags & SASL_MECH_SEC_CHANNEL_BINDING) != 0) + str_append(handshake, "\tchannel-binding"); + str_append_c(handshake, '\n'); + } + sasl_server_mech_iter_free(&iter); + + auth_sasl_mechs_handshake = i_strdup(str_c(handshake_buf)); + auth_sasl_mechs_handshake_cbind = i_strdup(str_c(handshake_buf_cbind)); +} + +static void auth_sasl_mechs_handshake_deinit(void) +{ + i_free(auth_sasl_mechs_handshake); + i_free(auth_sasl_mechs_handshake_cbind); +} + +static const char *auth_sasl_mech_get_plugin_name(const char *name) { string_t *str = t_str_new(32); @@ -559,9 +561,11 @@ void auth_sasl_preinit(void) void auth_sasl_init(void) { + auth_sasl_mechs_handshake_init(); } void auth_sasl_deinit(void) { sasl_server_deinit(&auth_sasl_server); + auth_sasl_mechs_handshake_deinit(); } diff --git a/src/auth/auth-sasl.h b/src/auth/auth-sasl.h index f4469c7b08..852c54b90b 100644 --- a/src/auth/auth-sasl.h +++ b/src/auth/auth-sasl.h @@ -18,7 +18,7 @@ struct auth_sasl_mech_module { */ void auth_sasl_request_init(struct auth_request *request, - const struct sasl_server_mech_def *mech_def); + const struct sasl_server_mech *mech); void auth_sasl_request_deinit(struct auth_request *request); void auth_sasl_request_initial(struct auth_request *request); @@ -36,6 +36,9 @@ void auth_sasl_mech_unregister_module( const struct auth_sasl_mech_module * auth_sasl_mech_module_find(const char *name); +const char *auth_sasl_mechs_get_handshake(void); +const char *auth_sasl_mechs_get_handshake_cbind(void); + /* * Instance */ diff --git a/src/auth/auth.c b/src/auth/auth.c index bec7900074..781298f12c 100644 --- a/src/auth/auth.c +++ b/src/auth/auth.c @@ -242,8 +242,7 @@ bool auth_passdb_list_have_set_credentials(const struct auth *auth) } static struct auth * ATTR_NULL(2) -auth_preinit(const struct auth_settings *set, const char *protocol, - const struct mechanisms_register *reg) +auth_preinit(const struct auth_settings *set, const char *protocol) { const struct auth_passdb_settings *const *passdbs; const struct auth_userdb_settings *const *userdbs; @@ -256,7 +255,6 @@ auth_preinit(const struct auth_settings *set, const char *protocol, auth->protocol = p_strdup(pool, protocol); auth->protocol_set = set; pool_ref(set->pool); - auth->reg = reg; if (array_is_created(&set->parsed_passdbs)) passdbs = array_get(&set->parsed_passdbs, &db_count); @@ -465,7 +463,6 @@ struct auth *auth_default_protocol(void) void auths_preinit(struct event *parent_event, const struct auth_settings *set, - const struct mechanisms_register *reg, const char *const *protocols) { const struct auth_settings *protocol_set; @@ -479,7 +476,7 @@ void auths_preinit(struct event *parent_event, event_add_category(auth_event, &event_category_auth); i_array_init(&auths, 8); - auth = auth_preinit(set, NULL, reg); + auth = auth_preinit(set, NULL); array_push_back(&auths, &auth); for (i = 0; protocols[i] != NULL; i++) { @@ -492,7 +489,7 @@ void auths_preinit(struct event *parent_event, not_protocol = protocols[i]; } protocol_set = auth_settings_get(protocols[i]); - auth = auth_preinit(protocol_set, protocols[i], reg); + auth = auth_preinit(protocol_set, protocols[i]); array_push_back(&auths, &auth); settings_free(protocol_set); } diff --git a/src/auth/auth.h b/src/auth/auth.h index 94faf67d32..9a35e05e26 100644 --- a/src/auth/auth.h +++ b/src/auth/auth.h @@ -78,8 +78,8 @@ struct auth { const char *protocol; const struct auth_settings *protocol_set; - const struct mechanisms_register *reg; struct sasl_server_instance *sasl_inst; + const struct sasl_server_mech *sasl_mech_dovecot_token; struct auth_passdb *masterdbs; struct auth_passdb *passdbs; @@ -102,7 +102,6 @@ void auth_userdbs_generate_md5(unsigned char md5[STATIC_ARRAY MD5_RESULTLEN]); void auths_preinit(struct event *parent_event, const struct auth_settings *set, - const struct mechanisms_register *reg, const char *const *protocols); void auths_init(void); void auths_deinit(void); diff --git a/src/auth/main.c b/src/auth/main.c index 32cfc89335..4dd6b511b4 100644 --- a/src/auth/main.c +++ b/src/auth/main.c @@ -72,7 +72,6 @@ time_t process_start_time; struct auth_penalty *auth_penalty; static struct module *modules = NULL; -static struct mechanisms_register *mech_reg; static ARRAY(struct auth_socket_listener) listeners; void auth_refresh_proctitle(void) @@ -181,7 +180,7 @@ static void main_preinit(void) dict_drivers_register_builtin(); auth_sasl_preinit(); - auths_preinit(NULL, global_auth_settings, mech_reg, protocols); + auths_preinit(NULL, global_auth_settings, protocols); listeners_init(); if (!worker) @@ -276,7 +275,6 @@ static void main_deinit(void) /* there are no more auth requests */ auths_free(); - mech_register_deinit(&mech_reg); mech_otp_deinit(); mech_deinit(global_auth_settings); diff --git a/src/auth/mech.c b/src/auth/mech.c index ba5e78c21f..4ff3829b5a 100644 --- a/src/auth/mech.c +++ b/src/auth/mech.c @@ -73,35 +73,6 @@ extern const struct sasl_server_mech_def mech_winbind_spnego; extern const struct sasl_server_mech_def mech_oauthbearer; extern const struct sasl_server_mech_def mech_xoauth2; -void mech_register_add(struct mechanisms_register *reg, - const struct sasl_server_mech_def *mech); - -const char *mech_get_plugin_name(const char *name); - -struct mechanisms_register * -mech_register_init(const struct auth_settings *set); - -void mech_register_deinit(struct mechanisms_register **_reg) -{ - struct mechanisms_register *reg = *_reg; - - *_reg = NULL; - pool_unref(®->pool); -} - -const struct sasl_server_mech_def * -mech_register_find(const struct mechanisms_register *reg, const char *name) -{ - const struct mech_module_list *list; - name = t_str_ucase(name); - - for (list = reg->modules; list != NULL; list = list->next) { - if (strcmp(list->module->name, name) == 0) - return list->module; - } - return NULL; -} - void mech_init(const struct auth_settings *set) { mech_register_module(&mech_plain); diff --git a/src/auth/sasl-server-mech-scram.c b/src/auth/sasl-server-mech-scram.c index 6a54483804..b350b12711 100644 --- a/src/auth/sasl-server-mech-scram.c +++ b/src/auth/sasl-server-mech-scram.c @@ -187,18 +187,19 @@ mech_scram_auth_new(pool_t pool, const struct hash_method *hash_method, request->password_scheme = password_scheme; struct auth *auth = auth_default_protocol(); + struct sasl_server_instance *sinst = auth->sasl_inst; struct auth_scram_server_settings scram_set; i_zero(&scram_set); scram_set.hash_method = hash_method; - if (mech_register_find(auth->reg, - t_strconcat(password_scheme, - "-PLUS", NULL)) == NULL) { + if (sasl_server_mech_find( + sinst, t_strconcat(request->password_scheme, + "-PLUS", NULL)) == NULL) { scram_set.cbind_support = AUTH_SCRAM_CBIND_SERVER_SUPPORT_NONE; - } else if (mech_register_find(auth->reg, - request->password_scheme) == NULL) { + } else if (sasl_server_mech_find(sinst, + request->password_scheme) == NULL) { scram_set.cbind_support = AUTH_SCRAM_CBIND_SERVER_SUPPORT_REQUIRED; } else { diff --git a/src/auth/sasl-server-protected.h b/src/auth/sasl-server-protected.h index e5d7ac4411..ccb1fa3607 100644 --- a/src/auth/sasl-server-protected.h +++ b/src/auth/sasl-server-protected.h @@ -95,12 +95,6 @@ void sasl_server_mech_generic_auth_initial( struct sasl_server_mech_request *mreq, const unsigned char *data, size_t data_size); -struct mechanisms_register * -mech_register_init(const struct auth_settings *set); -void mech_register_deinit(struct mechanisms_register **reg); -const struct sasl_server_mech_def * -mech_register_find(const struct mechanisms_register *reg, const char *name); - void mech_init(const struct auth_settings *set); void mech_deinit(const struct auth_settings *set); diff --git a/src/auth/sasl-server.h b/src/auth/sasl-server.h index 31be9354ae..d541deea8f 100644 --- a/src/auth/sasl-server.h +++ b/src/auth/sasl-server.h @@ -4,7 +4,6 @@ #include "sasl-common.h" struct sasl_passdb_result; -struct sasl_server_mech_def; struct sasl_server_mech; struct sasl_server_request; struct sasl_server_req_ctx; diff --git a/src/auth/test-auth.c b/src/auth/test-auth.c index 6adbe8d815..17d9c316c6 100644 --- a/src/auth/test-auth.c +++ b/src/auth/test-auth.c @@ -17,7 +17,9 @@ static const char *const settings[] = { "base_dir", ".", - "auth_mechanisms", "plain xoauth2", + "auth_mechanisms", + "ANONYMOUS APOP CRAM-MD5 DIGEST-MD5 EXTERNAL LOGIN PLAIN OTP " + "OAUTHBEARER SCRAM-SHA-1 SCRAM-SHA-256 XOAUTH2", "auth_username_chars", "", "auth_username_format", "", /* For tests of digest-md5. */ @@ -41,7 +43,6 @@ static const char *const settings[] = { NULL }; -static struct mechanisms_register *mech_reg; static struct settings_simple simple_set; void test_auth_init(void) @@ -55,7 +56,6 @@ void test_auth_init(void) /* this is needed to get oauth2 initialized */ auth_event = simple_set.event; mech_init(global_auth_settings); - mech_reg = mech_register_init(global_auth_settings); passdbs_init(); userdbs_init(); passdb_mock_mod_init(); @@ -63,7 +63,7 @@ void test_auth_init(void) password_schemes_allow_weak(TRUE); auth_sasl_preinit(); - auths_preinit(simple_set.event, global_auth_settings, mech_reg, protocols); + auths_preinit(simple_set.event, global_auth_settings, protocols); auths_init(); auth_token_init(); auth_sasl_init(); @@ -84,7 +84,6 @@ void test_auth_deinit(void) userdbs_deinit(); event_unref(&auth_event); mech_deinit(global_auth_settings); - mech_register_deinit(&mech_reg); auths_free(); auth_sasl_deinit(); settings_free(global_auth_settings); diff --git a/src/auth/test-mech.c b/src/auth/test-mech.c index 9bab54e470..39648deea5 100644 --- a/src/auth/test-mech.c +++ b/src/auth/test-mech.c @@ -85,7 +85,7 @@ auth_client_request_mock_callback( } static void test_mech_prepare_request(struct auth_request **request_r, - const struct sasl_server_mech_def *mech, + const char *mech_name, struct auth_request_handler *handler, unsigned int running_test, const struct test_case *test_case) @@ -101,12 +101,20 @@ static void test_mech_prepare_request(struct auth_request **request_r, request->mech_password = NULL; request->fields.protocol = "service"; request->state = AUTH_REQUEST_STATE_NEW; - request->mech = mech; request->set = new_set; request->protocol_set = global_auth_settings; request->connect_uid = running_test; handler->refcount = 1; + struct auth *auth = auth_default_protocol(); + const struct sasl_server_mech *mech; + if (strcmp(mech_name, "DOVECOT-TOKEN") == 0) + mech = auth->sasl_mech_dovecot_token; + else + mech = sasl_server_mech_find(auth->sasl_inst, mech_name); + i_assert(mech != NULL); + request->mech = mech->def; + auth_request_init_sasl(request, mech); request->failure_nodelay = TRUE; @@ -298,7 +306,7 @@ static void test_mechs(void) N_ELEMENTS(tests)); test_begin(testname); - test_mech_prepare_request(&request, mech, &handler, + test_mech_prepare_request(&request, mech->name, &handler, running_test, test_case); if (mech == &mech_apop && test_case->in == NULL) {