Dillo v3.1.1-46-g8a360e32
Loading...
Searching...
No Matches
auth.c
Go to the documentation of this file.
1/*
2 * File: auth.c
3 *
4 * Copyright 2008 Jeremy Henty <onepoint@starurchin.org>
5 * Copyright 2009 Justus Winter <4winter@informatik.uni-hamburg.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
20#include <ctype.h> /* iscntrl, isascii */
21#include "auth.h"
22#include "msg.h"
23#include "misc.h"
24#include "dialog.hh"
25#include "digest.h"
26#include "../dlib/dlib.h"
27
28typedef struct {
29 int ok;
31 const char *realm;
32 const char *nonce;
33 const char *opaque;
34 int stale;
35 enum AuthParseDigestAlgorithm_t algorithm;
36 const char *domain;
37 enum AuthParseDigestQOP_t qop;
38} AuthParse_t;
39
40typedef struct {
41 char *scheme;
42 char *authority;
43 Dlist *realms;
44} AuthHost_t;
45
46typedef struct {
47 const AuthParse_t *auth_parse;
48 const DilloUrl *url;
49} AuthDialogData_t;
50
55
59void a_Auth_init(void)
60{
62}
63
64static AuthParse_t *Auth_parse_new(void)
65{
66 AuthParse_t *auth_parse = dNew(AuthParse_t, 1);
67 auth_parse->ok = 0;
68 auth_parse->type = TYPENOTSET;
69 auth_parse->realm = NULL;
70 auth_parse->nonce = NULL;
71 auth_parse->opaque = NULL;
72 auth_parse->stale = 0;
73 auth_parse->algorithm = ALGORITHMNOTSET;
74 auth_parse->domain = NULL;
75 auth_parse->qop = QOPNOTSET;
76 return auth_parse;
77}
78
79static void Auth_parse_free(AuthParse_t *auth_parse)
80{
81 if (auth_parse) {
82 dFree((void *)auth_parse->realm);
83 dFree((void *)auth_parse->nonce);
84 dFree((void *)auth_parse->opaque);
85 dFree((void *)auth_parse->domain);
86 dFree(auth_parse);
87 }
88}
89
90static int Auth_path_is_inside(const char *path1, const char *path2, int len)
91{
92 /*
93 * path2 is effectively truncated to length len. Typically len will be
94 * strlen(path2), or 1 less when we want to ignore a trailing '/'.
95 */
96 return
97 strncmp(path1, path2, len) == 0 &&
98 (path1[len] == '\0' || path1[len] == '/');
99}
100
105static int Auth_is_token_char(char c)
106{
107 const char *invalid = "\"()<>@,;:\\[]?=/{} \t";
108 return (!d_isascii(c) || strchr(invalid, c) || iscntrl((uchar_t)c)) ? 0 : 1;
109}
110
125static Dstr *Auth_unquote_value(char **valuep)
126{
127 char c, quoted;
128 char *value = *valuep;
129 Dstr *result;
130
131 while (*value == ' ' || *value == '\t')
132 value++;
133
134 if ((quoted = *value == '"'))
135 value++;
136
137 result = dStr_new(NULL);
138 while ((c = *value) &&
139 (( quoted && c != '"') ||
140 (!quoted && Auth_is_token_char(c)))) {
141 dStr_append_c(result, (c == '\\' && value[1]) ? *++value : c);
142 value++;
143 }
144
145 if (quoted && *value == '\"')
146 value++;
147 *valuep = value;
148 return result;
149}
150
151typedef int (Auth_parse_token_value_callback_t)(AuthParse_t *auth_parse,
152 char *token,
153 const char *value);
154
155
164static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth,
166{
167 char keep_going, expect_quoted;
168 char *token, *beyond_token;
169 Dstr *value;
170 size_t *token_size;
171
172 while (**auth) {
173 _MSG("Auth_parse_token_value: remaining: %s\n", *auth);
174
175 /* parse a token */
176 token = *auth;
177
178 token_size = 0;
179 while (Auth_is_token_char(**auth)) {
180 (*auth)++;
181 token_size++;
182 }
183 if (token_size == 0) {
184 MSG("Auth_parse_token_value: missing auth token\n");
185 return 0;
186 }
187 beyond_token = *auth;
188 /* skip linear whitespace characters */
189 while (**auth == ' ' || **auth == '\t')
190 (*auth)++;
191
192 /* parse the '=' */
193 switch (*(*auth)++) {
194 case '=':
195 *beyond_token = '\0';
196 break;
197 case '\0':
198 case ',':
199 MSG("Auth_parse_token_value: missing auth token value\n");
200 return 0;
201 break;
202 default:
203 MSG("Auth_parse_token_value: garbage after auth token\n");
204 return 0;
205 break;
206 }
207
208 value = Auth_unquote_value(auth);
209 expect_quoted = !(strcmp(token, "stale") == 0 ||
210 strcmp(token, "algorithm") == 0);
211
212 if (((*auth)[-1] == '"') != expect_quoted)
213 MSG_WARN("Auth_parse_token_value: "
214 "Values for key %s should%s be quoted.\n",
215 token, expect_quoted ? "" : " not");
216
217 keep_going = callback(auth_parse, token, value->str);
218 dStr_free(value, 1);
219 if (!keep_going)
220 break;
221
222 /* skip ' ' and ',' */
223 while ((**auth == ' ') || (**auth == ','))
224 (*auth)++;
225 }
226 return 1;
227}
228
229static int Auth_parse_basic_challenge_cb(AuthParse_t *auth_parse, char *token,
230 const char *value)
231{
232 if (dStrAsciiCasecmp("realm", token) == 0) {
233 if (!auth_parse->realm)
234 auth_parse->realm = dStrdup(value);
235 return 0; /* end parsing */
236 } else
237 MSG("Auth_parse_basic_challenge_cb: Ignoring unknown parameter: %s = "
238 "'%s'\n", token, value);
239 return 1;
240}
241
242static int Auth_parse_digest_challenge_cb(AuthParse_t *auth_parse, char *token,
243 const char *value)
244{
245 const char *const fn = "Auth_parse_digest_challenge_cb";
246
247 if (!dStrAsciiCasecmp("realm", token) && !auth_parse->realm)
248 auth_parse->realm = dStrdup(value);
249 else if (!strcmp("domain", token) && !auth_parse->domain)
250 auth_parse->domain = dStrdup(value);
251 else if (!strcmp("nonce", token) && !auth_parse->nonce)
252 auth_parse->nonce = dStrdup(value);
253 else if (!strcmp("opaque", token) && !auth_parse->opaque)
254 auth_parse->opaque = dStrdup(value);
255 else if (strcmp("stale", token) == 0) {
256 if (dStrAsciiCasecmp("true", value) == 0)
257 auth_parse->stale = 1;
258 else if (dStrAsciiCasecmp("false", value) == 0)
259 auth_parse->stale = 0;
260 else {
261 MSG("%s: Invalid stale value: %s\n", fn, value);
262 return 0;
263 }
264 } else if (strcmp("algorithm", token) == 0) {
265 if (strcmp("MD5", value) == 0)
266 auth_parse->algorithm = MD5;
267 else if (strcmp("MD5-sess", value) == 0) {
268 /* auth_parse->algorithm = MD5SESS; */
269 MSG("%s: MD5-sess algorithm disabled (not tested because 'not "
270 "correctly implemented yet' in Apache 2.2)\n", fn);
271 return 0;
272 } else {
273 MSG("%s: Unknown algorithm: %s\n", fn, value);
274 return 0;
275 }
276 } else if (strcmp("qop", token) == 0) {
277 while (*value) {
278 int len = strcspn(value, ", \t");
279 if (len == 4 && strncmp("auth", value, 4) == 0) {
280 auth_parse->qop = AUTH;
281 break;
282 }
283 if (len == 8 && strncmp("auth-int", value, 8) == 0) {
284 /* auth_parse->qop = AUTHINT; */
285 /* Keep searching; maybe we'll find an "auth" yet. */
286 MSG("%s: auth-int qop disabled (not tested because 'not "
287 "implemented yet' in Apache 2.2)\n", fn);
288 } else {
289 MSG("%s: Unknown qop value in %s\n", fn, value);
290 }
291 value += len;
292 while (*value == ' ' || *value == '\t')
293 value++;
294 if (*value == ',')
295 value++;
296 while (*value == ' ' || *value == '\t')
297 value++;
298 }
299 } else {
300 MSG("%s: Ignoring unknown parameter: %s = '%s'\n", fn, token, value);
301 }
302 return 1;
303}
304
305static void Auth_parse_challenge_args(AuthParse_t *auth_parse,
306 char **challenge,
308{
309 /* parse comma-separated token-value pairs */
310 while (1) {
311 /* skip space and comma characters */
312 while (**challenge == ' ' || **challenge == ',')
313 (*challenge)++;
314 /* end of string? */
315 if (!**challenge)
316 break;
317 /* parse token-value pair */
318 if (!Auth_parse_token_value(auth_parse, challenge, cb))
319 break;
320 }
321
322 if (auth_parse->type == BASIC) {
323 if (auth_parse->realm) {
324 auth_parse->ok = 1;
325 } else {
326 MSG("Auth_parse_challenge_args: missing Basic auth realm\n");
327 return;
328 }
329 } else if (auth_parse->type == DIGEST) {
330 if (auth_parse->realm && auth_parse->nonce) {
331 auth_parse->ok = 1;
332 } else {
333 MSG("Auth_parse_challenge_args: Digest challenge incomplete\n");
334 return;
335 }
336 }
337}
338
339static void Auth_parse_challenge(AuthParse_t *auth_parse, char *challenge)
340{
342
343 MSG("auth.c: Auth_parse_challenge: challenge = '%s'\n", challenge);
344 if (auth_parse->type == DIGEST) {
345 challenge += 7;
347 } else {
348 challenge += 6;
350 }
351 Auth_parse_challenge_args(auth_parse, &challenge, cb);
352}
353
357static AuthHost_t *Auth_host_by_url(const DilloUrl *url)
358{
359 AuthHost_t *host;
360 int i;
361
362 for (i = 0; (host = dList_nth_data(auth_hosts, i)); i++)
363 if (((dStrAsciiCasecmp(URL_SCHEME(url), host->scheme) == 0) &&
364 (dStrAsciiCasecmp(URL_AUTHORITY(url), host->authority) == 0)))
365 return host;
366
367 return NULL;
368}
369
373static AuthRealm_t *Auth_realm_by_name(const AuthHost_t *host,
374 const char *name)
375{
376 AuthRealm_t *realm;
377 int i;
378
379 for (i = 0; (realm = dList_nth_data(host->realms, i)); i++)
380 if (strcmp(realm->name, name) == 0)
381 return realm;
382
383 return NULL;
384}
385
389static AuthRealm_t *Auth_realm_by_path(const AuthHost_t *host,
390 const char *path)
391{
392 AuthRealm_t *realm_best, *realm;
393 int i, j;
394 int match_length = 0;
395
396 realm_best = NULL;
397 for (i = 0; (realm = dList_nth_data(host->realms, i)); i++) {
398 char *realm_path;
399
400 for (j = 0; (realm_path = dList_nth_data(realm->paths, j)); j++) {
401 int realm_path_length = strlen(realm_path);
402 if (Auth_path_is_inside(path, realm_path, realm_path_length) &&
403 !(realm_best && match_length >= realm_path_length)) {
404 realm_best = realm;
405 match_length = realm_path_length;
406 }
407 }
408 }
409
410 return realm_best;
411}
412
414{
415 int i;
416
417 MSG("Auth_realm_delete: \"%s\"\n", realm->name);
418 for (i = dList_length(realm->paths) - 1; i >= 0; i--)
419 dFree(dList_nth_data(realm->paths, i));
420 dList_free(realm->paths);
421 dFree(realm->name);
422 dFree(realm->username);
423 dFree(realm->authorization);
424 dFree(realm->cnonce);
425 dFree(realm->nonce);
426 dFree(realm->opaque);
427 dFree(realm->domain);
428 dFree(realm);
429}
430
431static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path)
432{
433 int i;
434 char *realm_path;
435
436 for (i = 0; (realm_path = dList_nth_data(realm->paths, i)); i++)
437 if (Auth_path_is_inside(path, realm_path, strlen(realm_path)))
438 return 1;
439
440 return 0;
441}
442
443static void Auth_realm_add_path(AuthRealm_t *realm, const char *path)
444{
445 int len, i;
446 char *realm_path, *n_path;
447
448 n_path = dStrdup(path);
449 len = strlen(n_path);
450
451 /* remove trailing '/' */
452 if (len && n_path[len - 1] == '/')
453 n_path[--len] = 0;
454
455 /* delete existing paths that are inside the new one */
456 for (i = 0; (realm_path = dList_nth_data(realm->paths, i)); i++) {
457 if (Auth_path_is_inside(realm_path, path, len)) {
458 dList_remove_fast(realm->paths, realm_path);
459 dFree(realm_path);
460 i--; /* reconsider this slot */
461 }
462 }
463
464 dList_append(realm->paths, n_path);
465}
466
472char *a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri)
473{
474 char *ret = NULL;
475 AuthHost_t *host;
476 AuthRealm_t *realm;
477
478 if ((host = Auth_host_by_url(url)) &&
479 (realm = Auth_realm_by_path(host, URL_PATH(url)))) {
480 if (realm->type == BASIC)
481 ret = dStrdup(realm->authorization);
482 else if (realm->type == DIGEST)
483 ret = a_Digest_authorization_hdr(realm, url, request_uri);
484 else
485 MSG("a_Auth_get_auth_str() got an unknown realm type: %i.\n",
486 realm->type);
487 }
488 return ret;
489}
490
494static int Auth_do_auth_required(const AuthParse_t *auth_parse,
495 const DilloUrl *url)
496{
497 /*
498 * TO DO: I dislike the way that this code must decide whether we
499 * sent authentication during the request and trust us to resend it
500 * after the reload. Could it be more robust if every DilloUrl
501 * recorded its authentication, and whether it was accepted? (JCH)
502 */
503
504 AuthHost_t *host;
505 AuthRealm_t *realm;
506
507 /*
508 * The size of the following comments reflects the concerns in the
509 * TO DO at the top of this function. It should not be so hard to
510 * explain why code is correct! (JCH)
511 */
512
513 /*
514 * If we have authentication but did not send it (because we did
515 * not know this path was in the realm) then we update the realm.
516 * We do not re-authenticate because our authentication is probably
517 * OK. Thanks to the updated realm the forthcoming reload will
518 * make us send the authentication. If our authentication is not
519 * OK the server will challenge us again after the reload and then
520 * we will re-authenticate.
521 */
522 if ((host = Auth_host_by_url(url)) &&
523 (realm = Auth_realm_by_name(host, auth_parse->realm))) {
524 if (!Auth_realm_includes_path(realm, URL_PATH(url))) {
525 _MSG("Auth_do_auth_required: updating realm '%s' with URL '%s'\n",
526 auth_parse->realm, URL_STR(url));
527 Auth_realm_add_path(realm, URL_PATH(url));
528 return 0;
529 }
530
531 if (auth_parse->type == DIGEST && auth_parse->stale) {
532 /* we do have valid credentials but our nonce is old */
533 dFree((void *)realm->nonce);
534 realm->nonce = dStrdup(auth_parse->nonce);
535 return 0;
536 }
537 }
538
539 /*
540 * Either we had no authentication or we sent it and the server
541 * rejected it, so we must re-authenticate.
542 */
543 return 1;
544}
545
546static void Auth_do_auth_dialog_cb(const char *user, const char *password,
547 void *vData)
548{
549 AuthDialogData_t *data;
550 AuthHost_t *host;
551 AuthRealm_t *realm;
552
553 data = (AuthDialogData_t *)vData;
554
555 /* find or create the host */
556 if (!(host = Auth_host_by_url(data->url))) {
557 /* create a new host */
558 host = dNew(AuthHost_t, 1);
559 host->scheme = dStrdup(URL_SCHEME(data->url));
560 host->authority = dStrdup(URL_AUTHORITY(data->url));
561 host->realms = dList_new(1);
563 }
564
565 /* find or create the realm */
566 if (!(realm = Auth_realm_by_name(host, data->auth_parse->realm))) {
567 realm = dNew0(AuthRealm_t, 1);
568 realm->name = dStrdup(data->auth_parse->realm);
569 realm->paths = dList_new(1);
570 dList_append(host->realms, realm);
571 }
572 realm->type = data->auth_parse->type;
573 dFree(realm->authorization);
574 realm->authorization = NULL;
575
576 Auth_realm_add_path(realm, URL_PATH(data->url));
577
578 if (realm->type == BASIC) {
579 char *user_password = dStrconcat(user, ":", password, NULL);
580 char *response = a_Misc_encode_base64(user_password);
581 char *authorization =
582 dStrconcat("Authorization: Basic ", response, "\r\n", NULL);
583 dFree(realm->authorization);
584 realm->authorization = authorization;
585 dFree(response);
586 dStrshred(user_password);
587 dFree(user_password);
588 } else if (realm->type == DIGEST) {
589 dFree(realm->username);
590 realm->username = dStrdup(user);
591 realm->nonce_count = 0;
592 dFree(realm->nonce);
593 realm->nonce = dStrdup(data->auth_parse->nonce);
594 dFree(realm->opaque);
595 realm->opaque = dStrdup(data->auth_parse->opaque);
596 realm->algorithm = data->auth_parse->algorithm;
597 dFree(realm->domain);
598 realm->domain = dStrdup(data->auth_parse->domain);
599 realm->qop = data->auth_parse->qop;
600 dFree(realm->cnonce);
601 if (realm->qop != QOPNOTSET)
603 if (!a_Digest_compute_digest(realm, user, password)) {
604 MSG("Auth_do_auth_dialog_cb: a_Digest_compute_digest failed.\n");
605 dList_remove_fast(host->realms, realm);
606 Auth_realm_delete(realm);
607 }
608 } else {
609 MSG("Auth_do_auth_dialog_cb: Unknown auth type: %i\n",
610 realm->type);
611 }
612 dStrshred((char *)password);
613}
614
615/*
616 * Return: Nonzero if we got new credentials from the user and everything
617 * seems fine.
618 */
619static int Auth_do_auth_dialog(const AuthParse_t *auth_parse,
620 const DilloUrl *url)
621{
622 int ret;
623 char *title, *msg;
624 AuthDialogData_t *data;
625 const char *typestr = auth_parse->type == DIGEST ? "Digest" : "Basic";
626
627 _MSG("auth.c: Auth_do_auth_dialog: realm = '%s'\n", auth_parse->realm);
628
629 title = dStrconcat("Dillo: Password for ", auth_parse->realm, NULL);
630 msg = dStrconcat("The server at ", URL_HOST(url), " requires a username"
631 " and password for \"", auth_parse->realm, "\".\n\n"
632 "Authentication scheme: ", typestr, NULL);
633 data = dNew(AuthDialogData_t, 1);
634 data->auth_parse = auth_parse;
635 data->url = a_Url_dup(url);
636 ret = a_Dialog_user_password(title, msg, Auth_do_auth_dialog_cb, data);
637 dFree(title); dFree(msg);
638 a_Url_free((void *)data->url);
639 dFree(data);
640 return ret;
641}
642
646static int Auth_do_auth(char *challenge, enum AuthParseHTTPAuthType_t type,
647 const DilloUrl *url)
648{
649 AuthParse_t *auth_parse;
650 int reload = 0;
651
652 _MSG("auth.c: Auth_do_auth: challenge={%s}\n", challenge);
653 auth_parse = Auth_parse_new();
654 auth_parse->type = type;
655 Auth_parse_challenge(auth_parse, challenge);
656 if (auth_parse->ok)
657 reload =
658 Auth_do_auth_required(auth_parse, url) ?
659 Auth_do_auth_dialog(auth_parse, url)
660 : 1;
661 Auth_parse_free(auth_parse);
662
663 return reload;
664}
665
671int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url)
672{
673 int i;
674 char *chal;
675
676 for (i = 0; (chal = dList_nth_data(challenges, i)); ++i)
677 if (!dStrnAsciiCasecmp(chal, "Digest ", 7))
678 if (Auth_do_auth(chal, DIGEST, url))
679 return 1;
680 for (i = 0; (chal = dList_nth_data(challenges, i)); ++i)
681 if (!dStrnAsciiCasecmp(chal, "Basic ", 6))
682 if (Auth_do_auth(chal, BASIC, url))
683 return 1;
684
685 return 0;
686}
687
static AuthParse_t * Auth_parse_new(void)
Definition auth.c:64
static AuthRealm_t * Auth_realm_by_name(const AuthHost_t *host, const char *name)
Search all realms for the one with the given name.
Definition auth.c:373
static AuthHost_t * Auth_host_by_url(const DilloUrl *url)
Return the host that contains a URL, or NULL if there is no such host.
Definition auth.c:357
int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url)
Given authentication challenge(s), prepare authorization.
Definition auth.c:671
static int Auth_do_auth_required(const AuthParse_t *auth_parse, const DilloUrl *url)
Determine whether the user needs to authenticate.
Definition auth.c:494
static int Auth_is_token_char(char c)
Check valid chars.
Definition auth.c:105
void a_Auth_init(void)
Initialize the auth module.
Definition auth.c:59
int() Auth_parse_token_value_callback_t(AuthParse_t *auth_parse, char *token, const char *value)
Definition auth.c:151
static void Auth_parse_challenge_args(AuthParse_t *auth_parse, char **challenge, Auth_parse_token_value_callback_t *cb)
Definition auth.c:305
static void Auth_do_auth_dialog_cb(const char *user, const char *password, void *vData)
Definition auth.c:546
static int Auth_do_auth_dialog(const AuthParse_t *auth_parse, const DilloUrl *url)
Definition auth.c:619
static int Auth_parse_basic_challenge_cb(AuthParse_t *auth_parse, char *token, const char *value)
Definition auth.c:229
char * a_Auth_get_auth_str(const DilloUrl *url, const char *request_uri)
Return the authorization header for an HTTP query.
Definition auth.c:472
static void Auth_realm_add_path(AuthRealm_t *realm, const char *path)
Definition auth.c:443
static int Auth_parse_digest_challenge_cb(AuthParse_t *auth_parse, char *token, const char *value)
Definition auth.c:242
static int Auth_parse_token_value(AuthParse_t *auth_parse, char **auth, Auth_parse_token_value_callback_t *callback)
Parse authentication challenge into token-value pairs and feed them into the callback function.
Definition auth.c:164
static int Auth_realm_includes_path(const AuthRealm_t *realm, const char *path)
Definition auth.c:431
static int Auth_do_auth(char *challenge, enum AuthParseHTTPAuthType_t type, const DilloUrl *url)
Do authorization for an auth string.
Definition auth.c:646
static void Auth_parse_challenge(AuthParse_t *auth_parse, char *challenge)
Definition auth.c:339
static Dstr * Auth_unquote_value(char **valuep)
Unquote the content of a (potentially) quoted string.
Definition auth.c:125
static int Auth_path_is_inside(const char *path1, const char *path2, int len)
Definition auth.c:90
static AuthRealm_t * Auth_realm_by_path(const AuthHost_t *host, const char *path)
Search all realms for the one with the best-matching path.
Definition auth.c:389
static void Auth_realm_delete(AuthRealm_t *realm)
Definition auth.c:413
static Dlist * auth_hosts
Local data.
Definition auth.c:54
static void Auth_parse_free(AuthParse_t *auth_parse)
Definition auth.c:79
AuthParseDigestQOP_t
Definition auth.h:12
@ AUTH
Definition auth.h:12
@ QOPNOTSET
Definition auth.h:12
AuthParseHTTPAuthType_t
Definition auth.h:10
@ TYPENOTSET
Definition auth.h:10
@ BASIC
Definition auth.h:10
@ DIGEST
Definition auth.h:10
AuthParseDigestAlgorithm_t
Definition auth.h:11
@ MD5
Definition auth.h:11
@ ALGORITHMNOTSET
Definition auth.h:11
#define _MSG(...)
Definition bookmarks.c:45
#define MSG(...)
Definition bookmarks.c:46
unsigned char uchar_t
Definition d_size.h:17
int a_Dialog_user_password(const char *title, const char *msg, UserPasswordCB cb, void *vp)
Make a user/password dialog.
Definition dialog.cc:413
int a_Digest_compute_digest(AuthRealm_t *realm, const char *username, const char *passwd)
This portion only has to be calculated once.
Definition digest.c:54
char * a_Digest_create_cnonce(void)
Returns a pointer to a newly allocated string containing a cnonce.
Definition digest.c:41
char * a_Digest_authorization_hdr(AuthRealm_t *realm, const DilloUrl *url, const char *digest_uri)
Construct Digest Authorization header.
Definition digest.c:169
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
Definition dlib.c:102
void dFree(void *mem)
Definition dlib.c:68
int dStrAsciiCasecmp(const char *s1, const char *s2)
Definition dlib.c:203
char * dStrdup(const char *s)
Definition dlib.c:77
Dlist * dList_new(int size)
Create a new empty list.
Definition dlib.c:548
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
Definition dlib.c:215
int dList_length(Dlist *lp)
For completing the ADT.
Definition dlib.c:613
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
Definition dlib.c:662
void dList_remove_fast(Dlist *lp, const void *data)
Remove a data item without preserving order.
Definition dlib.c:623
void dStr_free(Dstr *ds, int all)
Free a dillo string.
Definition dlib.c:337
void dStrshred(char *s)
Clear the contents of the string.
Definition dlib.c:140
void dStr_append_c(Dstr *ds, int c)
Append one character.
Definition dlib.c:349
Dstr * dStr_new(const char *s)
Create a new string.
Definition dlib.c:325
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
Definition dlib.c:597
void dList_free(Dlist *lp)
Free a list (not its elements)
Definition dlib.c:564
#define dNew0(type, count)
Definition dlib.h:51
#define dNew(type, count)
Definition dlib.h:49
#define MSG_WARN(...)
Definition msg.h:26
char * a_Misc_encode_base64(const char *in)
Encodes string using base64 encoding.
Definition misc.c:425
#define d_isascii(c)
Definition misc.h:11
unsigned int nonce_count
Definition auth.h:23
enum AuthParseHTTPAuthType_t type
Definition auth.h:15
char * domain
Definition auth.h:27
char * username
Definition auth.h:21
char * cnonce
Definition auth.h:22
enum AuthParseDigestQOP_t qop
Definition auth.h:28
char * opaque
Definition auth.h:25
Dlist * paths
Definition auth.h:17
char * nonce
Definition auth.h:24
char * name
Definition auth.h:16
char * authorization
Definition auth.h:18
enum AuthParseDigestAlgorithm_t algorithm
Definition auth.h:26
Definition url.h:88
Definition dlib.h:131
Definition dlib.h:102
Dstr_char_t * str
Definition dlib.h:105
static void path()
Definition cookies.c:859
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
Definition url.c:208
DilloUrl * a_Url_dup(const DilloUrl *ori)
Duplicate a Url structure.
Definition url.c:477
#define URL_PATH(u)
Definition url.h:72
#define URL_STR(u)
Definition url.h:76
#define URL_SCHEME(u)
Definition url.h:70
#define URL_AUTHORITY(u)
Definition url.h:71
#define URL_HOST(u)
Definition url.h:75