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