1 #include "auth.h"
2 #include "base64.h"
3 #include "buf.h"
4 #include "str.h"
5 #include "unused.h"
6
7 #include <vanessa_logger.h>
8
9 #if WITH_LIBIDN
10 #include <stringprep.h>
11
saslprep(const char * in)12 static char *saslprep(const char *in)
13 {
14 int status;
15 char *out;
16
17 status = stringprep_profile(in, &out, "SASLprep", 0);
18 if (status != STRINGPREP_OK) {
19 VANESSA_LOGGER_DEBUG_UNSAFE("stringprep_profile: \"%s\"",
20 stringprep_strerror(status));
21 return NULL;
22 }
23
24 return out;
25 }
26
saslprep_str_free(char * out)27 static void saslprep_str_free(char *out)
28 {
29 free(out);
30 }
31
32 #else
saslprep(char * in)33 static char *saslprep(char *in)
34 {
35 return in;
36 }
37
saslprep_str_free(char * UNUSED (out))38 static void saslprep_str_free(char *UNUSED(out))
39 {
40 ;
41 }
42 #endif
43
44 /**********************************************************************
45 * sasl_plain_challenge_decode
46 * Decode a SASL PLAIN challenge
47 * pre: challenge: the challenge
48 * return: .auth: seeded auth structure
49 * .status: auth_status_ok on success
50 * auth_status_invalid if the challenge is invalid
51 * auth_status_error on internal error
52 **********************************************************************/
53
sasl_plain_challenge_decode(char * challenge)54 struct auth_status sasl_plain_challenge_decode(char *challenge)
55 {
56 STRUCT_CONST_BUF(in);
57 STRUCT_BUF(out);
58 STRUCT_AUTH_STATUS(as);
59 char *authorisation_id = NULL, *authentication_id = NULL;
60 char *passwd = NULL, *base64_data = NULL, *tmp = NULL;
61
62 in.data = challenge;
63 in.len = strlen(challenge);
64 out = base64_decode(&in);
65 if (buf_is_err(&out)) {
66 if (out.len) {
67 VANESSA_LOGGER_DEBUG("base64_decode");
68 goto err;
69 }
70 as.reason = "Invalid base64 encoded challenge, mate";
71 as.status = auth_status_invalid;
72 goto err;
73 }
74 base64_data = out.data;
75
76 /* Note about the use of strn_to_str() below.
77 *
78 * This may over-allocate and result in a string with
79 * more than one '\0', but it won't over-run and anything
80 * after the first '\0' will subsequently be ignored */
81
82 if (out.len == 0) {
83 as.reason = "Empty challenge, mate";
84 as.status = auth_status_invalid;
85 goto err;
86 }
87
88 if (*out.data) {
89 char *saslprep_str;
90
91 authorisation_id = strn_to_str(out.data, out.len);
92 if (!authorisation_id) {
93 VANESSA_LOGGER_DEBUG("strdup authorisation_id");
94 goto err;
95 }
96
97 saslprep_str = authorisation_id;
98 authorisation_id = saslprep(authorisation_id);
99 saslprep_str_free(saslprep_str);
100 if (!authorisation_id) {
101 VANESSA_LOGGER_DEBUG("saslprep "
102 "authorisation_id");
103 goto err;
104 }
105
106 out.data += strlen(authorisation_id);
107 out.len -= strlen(authorisation_id);
108 }
109
110 if (out.len < 1) {
111 as.reason = "Challenge has no authentication id, mate";
112 as.status = -1;
113 goto err;
114 }
115
116 out.data++;
117 out.len--;
118
119 authentication_id = strn_to_str(out.data, out.len);
120 if (!authentication_id) {
121 VANESSA_LOGGER_DEBUG("strdup authentication_id");
122 goto err;
123 }
124 out.data += strlen(authentication_id);
125 out.len -= strlen(authentication_id);
126
127 tmp = saslprep(authentication_id);
128 if (!tmp) {
129 VANESSA_LOGGER_DEBUG("saslprep: authentication_id");
130 goto err;
131 }
132 if (tmp != authentication_id) {
133 free(authentication_id);
134 authentication_id = tmp;
135 }
136
137 if (!*authentication_id) {
138 as.reason = "Empty authentication id, mate";
139 as.status = auth_status_invalid;
140 goto err;
141 }
142
143 if (out.len < 1) {
144 as.reason = "Challenge has no password, mate";
145 as.status = auth_status_invalid;
146 goto err;
147 }
148
149 out.data++;
150 out.len--;
151
152 passwd = strn_to_str(out.data, out.len);
153 if (!passwd) {
154 VANESSA_LOGGER_DEBUG("strdup passwd");
155 goto err;
156 }
157 out.len -= strlen(passwd);
158
159 if (out.len) {
160 as.reason = "Trailing garbage in challenge, mate";
161 as.status = -1;
162 goto err;
163 }
164
165 as.auth = auth_set_sasl_plain(authorisation_id,
166 authentication_id, passwd);
167 authorisation_id = authentication_id = passwd = NULL;
168 as.status = auth_status_ok;
169
170 err:
171 free(authorisation_id);
172 free(authentication_id);
173 free(passwd);
174 free(base64_data);
175 return as;
176 }
177
178 /**********************************************************************
179 * sasl_plain_challenge_encode
180 * Encode a SASL PLAIN challenge
181 * pre: auth: seeded auth structure
182 * return: encoded challenge
183 * NULL on error
184 **********************************************************************/
185
sasl_plain_challenge_encode(const struct auth * auth)186 char * sasl_plain_challenge_encode(const struct auth *auth)
187 {
188 STRUCT_BUF(in);
189 STRUCT_BUF(out);
190 char *p, *out_str = NULL;
191
192 if (auth->authorisation_id)
193 in.len += strlen(auth->authorisation_id);
194 in.len += 1 + strlen(auth->authentication_id) + 1;
195 in.len += strlen(auth->passwd);
196
197 in.data = malloc(in.len);
198 if (!in.len) {
199 VANESSA_LOGGER_DEBUG_ERRNO("malloc");
200 goto err;
201 }
202
203 p = in.data;
204 if (auth->authorisation_id) {
205 strcpy(in.data, auth->authorisation_id);
206 p += strlen(auth->authorisation_id) + 1;
207 } else {
208 in.data[0] = '\0';
209 p++;
210 }
211 strcpy(p, auth->authentication_id);
212 p += strlen(auth->authentication_id) + 1;
213 memcpy(p, auth->passwd, strlen(auth->passwd));
214
215 out = base64_encode(&in);
216 if (buf_is_err(&out)) {
217 VANESSA_LOGGER_DEBUG("base64_encode");
218 goto err;
219 }
220
221 out_str = strn_to_str(out.data, out.len);
222 if (!out_str) {
223 VANESSA_LOGGER_DEBUG("strn_to_str");
224 goto err;
225 }
226
227 err:
228 free(out.data);
229 free(in.data);
230 return out_str;
231 }
232