1/* printer.h --- Convert DIGEST-MD5 token structures into strings.
2 * Copyright (C) 2004-2012 Simon Josefsson
3 *
4 * This file is part of GNU SASL Library.
5 *
6 * GNU SASL Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * GNU SASL Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GNU SASL Library; if not, write to the Free
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27/* Get prototypes. */
28#include "printer.h"
29
30/* Get free. */
31#include <stdlib.h>
32
33/* Get asprintf. */
34#include <stdio.h>
35
36/* Get token validator. */
37#include "validate.h"
38
39/* Append a key/value pair to a comma'd string list. Additionally enclose
40 the value in quotes if requested. */
41static int
42comma_append (char **dst, const char *key, const char *value, int quotes)
43{
44 char *tmp;
45 int result;
46
47 if (*dst)
48 if (value)
49 if (quotes)
50 result = asprintf (&tmp, "%s, %s=\"%s\"", *dst, key, value);
51 else
52 result = asprintf (&tmp, "%s, %s=%s", *dst, key, value);
53 else
54 result = asprintf (&tmp, "%s, %s", *dst, key);
55 else if (value)
56 if (quotes)
57 result = asprintf (&tmp, "%s=\"%s\"", key, value);
58 else
59 result = asprintf (&tmp, "%s=%s", key, value);
60 else
61 result = asprintf (&tmp, "%s", key);
62
63 if (result < 0)
64 return result;
65
66 free (*dst);
67
68 *dst = tmp;
69
70 return result;
71}
72
73char *
74digest_md5_print_challenge (digest_md5_challenge * c)
75{
76 char *out = NULL;
77 size_t i;
78
79 /* Below we assume the mandatory fields are present, verify that
80 first to avoid crashes. */
81 if (digest_md5_validate_challenge (c) != 0)
82 return NULL;
83
84 for (i = 0; i < c->nrealms; i++)
85 {
86 if (comma_append (&out, "realm", c->realms[i], 1) < 0)
87 {
88 free (out);
89 return NULL;
90 }
91 }
92
93 if (c->nonce)
94 if (comma_append (&out, "nonce", c->nonce, 1) < 0)
95 {
96 free (out);
97 return NULL;
98 }
99
100 if (c->qops)
101 {
102 char *tmp = NULL;
103
104 if (c->qops & DIGEST_MD5_QOP_AUTH)
105 if (comma_append (&tmp, "auth", NULL, 0) < 0)
106 {
107 free (tmp);
108 free (out);
109 return NULL;
110 }
111
112 if (c->qops & DIGEST_MD5_QOP_AUTH_INT)
113 if (comma_append (&tmp, "auth-int", NULL, 0) < 0)
114 {
115 free (tmp);
116 free (out);
117 return NULL;
118 }
119
120 if (c->qops & DIGEST_MD5_QOP_AUTH_CONF)
121 if (comma_append (&tmp, "auth-conf", NULL, 0) < 0)
122 {
123 free (tmp);
124 free (out);
125 return NULL;
126 }
127
128 if (comma_append (&out, "qop", tmp, 1) < 0)
129 {
130 free (tmp);
131 free (out);
132 return NULL;
133 }
134
135 free (tmp);
136 }
137
138 if (c->stale)
139 if (comma_append (&out, "stale", "true", 0) < 0)
140 {
141 free (out);
142 return NULL;
143 }
144
145 if (c->servermaxbuf)
146 {
147 char *tmp;
148
149 if (asprintf (&tmp, "%lu", c->servermaxbuf) < 0)
150 {
151 free (out);
152 return NULL;
153 }
154
155 if (comma_append (&out, "maxbuf", tmp, 0) < 0)
156 {
157 free (out);
158 return NULL;
159 }
160
161 free (tmp);
162 }
163
164 if (c->utf8)
165 if (comma_append (&out, "charset", "utf-8", 0) < 0)
166 {
167 free (out);
168 return NULL;
169 }
170
171 if (comma_append (&out, "algorithm", "md5-sess", 0) < 0)
172 {
173 free (out);
174 return NULL;
175 }
176
177 if (c->ciphers)
178 {
179 char *tmp = NULL;
180
181 if (c->ciphers & DIGEST_MD5_CIPHER_3DES)
182 if (comma_append (&tmp, "3des", NULL, 0) < 0)
183 {
184 free (tmp);
185 free (out);
186 return NULL;
187 }
188
189 if (c->ciphers & DIGEST_MD5_CIPHER_DES)
190 if (comma_append (&tmp, "des", NULL, 0) < 0)
191 {
192 free (tmp);
193 free (out);
194 return NULL;
195 }
196
197 if (c->ciphers & DIGEST_MD5_CIPHER_RC4_40)
198 if (comma_append (&tmp, "rc4-40", NULL, 0) < 0)
199 {
200 free (tmp);
201 free (out);
202 return NULL;
203 }
204
205 if (c->ciphers & DIGEST_MD5_CIPHER_RC4)
206 if (comma_append (&tmp, "rc4", NULL, 0) < 0)
207 {
208 free (tmp);
209 free (out);
210 return NULL;
211 }
212
213 if (c->ciphers & DIGEST_MD5_CIPHER_RC4_56)
214 if (comma_append (&tmp, "rc4-56", NULL, 0) < 0)
215 {
216 free (tmp);
217 free (out);
218 return NULL;
219 }
220
221 if (c->ciphers & DIGEST_MD5_CIPHER_AES_CBC)
222 if (comma_append (&tmp, "aes-cbc", NULL, 0) < 0)
223 {
224 free (tmp);
225 free (out);
226 return NULL;
227 }
228
229 if (comma_append (&out, "cipher", tmp, 1) < 0)
230 {
231 free (tmp);
232 free (out);
233 return NULL;
234 }
235
236 free (tmp);
237 }
238
239 return out;
240}
241
242char *
243digest_md5_print_response (digest_md5_response * r)
244{
245 char *out = NULL;
246 const char *qop = NULL;
247 const char *cipher = NULL;
248
249 /* Below we assume the mandatory fields are present, verify that
250 first to avoid crashes. */
251 if (digest_md5_validate_response (r) != 0)
252 return NULL;
253
254 if (r->qop & DIGEST_MD5_QOP_AUTH_CONF)
255 qop = "qop=auth-conf";
256 else if (r->qop & DIGEST_MD5_QOP_AUTH_INT)
257 qop = "qop=auth-int";
258 else if (r->qop & DIGEST_MD5_QOP_AUTH)
259 qop = "qop=auth";
260
261 if (r->cipher & DIGEST_MD5_CIPHER_3DES)
262 cipher = "cipher=3des";
263 else if (r->cipher & DIGEST_MD5_CIPHER_DES)
264 cipher = "cipher=des";
265 else if (r->cipher & DIGEST_MD5_CIPHER_RC4_40)
266 cipher = "cipher=rc4-40";
267 else if (r->cipher & DIGEST_MD5_CIPHER_RC4)
268 cipher = "cipher=rc4";
269 else if (r->cipher & DIGEST_MD5_CIPHER_RC4_56)
270 cipher = "cipher=rc4-56";
271 else if (r->cipher & DIGEST_MD5_CIPHER_AES_CBC)
272 cipher = "cipher=aes-cbc";
273 else if (r->cipher & DIGEST_MD5_CIPHER_3DES)
274 cipher = "cipher=3des";
275
276 if (r->username)
277 if (comma_append (&out, "username", r->username, 1) < 0)
278 {
279 free (out);
280 return NULL;
281 }
282
283 if (r->realm)
284 if (comma_append (&out, "realm", r->realm, 1) < 0)
285 {
286 free (out);
287 return NULL;
288 }
289
290 if (r->nonce)
291 if (comma_append (&out, "nonce", r->nonce, 1) < 0)
292 {
293 free (out);
294 return NULL;
295 }
296
297 if (r->cnonce)
298 if (comma_append (&out, "cnonce", r->cnonce, 1) < 0)
299 {
300 free (out);
301 return NULL;
302 }
303
304 if (r->nc)
305 {
306 char *tmp;
307
308 if (asprintf (&tmp, "%08lx", r->nc) < 0)
309 {
310 free (out);
311 return NULL;
312 }
313
314 if (comma_append (&out, "nc", tmp, 0) < 0)
315 {
316 free (tmp);
317 free (out);
318 return NULL;
319 }
320
321 free (tmp);
322 }
323
324 if (qop)
325 if (comma_append (&out, qop, NULL, 0) < 0)
326 {
327 free (out);
328 return NULL;
329 }
330
331 if (r->digesturi)
332 if (comma_append (&out, "digest-uri", r->digesturi, 1) < 0)
333 {
334 free (out);
335 return NULL;
336 }
337
338 if (r->response)
339 if (comma_append (&out, "response", r->response, 0) < 0)
340 {
341 free (out);
342 return NULL;
343 }
344
345 if (r->clientmaxbuf)
346 {
347 char *tmp;
348
349 if (asprintf (&tmp, "%lu", r->clientmaxbuf) < 0)
350 {
351 free (out);
352 return NULL;
353 }
354
355 if (comma_append (&out, "maxbuf", tmp, 0) < 0)
356 {
357 free (tmp);
358 free (out);
359 return NULL;
360 }
361
362 free (tmp);
363 }
364
365 if (r->utf8)
366 if (comma_append (&out, "charset", "utf-8", 0) < 0)
367 {
368 free (out);
369 return NULL;
370 }
371
372 if (cipher)
373 if (comma_append (&out, cipher, NULL, 0) < 0)
374 {
375 free (out);
376 return NULL;
377 }
378
379 if (r->authzid)
380 if (comma_append (&out, "authzid", r->authzid, 1) < 0)
381 {
382 free (out);
383 return NULL;
384 }
385
386 return out;
387}
388
389char *
390digest_md5_print_finish (digest_md5_finish * finish)
391{
392 char *out;
393
394 /* Below we assume the mandatory fields are present, verify that
395 first to avoid crashes. */
396 if (digest_md5_validate_finish (finish) != 0)
397 return NULL;
398
399 if (asprintf (&out, "rspauth=%s", finish->rspauth) < 0)
400 return NULL;
401
402 return out;
403}
404