gen_auth.c (23764B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2022-2023 Evgeny Grin (Karlson2k) 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library. 17 If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * @file microhttpd/gen_auth.c 22 * @brief HTTP authorisation general functions 23 * @author Karlson2k (Evgeny Grin) 24 */ 25 26 #include "gen_auth.h" 27 #include "internal.h" 28 #include "connection.h" 29 #include "mhd_str.h" 30 #include "mhd_assert.h" 31 32 #ifdef BAUTH_SUPPORT 33 #include "basicauth.h" 34 #endif /* BAUTH_SUPPORT */ 35 #ifdef DAUTH_SUPPORT 36 #include "digestauth.h" 37 #endif /* DAUTH_SUPPORT */ 38 39 #if ! defined(BAUTH_SUPPORT) && ! defined(DAUTH_SUPPORT) 40 #error This file requires Basic or Digest authentication support 41 #endif 42 43 /** 44 * Type of authorisation 45 */ 46 enum MHD_AuthType 47 { 48 MHD_AUTHTYPE_NONE = 0,/**< No authorisation, unused */ 49 MHD_AUTHTYPE_BASIC, /**< Basic Authorisation, RFC 7617 */ 50 MHD_AUTHTYPE_DIGEST, /**< Digest Authorisation, RFC 7616 */ 51 MHD_AUTHTYPE_UNKNOWN, /**< Unknown/Unsupported authorisation type, unused */ 52 MHD_AUTHTYPE_INVALID /**< Wrong/broken authorisation header, unused */ 53 }; 54 55 /** 56 * Find required "Authorization" request header 57 * @param c the connection with request 58 * @param type the type of the authorisation: basic or digest 59 * @param[out] auth_value will be set to the remaining of header value after 60 * authorisation token (after "Basic " or "Digest ") 61 * @return true if requested header is found, 62 * false otherwise 63 */ 64 static bool 65 find_auth_rq_header_ (const struct MHD_Connection *c, enum MHD_AuthType type, 66 struct _MHD_str_w_len *auth_value) 67 { 68 const struct MHD_HTTP_Req_Header *h; 69 const char *token; 70 size_t token_len; 71 72 mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= c->state); 73 if (MHD_CONNECTION_HEADERS_PROCESSED > c->state) 74 return false; 75 76 #ifdef DAUTH_SUPPORT 77 if (MHD_AUTHTYPE_DIGEST == type) 78 { 79 token = _MHD_AUTH_DIGEST_BASE; 80 token_len = MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE); 81 } 82 else /* combined with the next line */ 83 #endif /* DAUTH_SUPPORT */ 84 #ifdef BAUTH_SUPPORT 85 if (MHD_AUTHTYPE_BASIC == type) 86 { 87 token = _MHD_AUTH_BASIC_BASE; 88 token_len = MHD_STATICSTR_LEN_ (_MHD_AUTH_BASIC_BASE); 89 } 90 else /* combined with the next line */ 91 #endif /* BAUTH_SUPPORT */ 92 { 93 mhd_assert (0); 94 return false; 95 } 96 97 for (h = c->rq.headers_received; NULL != h; h = h->next) 98 { 99 if (MHD_HEADER_KIND != h->kind) 100 continue; 101 if (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_AUTHORIZATION) != h->header_size) 102 continue; 103 if (token_len > h->value_size) 104 continue; 105 if (! MHD_str_equal_caseless_bin_n_ (MHD_HTTP_HEADER_AUTHORIZATION, 106 h->header, 107 MHD_STATICSTR_LEN_ ( \ 108 MHD_HTTP_HEADER_AUTHORIZATION))) 109 continue; 110 if (! MHD_str_equal_caseless_bin_n_ (h->value, token, token_len)) 111 continue; 112 /* Match only if token string is full header value or token is 113 * followed by space or tab 114 * Note: RFC 9110 (and RFC 7234) allows only space character, but 115 * tab is supported here as well for additional flexibility and uniformity 116 * as tabs are supported as separators between parameters. 117 */ 118 if ((token_len == h->value_size) || 119 (' ' == h->value[token_len]) || ('\t' == h->value[token_len])) 120 { 121 if (token_len != h->value_size) 122 { /* Skip whitespace */ 123 auth_value->str = h->value + token_len + 1; 124 auth_value->len = h->value_size - (token_len + 1); 125 } 126 else 127 { /* No whitespace to skip */ 128 auth_value->str = h->value + token_len; 129 auth_value->len = h->value_size - token_len; 130 } 131 return true; /* Found a match */ 132 } 133 } 134 return false; /* No matching header has been found */ 135 } 136 137 138 #ifdef BAUTH_SUPPORT 139 140 141 /** 142 * Parse request Authorization header parameters for Basic Authentication 143 * @param str the header string, everything after "Basic " substring 144 * @param str_len the length of @a str in characters 145 * @param[out] pbauth the pointer to the structure with Basic Authentication 146 * parameters 147 * @return true if parameters has been successfully parsed, 148 * false if format of the @a str is invalid 149 */ 150 static bool 151 parse_bauth_params (const char *str, 152 size_t str_len, 153 struct MHD_RqBAuth *pbauth) 154 { 155 size_t i; 156 157 i = 0; 158 159 /* Skip all whitespaces at start */ 160 while (i < str_len && (' ' == str[i] || '\t' == str[i])) 161 i++; 162 163 if (str_len > i) 164 { 165 size_t token68_start; 166 size_t token68_len; 167 168 /* 'i' points to the first non-whitespace char after scheme token */ 169 token68_start = i; 170 /* Find end of the token. Token cannot contain whitespace. */ 171 while (i < str_len && ' ' != str[i] && '\t' != str[i]) 172 { 173 if (0 == str[i]) 174 return false; /* Binary zero is not allowed */ 175 if ((',' == str[i]) || (';' == str[i])) 176 return false; /* Only single token68 is allowed */ 177 i++; 178 } 179 token68_len = i - token68_start; 180 mhd_assert (0 != token68_len); 181 182 /* Skip all whitespaces */ 183 while (i < str_len && (' ' == str[i] || '\t' == str[i])) 184 i++; 185 /* Check whether any garbage is present at the end of the string */ 186 if (str_len != i) 187 return false; 188 else 189 { 190 /* No more data in the string, only single token68. */ 191 pbauth->token68.str = str + token68_start; 192 pbauth->token68.len = token68_len; 193 } 194 } 195 return true; 196 } 197 198 199 /** 200 * Return request's Basic Authorisation parameters. 201 * 202 * Function return result of parsing of the request's "Authorization" header or 203 * returns cached parsing result if the header was already parsed for 204 * the current request. 205 * @param connection the connection to process 206 * @return the pointer to structure with Authentication parameters, 207 * NULL if no memory in memory pool, if called too early (before 208 * header has been received) or if no valid Basic Authorisation header 209 * found. 210 */ 211 const struct MHD_RqBAuth * 212 MHD_get_rq_bauth_params_ (struct MHD_Connection *connection) 213 { 214 struct _MHD_str_w_len h_auth_value; 215 struct MHD_RqBAuth *bauth; 216 217 mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= connection->state); 218 219 if (connection->rq.bauth_tried) 220 return connection->rq.bauth; 221 222 if (MHD_CONNECTION_HEADERS_PROCESSED > connection->state) 223 return NULL; 224 225 if (! find_auth_rq_header_ (connection, MHD_AUTHTYPE_BASIC, &h_auth_value)) 226 { 227 connection->rq.bauth_tried = true; 228 connection->rq.bauth = NULL; 229 return NULL; 230 } 231 232 bauth = 233 (struct MHD_RqBAuth *) 234 MHD_connection_alloc_memory_ (connection, sizeof (struct MHD_RqBAuth)); 235 236 if (NULL == bauth) 237 { 238 #ifdef HAVE_MESSAGES 239 MHD_DLOG (connection->daemon, 240 _ ("Not enough memory in the connection's pool to allocate " \ 241 "for Basic Authorization header parsing.\n")); 242 #endif /* HAVE_MESSAGES */ 243 return NULL; 244 } 245 246 memset (bauth, 0, sizeof(struct MHD_RqBAuth)); 247 if (parse_bauth_params (h_auth_value.str, h_auth_value.len, bauth)) 248 connection->rq.bauth = bauth; 249 else 250 { 251 #ifdef HAVE_MESSAGES 252 MHD_DLOG (connection->daemon, 253 _ ("The Basic Authorization client's header has " 254 "incorrect format.\n")); 255 #endif /* HAVE_MESSAGES */ 256 connection->rq.bauth = NULL; 257 /* Memory in the pool remains allocated until next request */ 258 } 259 connection->rq.bauth_tried = true; 260 return connection->rq.bauth; 261 } 262 263 264 #endif /* BAUTH_SUPPORT */ 265 266 #ifdef DAUTH_SUPPORT 267 268 269 /** 270 * Get client's Digest Authorization algorithm type. 271 * If no algorithm is specified by client, MD5 is assumed. 272 * @param params the Digest Authorization 'algorithm' parameter 273 * @return the algorithm type 274 */ 275 static enum MHD_DigestAuthAlgo3 276 get_rq_dauth_algo (const struct MHD_RqDAuthParam *const algo_param) 277 { 278 if (NULL == algo_param->value.str) 279 return MHD_DIGEST_AUTH_ALGO3_MD5; /* Assume MD5 by default */ 280 281 if (algo_param->quoted) 282 { 283 if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ 284 algo_param->value.len, \ 285 _MHD_MD5_TOKEN)) 286 return MHD_DIGEST_AUTH_ALGO3_MD5; 287 if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ 288 algo_param->value.len, \ 289 _MHD_SHA256_TOKEN)) 290 return MHD_DIGEST_AUTH_ALGO3_SHA256; 291 if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ 292 algo_param->value.len, \ 293 _MHD_MD5_TOKEN _MHD_SESS_TOKEN)) 294 return MHD_DIGEST_AUTH_ALGO3_SHA512_256; 295 if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ 296 algo_param->value.len, \ 297 _MHD_SHA512_256_TOKEN \ 298 _MHD_SESS_TOKEN)) 299 300 /* Algorithms below are not supported by MHD for authentication */ 301 302 return MHD_DIGEST_AUTH_ALGO3_MD5_SESSION; 303 if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ 304 algo_param->value.len, \ 305 _MHD_SHA256_TOKEN \ 306 _MHD_SESS_TOKEN)) 307 return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; 308 if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ 309 algo_param->value.len, \ 310 _MHD_SHA512_256_TOKEN)) 311 return MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION; 312 313 /* No known algorithm has been detected */ 314 return MHD_DIGEST_AUTH_ALGO3_INVALID; 315 } 316 /* The algorithm value is not quoted */ 317 if (MHD_str_equal_caseless_s_bin_n_ (_MHD_MD5_TOKEN, \ 318 algo_param->value.str, \ 319 algo_param->value.len)) 320 return MHD_DIGEST_AUTH_ALGO3_MD5; 321 if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA256_TOKEN, \ 322 algo_param->value.str, \ 323 algo_param->value.len)) 324 return MHD_DIGEST_AUTH_ALGO3_SHA256; 325 if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN, \ 326 algo_param->value.str, \ 327 algo_param->value.len)) 328 return MHD_DIGEST_AUTH_ALGO3_SHA512_256; 329 330 /* Algorithms below are not supported by MHD for authentication */ 331 332 if (MHD_str_equal_caseless_s_bin_n_ (_MHD_MD5_TOKEN _MHD_SESS_TOKEN, \ 333 algo_param->value.str, \ 334 algo_param->value.len)) 335 return MHD_DIGEST_AUTH_ALGO3_MD5_SESSION; 336 if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA256_TOKEN _MHD_SESS_TOKEN, \ 337 algo_param->value.str, \ 338 algo_param->value.len)) 339 return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; 340 if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN _MHD_SESS_TOKEN, \ 341 algo_param->value.str, \ 342 algo_param->value.len)) 343 return MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION; 344 345 /* No known algorithm has been detected */ 346 return MHD_DIGEST_AUTH_ALGO3_INVALID; 347 } 348 349 350 /** 351 * Get QOP ('quality of protection') type. 352 * @param qop_param the Digest Authorization 'QOP' parameter 353 * @return detected QOP ('quality of protection') type. 354 */ 355 static enum MHD_DigestAuthQOP 356 get_rq_dauth_qop (const struct MHD_RqDAuthParam *const qop_param) 357 { 358 if (NULL == qop_param->value.str) 359 return MHD_DIGEST_AUTH_QOP_NONE; 360 if (qop_param->quoted) 361 { 362 if (MHD_str_equal_caseless_quoted_s_bin_n (qop_param->value.str, \ 363 qop_param->value.len, \ 364 MHD_TOKEN_AUTH_)) 365 return MHD_DIGEST_AUTH_QOP_AUTH; 366 if (MHD_str_equal_caseless_quoted_s_bin_n (qop_param->value.str, \ 367 qop_param->value.len, \ 368 MHD_TOKEN_AUTH_INT_)) 369 return MHD_DIGEST_AUTH_QOP_AUTH_INT; 370 } 371 else 372 { 373 if (MHD_str_equal_caseless_s_bin_n_ (MHD_TOKEN_AUTH_, \ 374 qop_param->value.str, \ 375 qop_param->value.len)) 376 return MHD_DIGEST_AUTH_QOP_AUTH; 377 if (MHD_str_equal_caseless_s_bin_n_ (MHD_TOKEN_AUTH_INT_, \ 378 qop_param->value.str, \ 379 qop_param->value.len)) 380 return MHD_DIGEST_AUTH_QOP_AUTH_INT; 381 } 382 /* No know QOP has been detected */ 383 return MHD_DIGEST_AUTH_QOP_INVALID; 384 } 385 386 387 /** 388 * Parse request Authorization header parameters for Digest Authentication 389 * @param str the header string, everything after "Digest " substring 390 * @param str_len the length of @a str in characters 391 * @param[out] pdauth the pointer to the structure with Digest Authentication 392 * parameters 393 * @return true if parameters has been successfully parsed, 394 * false if format of the @a str is invalid 395 */ 396 static bool 397 parse_dauth_params (const char *str, 398 const size_t str_len, 399 struct MHD_RqDAuth *pdauth) 400 { 401 /* The tokens */ 402 static const struct _MHD_cstr_w_len nonce_tk = _MHD_S_STR_W_LEN ("nonce"); 403 static const struct _MHD_cstr_w_len opaque_tk = _MHD_S_STR_W_LEN ("opaque"); 404 static const struct _MHD_cstr_w_len algorithm_tk = 405 _MHD_S_STR_W_LEN ("algorithm"); 406 static const struct _MHD_cstr_w_len response_tk = 407 _MHD_S_STR_W_LEN ("response"); 408 static const struct _MHD_cstr_w_len username_tk = 409 _MHD_S_STR_W_LEN ("username"); 410 static const struct _MHD_cstr_w_len username_ext_tk = 411 _MHD_S_STR_W_LEN ("username*"); 412 static const struct _MHD_cstr_w_len realm_tk = _MHD_S_STR_W_LEN ("realm"); 413 static const struct _MHD_cstr_w_len uri_tk = _MHD_S_STR_W_LEN ("uri"); 414 static const struct _MHD_cstr_w_len qop_tk = _MHD_S_STR_W_LEN ("qop"); 415 static const struct _MHD_cstr_w_len cnonce_tk = _MHD_S_STR_W_LEN ("cnonce"); 416 static const struct _MHD_cstr_w_len nc_tk = _MHD_S_STR_W_LEN ("nc"); 417 static const struct _MHD_cstr_w_len userhash_tk = 418 _MHD_S_STR_W_LEN ("userhash"); 419 /* The locally processed parameters */ 420 struct MHD_RqDAuthParam userhash; 421 struct MHD_RqDAuthParam algorithm; 422 /* Indexes */ 423 size_t i; 424 size_t p; 425 /* The list of the tokens. 426 The order of the elements matches the next array. */ 427 static const struct _MHD_cstr_w_len *const tk_names[] = { 428 &nonce_tk, /* 0 */ 429 &opaque_tk, /* 1 */ 430 &algorithm_tk, /* 2 */ 431 &response_tk, /* 3 */ 432 &username_tk, /* 4 */ 433 &username_ext_tk, /* 5 */ 434 &realm_tk, /* 6 */ 435 &uri_tk, /* 7 */ 436 &qop_tk, /* 8 */ 437 &cnonce_tk, /* 9 */ 438 &nc_tk, /* 10 */ 439 &userhash_tk /* 11 */ 440 }; 441 /* The list of the parameters. 442 The order of the elements matches the previous array. */ 443 struct MHD_RqDAuthParam *params[sizeof(tk_names) / sizeof(tk_names[0])]; 444 445 params[0 ] = &(pdauth->nonce); /* 0 */ 446 params[1 ] = &(pdauth->opaque); /* 1 */ 447 params[2 ] = &algorithm; /* 2 */ 448 params[3 ] = &(pdauth->response); /* 3 */ 449 params[4 ] = &(pdauth->username); /* 4 */ 450 params[5 ] = &(pdauth->username_ext); /* 5 */ 451 params[6 ] = &(pdauth->realm); /* 6 */ 452 params[7 ] = &(pdauth->uri); /* 7 */ 453 params[8 ] = &(pdauth->qop_raw); /* 8 */ 454 params[9 ] = &(pdauth->cnonce); /* 9 */ 455 params[10] = &(pdauth->nc); /* 10 */ 456 params[11] = &userhash; /* 11 */ 457 458 mhd_assert ((sizeof(tk_names) / sizeof(tk_names[0])) == \ 459 (sizeof(params) / sizeof(params[0]))); 460 memset (&userhash, 0, sizeof(userhash)); 461 memset (&algorithm, 0, sizeof(algorithm)); 462 i = 0; 463 464 /* Skip all whitespaces at start */ 465 while (i < str_len && (' ' == str[i] || '\t' == str[i])) 466 i++; 467 468 while (str_len > i) 469 { 470 size_t left; 471 mhd_assert (' ' != str[i]); 472 mhd_assert ('\t' != str[i]); 473 474 left = str_len - i; 475 if ('=' == str[i]) 476 return false; /* The equal sign is not allowed as the first character */ 477 for (p = 0; p < (sizeof(tk_names) / sizeof(tk_names[0])); ++p) 478 { 479 const struct _MHD_cstr_w_len *const tk_name = tk_names[p]; 480 struct MHD_RqDAuthParam *const param = params[p]; 481 if ( (tk_name->len <= left) && 482 MHD_str_equal_caseless_bin_n_ (str + i, tk_name->str, 483 tk_name->len) && 484 ((tk_name->len == left) || 485 ('=' == str[i + tk_name->len]) || 486 (' ' == str[i + tk_name->len]) || 487 ('\t' == str[i + tk_name->len]) || 488 (',' == str[i + tk_name->len]) || 489 (';' == str[i + tk_name->len])) ) 490 { 491 size_t value_start; 492 size_t value_len; 493 bool quoted; /* Only mark as "quoted" if backslash-escape used */ 494 495 if (tk_name->len == left) 496 return false; /* No equal sign after parameter name, broken data */ 497 498 quoted = false; 499 i += tk_name->len; 500 /* Skip all whitespaces before '=' */ 501 while (str_len > i && (' ' == str[i] || '\t' == str[i])) 502 i++; 503 if ((i == str_len) || ('=' != str[i])) 504 return false; /* No equal sign, broken data */ 505 i++; 506 /* Skip all whitespaces after '=' */ 507 while (str_len > i && (' ' == str[i] || '\t' == str[i])) 508 i++; 509 if ((str_len > i) && ('"' == str[i])) 510 { /* Value is in quotation marks */ 511 i++; /* Advance after the opening quote */ 512 value_start = i; 513 while (str_len > i && '"' != str[i]) 514 { 515 if ('\\' == str[i]) 516 { 517 i++; 518 quoted = true; /* Have escaped chars */ 519 } 520 if (0 == str[i]) 521 return false; /* Binary zero in parameter value */ 522 i++; 523 } 524 if (str_len <= i) 525 return false; /* No closing quote */ 526 mhd_assert ('"' == str[i]); 527 value_len = i - value_start; 528 i++; /* Advance after the closing quote */ 529 } 530 else 531 { 532 value_start = i; 533 while (str_len > i && ',' != str[i] && 534 ' ' != str[i] && '\t' != str[i] && ';' != str[i]) 535 { 536 if (0 == str[i]) 537 return false; /* Binary zero in parameter value */ 538 i++; 539 } 540 if (';' == str[i]) 541 return false; /* Semicolon in parameter value */ 542 value_len = i - value_start; 543 } 544 /* Skip all whitespaces after parameter value */ 545 while (str_len > i && (' ' == str[i] || '\t' == str[i])) 546 i++; 547 if ((str_len > i) && (',' != str[i])) 548 return false; /* Garbage after parameter value */ 549 550 /* Have valid parameter name and value */ 551 mhd_assert (! quoted || 0 != value_len); 552 param->value.str = str + value_start; 553 param->value.len = value_len; 554 param->quoted = quoted; 555 556 break; /* Found matching parameter name */ 557 } 558 } 559 if (p == (sizeof(tk_names) / sizeof(tk_names[0]))) 560 { 561 /* No matching parameter name */ 562 while (str_len > i && ',' != str[i]) 563 { 564 if ((0 == str[i]) || (';' == str[i])) 565 return false; /* Not allowed characters */ 566 if ('"' == str[i]) 567 { /* Skip quoted part */ 568 i++; /* Advance after the opening quote */ 569 while (str_len > i && '"' != str[i]) 570 { 571 if (0 == str[i]) 572 return false; /* Binary zero is not allowed */ 573 if ('\\' == str[i]) 574 i++; /* Skip escaped char */ 575 i++; 576 } 577 if (str_len <= i) 578 return false; /* No closing quote */ 579 mhd_assert ('"' == str[i]); 580 } 581 i++; 582 } 583 } 584 mhd_assert (str_len == i || ',' == str[i]); 585 if (str_len > i) 586 i++; /* Advance after ',' */ 587 /* Skip all whitespaces before next parameter name */ 588 while (i < str_len && (' ' == str[i] || '\t' == str[i])) 589 i++; 590 } 591 592 /* Postprocess values */ 593 594 if (NULL != userhash.value.str) 595 { 596 if (userhash.quoted) 597 pdauth->userhash = 598 MHD_str_equal_caseless_quoted_s_bin_n (userhash.value.str, \ 599 userhash.value.len, \ 600 "true"); 601 else 602 pdauth->userhash = 603 MHD_str_equal_caseless_s_bin_n_ ("true", userhash.value.str, \ 604 userhash.value.len); 605 606 } 607 else 608 pdauth->userhash = false; 609 610 pdauth->algo3 = get_rq_dauth_algo (&algorithm); 611 pdauth->qop = get_rq_dauth_qop (&pdauth->qop_raw); 612 613 return true; 614 } 615 616 617 /** 618 * Return request's Digest Authorisation parameters. 619 * 620 * Function return result of parsing of the request's "Authorization" header or 621 * returns cached parsing result if the header was already parsed for 622 * the current request. 623 * @param connection the connection to process 624 * @return the pointer to structure with Authentication parameters, 625 * NULL if no memory in memory pool, if called too early (before 626 * header has been received) or if no valid Basic Authorisation header 627 * found. 628 */ 629 const struct MHD_RqDAuth * 630 MHD_get_rq_dauth_params_ (struct MHD_Connection *connection) 631 { 632 struct _MHD_str_w_len h_auth_value; 633 struct MHD_RqDAuth *dauth; 634 635 mhd_assert (MHD_CONNECTION_HEADERS_PROCESSED <= connection->state); 636 637 if (connection->rq.dauth_tried) 638 return connection->rq.dauth; 639 640 if (MHD_CONNECTION_HEADERS_PROCESSED > connection->state) 641 return NULL; 642 643 if (! find_auth_rq_header_ (connection, MHD_AUTHTYPE_DIGEST, &h_auth_value)) 644 { 645 connection->rq.dauth_tried = true; 646 connection->rq.dauth = NULL; 647 return NULL; 648 } 649 650 dauth = 651 (struct MHD_RqDAuth *) 652 MHD_connection_alloc_memory_ (connection, sizeof (struct MHD_RqDAuth)); 653 654 if (NULL == dauth) 655 { 656 #ifdef HAVE_MESSAGES 657 MHD_DLOG (connection->daemon, 658 _ ("Not enough memory in the connection's pool to allocate " \ 659 "for Digest Authorization header parsing.\n")); 660 #endif /* HAVE_MESSAGES */ 661 return NULL; 662 } 663 664 memset (dauth, 0, sizeof(struct MHD_RqDAuth)); 665 if (parse_dauth_params (h_auth_value.str, h_auth_value.len, dauth)) 666 connection->rq.dauth = dauth; 667 else 668 { 669 #ifdef HAVE_MESSAGES 670 MHD_DLOG (connection->daemon, 671 _ ("The Digest Authorization client's header has " 672 "incorrect format.\n")); 673 #endif /* HAVE_MESSAGES */ 674 connection->rq.dauth = NULL; 675 /* Memory in the pool remains allocated until next request */ 676 } 677 connection->rq.dauth_tried = true; 678 return connection->rq.dauth; 679 } 680 681 682 #endif /* DAUTH_SUPPORT */