| 1 | /*************************************************************************** | 
|---|
| 2 | *                                  _   _ ____  _ | 
|---|
| 3 | *  Project                     ___| | | |  _ \| | | 
|---|
| 4 | *                             / __| | | | |_) | | | 
|---|
| 5 | *                            | (__| |_| |  _ <| |___ | 
|---|
| 6 | *                             \___|\___/|_| \_\_____| | 
|---|
| 7 | * | 
|---|
| 8 | * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al. | 
|---|
| 9 | * | 
|---|
| 10 | * This software is licensed as described in the file COPYING, which | 
|---|
| 11 | * you should have received as part of this distribution. The terms | 
|---|
| 12 | * are also available at https://curl.haxx.se/docs/copyright.html. | 
|---|
| 13 | * | 
|---|
| 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell | 
|---|
| 15 | * copies of the Software, and permit persons to whom the Software is | 
|---|
| 16 | * furnished to do so, under the terms of the COPYING file. | 
|---|
| 17 | * | 
|---|
| 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | 
|---|
| 19 | * KIND, either express or implied. | 
|---|
| 20 | * | 
|---|
| 21 | ***************************************************************************/ | 
|---|
| 22 |  | 
|---|
| 23 | #include "curl_setup.h" | 
|---|
| 24 |  | 
|---|
| 25 | #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) | 
|---|
| 26 |  | 
|---|
| 27 | #include "urldata.h" | 
|---|
| 28 | #include "strcase.h" | 
|---|
| 29 | #include "vauth/vauth.h" | 
|---|
| 30 | #include "http_digest.h" | 
|---|
| 31 |  | 
|---|
| 32 | /* The last 3 #include files should be in this order */ | 
|---|
| 33 | #include "curl_printf.h" | 
|---|
| 34 | #include "curl_memory.h" | 
|---|
| 35 | #include "memdebug.h" | 
|---|
| 36 |  | 
|---|
| 37 | /* Test example headers: | 
|---|
| 38 |  | 
|---|
| 39 | WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" | 
|---|
| 40 | Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598" | 
|---|
| 41 |  | 
|---|
| 42 | */ | 
|---|
| 43 |  | 
|---|
| 44 | CURLcode Curl_input_digest(struct connectdata *conn, | 
|---|
| 45 | bool proxy, | 
|---|
| 46 | const char *) /* rest of the *-authenticate: | 
|---|
| 47 | header */ | 
|---|
| 48 | { | 
|---|
| 49 | struct Curl_easy *data = conn->data; | 
|---|
| 50 |  | 
|---|
| 51 | /* Point to the correct struct with this */ | 
|---|
| 52 | struct digestdata *digest; | 
|---|
| 53 |  | 
|---|
| 54 | if(proxy) { | 
|---|
| 55 | digest = &data->state.proxydigest; | 
|---|
| 56 | } | 
|---|
| 57 | else { | 
|---|
| 58 | digest = &data->state.digest; | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | if(!checkprefix( "Digest", header)) | 
|---|
| 62 | return CURLE_BAD_CONTENT_ENCODING; | 
|---|
| 63 |  | 
|---|
| 64 | header += strlen( "Digest"); | 
|---|
| 65 | while(*header && ISSPACE(*header)) | 
|---|
| 66 | header++; | 
|---|
| 67 |  | 
|---|
| 68 | return Curl_auth_decode_digest_http_message(header, digest); | 
|---|
| 69 | } | 
|---|
| 70 |  | 
|---|
| 71 | CURLcode Curl_output_digest(struct connectdata *conn, | 
|---|
| 72 | bool proxy, | 
|---|
| 73 | const unsigned char *request, | 
|---|
| 74 | const unsigned char *uripath) | 
|---|
| 75 | { | 
|---|
| 76 | CURLcode result; | 
|---|
| 77 | struct Curl_easy *data = conn->data; | 
|---|
| 78 | unsigned char *path = NULL; | 
|---|
| 79 | char *tmp = NULL; | 
|---|
| 80 | char *response; | 
|---|
| 81 | size_t len; | 
|---|
| 82 | bool have_chlg; | 
|---|
| 83 |  | 
|---|
| 84 | /* Point to the address of the pointer that holds the string to send to the | 
|---|
| 85 | server, which is for a plain host or for a HTTP proxy */ | 
|---|
| 86 | char **allocuserpwd; | 
|---|
| 87 |  | 
|---|
| 88 | /* Point to the name and password for this */ | 
|---|
| 89 | const char *userp; | 
|---|
| 90 | const char *passwdp; | 
|---|
| 91 |  | 
|---|
| 92 | /* Point to the correct struct with this */ | 
|---|
| 93 | struct digestdata *digest; | 
|---|
| 94 | struct auth *authp; | 
|---|
| 95 |  | 
|---|
| 96 | if(proxy) { | 
|---|
| 97 | digest = &data->state.proxydigest; | 
|---|
| 98 | allocuserpwd = &conn->allocptr.proxyuserpwd; | 
|---|
| 99 | userp = conn->http_proxy.user; | 
|---|
| 100 | passwdp = conn->http_proxy.passwd; | 
|---|
| 101 | authp = &data->state.authproxy; | 
|---|
| 102 | } | 
|---|
| 103 | else { | 
|---|
| 104 | digest = &data->state.digest; | 
|---|
| 105 | allocuserpwd = &conn->allocptr.userpwd; | 
|---|
| 106 | userp = conn->user; | 
|---|
| 107 | passwdp = conn->passwd; | 
|---|
| 108 | authp = &data->state.authhost; | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | Curl_safefree(*allocuserpwd); | 
|---|
| 112 |  | 
|---|
| 113 | /* not set means empty */ | 
|---|
| 114 | if(!userp) | 
|---|
| 115 | userp = ""; | 
|---|
| 116 |  | 
|---|
| 117 | if(!passwdp) | 
|---|
| 118 | passwdp = ""; | 
|---|
| 119 |  | 
|---|
| 120 | #if defined(USE_WINDOWS_SSPI) | 
|---|
| 121 | have_chlg = digest->input_token ? TRUE : FALSE; | 
|---|
| 122 | #else | 
|---|
| 123 | have_chlg = digest->nonce ? TRUE : FALSE; | 
|---|
| 124 | #endif | 
|---|
| 125 |  | 
|---|
| 126 | if(!have_chlg) { | 
|---|
| 127 | authp->done = FALSE; | 
|---|
| 128 | return CURLE_OK; | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | /* So IE browsers < v7 cut off the URI part at the query part when they | 
|---|
| 132 | evaluate the MD5 and some (IIS?) servers work with them so we may need to | 
|---|
| 133 | do the Digest IE-style. Note that the different ways cause different MD5 | 
|---|
| 134 | sums to get sent. | 
|---|
| 135 |  | 
|---|
| 136 | Apache servers can be set to do the Digest IE-style automatically using | 
|---|
| 137 | the BrowserMatch feature: | 
|---|
| 138 | https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie | 
|---|
| 139 |  | 
|---|
| 140 | Further details on Digest implementation differences: | 
|---|
| 141 | http://www.fngtps.com/2006/09/http-authentication | 
|---|
| 142 | */ | 
|---|
| 143 |  | 
|---|
| 144 | if(authp->iestyle) { | 
|---|
| 145 | tmp = strchr((char *)uripath, '?'); | 
|---|
| 146 | if(tmp) { | 
|---|
| 147 | size_t urilen = tmp - (char *)uripath; | 
|---|
| 148 | path = (unsigned char *) aprintf( "%.*s", urilen, uripath); | 
|---|
| 149 | } | 
|---|
| 150 | } | 
|---|
| 151 | if(!tmp) | 
|---|
| 152 | path = (unsigned char *) strdup((char *) uripath); | 
|---|
| 153 |  | 
|---|
| 154 | if(!path) | 
|---|
| 155 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 156 |  | 
|---|
| 157 | result = Curl_auth_create_digest_http_message(data, userp, passwdp, request, | 
|---|
| 158 | path, digest, &response, &len); | 
|---|
| 159 | free(path); | 
|---|
| 160 | if(result) | 
|---|
| 161 | return result; | 
|---|
| 162 |  | 
|---|
| 163 | *allocuserpwd = aprintf( "%sAuthorization: Digest %s\r\n", | 
|---|
| 164 | proxy ? "Proxy-": "", | 
|---|
| 165 | response); | 
|---|
| 166 | free(response); | 
|---|
| 167 | if(!*allocuserpwd) | 
|---|
| 168 | return CURLE_OUT_OF_MEMORY; | 
|---|
| 169 |  | 
|---|
| 170 | authp->done = TRUE; | 
|---|
| 171 |  | 
|---|
| 172 | return CURLE_OK; | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | void Curl_http_auth_cleanup_digest(struct Curl_easy *data) | 
|---|
| 176 | { | 
|---|
| 177 | Curl_auth_digest_cleanup(&data->state.digest); | 
|---|
| 178 | Curl_auth_digest_cleanup(&data->state.proxydigest); | 
|---|
| 179 | } | 
|---|
| 180 |  | 
|---|
| 181 | #endif | 
|---|
| 182 |  | 
|---|