diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-sasl/dsasl-client.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/lib-sasl/dsasl-client.c b/src/lib-sasl/dsasl-client.c new file mode 100644 index 0000000..bf11d5c --- /dev/null +++ b/src/lib-sasl/dsasl-client.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "safe-memset.h" +#include "dsasl-client-private.h" + +static int init_refcount = 0; +static ARRAY(const struct dsasl_client_mech *) dsasl_mechanisms = ARRAY_INIT; + +static const struct dsasl_client_mech * +dsasl_client_mech_find_idx(const char *name, unsigned int *idx_r) +{ + const struct dsasl_client_mech *const *mechp; + + array_foreach(&dsasl_mechanisms, mechp) { + if (strcasecmp((*mechp)->name, name) == 0) { + *idx_r = array_foreach_idx(&dsasl_mechanisms, mechp); + return *mechp; + } + } + return NULL; +} + +const struct dsasl_client_mech *dsasl_client_mech_find(const char *name) +{ + unsigned int idx; + + return dsasl_client_mech_find_idx(name, &idx); +} + +const char *dsasl_client_mech_get_name(const struct dsasl_client_mech *mech) +{ + return mech->name; +} + +void dsasl_client_mech_register(const struct dsasl_client_mech *mech) +{ + unsigned int idx; + + if (dsasl_client_mech_find_idx(mech->name, &idx) != NULL) { + /* allow plugins to override the default mechanisms */ + array_delete(&dsasl_mechanisms, idx, 1); + } + array_push_back(&dsasl_mechanisms, &mech); +} + +void dsasl_client_mech_unregister(const struct dsasl_client_mech *mech) +{ + unsigned int idx; + + if (dsasl_client_mech_find_idx(mech->name, &idx) == NULL) + i_panic("SASL mechanism not registered: %s", mech->name); + array_delete(&dsasl_mechanisms, idx, 1); +} + +struct dsasl_client *dsasl_client_new(const struct dsasl_client_mech *mech, + const struct dsasl_client_settings *set) +{ + struct dsasl_client *client; + pool_t pool = pool_alloconly_create("sasl client", 512); + + client = p_malloc(pool, mech->struct_size); + client->pool = pool; + client->mech = mech; + client->set.authid = p_strdup(pool, set->authid); + client->set.authzid = p_strdup(pool, set->authzid); + client->password = p_strdup(pool, set->password); + client->set.password = client->password; + return client; +} + +void dsasl_client_free(struct dsasl_client **_client) +{ + struct dsasl_client *client = *_client; + + if (client == NULL) + return; + *_client = NULL; + + if (client->mech->free != NULL) + client->mech->free(client); + if (client->password != NULL) + safe_memset(client->password, 0, strlen(client->password)); + pool_unref(&client->pool); +} + +int dsasl_client_input(struct dsasl_client *client, + const unsigned char *input, size_t input_len, + const char **error_r) +{ + if ((client->mech->flags & DSASL_MECH_SEC_ALLOW_NULS) == 0 && + memchr(input, '\0', input_len) != NULL) { + *error_r = "Unexpected NUL in input data"; + return -1; + } + return client->mech->input(client, input, input_len, error_r); +} + +int dsasl_client_output(struct dsasl_client *client, + const unsigned char **output_r, size_t *output_len_r, + const char **error_r) +{ + return client->mech->output(client, output_r, output_len_r, error_r); +} + +int dsasl_client_set_parameter(struct dsasl_client *client, + const char *param, const char *value, + const char **error_r) +{ + if (client->mech->set_parameter != NULL) { + int ret = client->mech->set_parameter(client, param, + value, error_r); + i_assert(ret >= 0 || *error_r != NULL); + return ret; + } else + return 0; +} + +int dsasl_client_get_result(struct dsasl_client *client, + const char *key, const char **value_r, + const char **error_r) +{ + if (client->mech->get_result != NULL) { + int ret = + client->mech->get_result(client, key, value_r, error_r); + i_assert(ret <= 0 || *value_r != NULL); + i_assert(ret >= 0 || *error_r != NULL); + return ret; + } else + return 0; +} + +void dsasl_clients_init(void) +{ + if (init_refcount++ > 0) + return; + + i_array_init(&dsasl_mechanisms, 8); + dsasl_client_mech_register(&dsasl_client_mech_external); + dsasl_client_mech_register(&dsasl_client_mech_plain); + dsasl_client_mech_register(&dsasl_client_mech_login); + dsasl_client_mech_register(&dsasl_client_mech_oauthbearer); + dsasl_client_mech_register(&dsasl_client_mech_xoauth2); +} + +void dsasl_clients_deinit(void) +{ + if (--init_refcount > 0) + return; + array_free(&dsasl_mechanisms); +} |