1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "safe-memset.h"
6 #include "dsasl-client-private.h"
7
8 static int init_refcount = 0;
9 static ARRAY(const struct dsasl_client_mech *) dsasl_mechanisms = ARRAY_INIT;
10
11 static const struct dsasl_client_mech *
dsasl_client_mech_find_idx(const char * name,unsigned int * idx_r)12 dsasl_client_mech_find_idx(const char *name, unsigned int *idx_r)
13 {
14 const struct dsasl_client_mech *const *mechp;
15
16 array_foreach(&dsasl_mechanisms, mechp) {
17 if (strcasecmp((*mechp)->name, name) == 0) {
18 *idx_r = array_foreach_idx(&dsasl_mechanisms, mechp);
19 return *mechp;
20 }
21 }
22 return NULL;
23 }
24
dsasl_client_mech_find(const char * name)25 const struct dsasl_client_mech *dsasl_client_mech_find(const char *name)
26 {
27 unsigned int idx;
28
29 return dsasl_client_mech_find_idx(name, &idx);
30 }
31
dsasl_client_mech_get_name(const struct dsasl_client_mech * mech)32 const char *dsasl_client_mech_get_name(const struct dsasl_client_mech *mech)
33 {
34 return mech->name;
35 }
36
dsasl_client_mech_register(const struct dsasl_client_mech * mech)37 void dsasl_client_mech_register(const struct dsasl_client_mech *mech)
38 {
39 unsigned int idx;
40
41 if (dsasl_client_mech_find_idx(mech->name, &idx) != NULL) {
42 /* allow plugins to override the default mechanisms */
43 array_delete(&dsasl_mechanisms, idx, 1);
44 }
45 array_push_back(&dsasl_mechanisms, &mech);
46 }
47
dsasl_client_mech_unregister(const struct dsasl_client_mech * mech)48 void dsasl_client_mech_unregister(const struct dsasl_client_mech *mech)
49 {
50 unsigned int idx;
51
52 if (dsasl_client_mech_find_idx(mech->name, &idx) == NULL)
53 i_panic("SASL mechanism not registered: %s", mech->name);
54 array_delete(&dsasl_mechanisms, idx, 1);
55 }
56
dsasl_client_new(const struct dsasl_client_mech * mech,const struct dsasl_client_settings * set)57 struct dsasl_client *dsasl_client_new(const struct dsasl_client_mech *mech,
58 const struct dsasl_client_settings *set)
59 {
60 struct dsasl_client *client;
61 pool_t pool = pool_alloconly_create("sasl client", 512);
62
63 client = p_malloc(pool, mech->struct_size);
64 client->pool = pool;
65 client->mech = mech;
66 client->set.authid = p_strdup(pool, set->authid);
67 client->set.authzid = p_strdup(pool, set->authzid);
68 client->password = p_strdup(pool, set->password);
69 client->set.password = client->password;
70 return client;
71 }
72
dsasl_client_free(struct dsasl_client ** _client)73 void dsasl_client_free(struct dsasl_client **_client)
74 {
75 struct dsasl_client *client = *_client;
76
77 *_client = NULL;
78
79 if (client->mech->free != NULL)
80 client->mech->free(client);
81 if (client->password != NULL)
82 safe_memset(client->password, 0, strlen(client->password));
83 pool_unref(&client->pool);
84 }
85
dsasl_client_input(struct dsasl_client * client,const unsigned char * input,size_t input_len,const char ** error_r)86 int dsasl_client_input(struct dsasl_client *client,
87 const unsigned char *input, size_t input_len,
88 const char **error_r)
89 {
90 if ((client->mech->flags & DSASL_MECH_SEC_ALLOW_NULS) == 0 &&
91 memchr(input, '\0', input_len) != NULL) {
92 *error_r = "Unexpected NUL in input data";
93 return -1;
94 }
95 return client->mech->input(client, input, input_len, error_r);
96 }
97
dsasl_client_output(struct dsasl_client * client,const unsigned char ** output_r,size_t * output_len_r,const char ** error_r)98 int dsasl_client_output(struct dsasl_client *client,
99 const unsigned char **output_r, size_t *output_len_r,
100 const char **error_r)
101 {
102 return client->mech->output(client, output_r, output_len_r, error_r);
103 }
104
dsasl_client_set_parameter(struct dsasl_client * client,const char * param,const char * value,const char ** error_r)105 int dsasl_client_set_parameter(struct dsasl_client *client,
106 const char *param, const char *value,
107 const char **error_r)
108 {
109 if (client->mech->set_parameter != NULL) {
110 int ret = client->mech->set_parameter(client, param,
111 value, error_r);
112 i_assert(ret >= 0 || *error_r != NULL);
113 return ret;
114 } else
115 return 0;
116 }
117
dsasl_client_get_result(struct dsasl_client * client,const char * key,const char ** value_r,const char ** error_r)118 int dsasl_client_get_result(struct dsasl_client *client,
119 const char *key, const char **value_r,
120 const char **error_r)
121 {
122 if (client->mech->get_result != NULL) {
123 int ret =
124 client->mech->get_result(client, key, value_r, error_r);
125 i_assert(ret <= 0 || *value_r != NULL);
126 i_assert(ret >= 0 || *error_r != NULL);
127 return ret;
128 } else
129 return 0;
130 }
131
dsasl_clients_init(void)132 void dsasl_clients_init(void)
133 {
134 if (init_refcount++ > 0)
135 return;
136
137 i_array_init(&dsasl_mechanisms, 8);
138 dsasl_client_mech_register(&dsasl_client_mech_external);
139 dsasl_client_mech_register(&dsasl_client_mech_plain);
140 dsasl_client_mech_register(&dsasl_client_mech_login);
141 dsasl_client_mech_register(&dsasl_client_mech_oauthbearer);
142 dsasl_client_mech_register(&dsasl_client_mech_xoauth2);
143 }
144
dsasl_clients_deinit(void)145 void dsasl_clients_deinit(void)
146 {
147 if (--init_refcount > 0)
148 return;
149 array_free(&dsasl_mechanisms);
150 }
151