00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "setup.h"
00024
00025 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
00026
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdarg.h>
00030 #include <stdlib.h>
00031 #include <ctype.h>
00032
00033 #include "urldata.h"
00034 #include "sendf.h"
00035 #include "strequal.h"
00036 #include "base64.h"
00037 #include "md5.h"
00038 #include "http_digest.h"
00039 #include "strtok.h"
00040 #include "url.h"
00041 #include "memory.h"
00042 #include "easyif.h"
00043
00044 #define _MPRINTF_REPLACE
00045 #include <curl/mprintf.h>
00046
00047
00048 #include "memdebug.h"
00049
00050
00051
00052
00053
00054
00055
00056
00057 CURLdigest Curl_input_digest(struct connectdata *conn,
00058 bool proxy,
00059 char *header)
00060
00061 {
00062 bool more = TRUE;
00063 char *token = NULL;
00064 char *tmp = NULL;
00065 bool foundAuth = FALSE;
00066 bool foundAuthInt = FALSE;
00067 struct SessionHandle *data=conn->data;
00068 bool before = FALSE;
00069 struct digestdata *d;
00070
00071 if(proxy) {
00072 d = &data->state.proxydigest;
00073 }
00074 else {
00075 d = &data->state.digest;
00076 }
00077
00078
00079 while(*header && ISSPACE(*header))
00080 header++;
00081
00082 if(checkprefix("Digest", header)) {
00083 header += strlen("Digest");
00084
00085
00086 if(d->nonce)
00087 before = TRUE;
00088
00089
00090 Curl_digest_cleanup_one(d);
00091
00092 while(more) {
00093 char value[32];
00094 char content[128];
00095 size_t totlen=0;
00096
00097 while(*header && ISSPACE(*header))
00098 header++;
00099
00100
00101 if((2 == sscanf(header, "%31[^=]=\"%127[^\"]\"",
00102 value, content)) ||
00103
00104
00105 (2 == sscanf(header, "%31[^=]=%127[^\r\n,]",
00106 value, content)) ) {
00107 if(strequal(value, "nonce")) {
00108 d->nonce = strdup(content);
00109 if(!d->nonce)
00110 return CURLDIGEST_NOMEM;
00111 }
00112 else if(strequal(value, "stale")) {
00113 if(strequal(content, "true")) {
00114 d->stale = TRUE;
00115 d->nc = 1;
00116 }
00117 }
00118 else if(strequal(value, "realm")) {
00119 d->realm = strdup(content);
00120 if(!d->realm)
00121 return CURLDIGEST_NOMEM;
00122 }
00123 else if(strequal(value, "opaque")) {
00124 d->opaque = strdup(content);
00125 if(!d->opaque)
00126 return CURLDIGEST_NOMEM;
00127 }
00128 else if(strequal(value, "qop")) {
00129 char *tok_buf;
00130
00131
00132 tmp = strdup(content);
00133 if(!tmp)
00134 return CURLDIGEST_NOMEM;
00135 token = strtok_r(tmp, ",", &tok_buf);
00136 while (token != NULL) {
00137 if (strequal(token, "auth")) {
00138 foundAuth = TRUE;
00139 }
00140 else if (strequal(token, "auth-int")) {
00141 foundAuthInt = TRUE;
00142 }
00143 token = strtok_r(NULL, ",", &tok_buf);
00144 }
00145 free(tmp);
00146
00147 if (foundAuth) {
00148 d->qop = strdup("auth");
00149 if(!d->qop)
00150 return CURLDIGEST_NOMEM;
00151 }
00152 else if (foundAuthInt) {
00153 d->qop = strdup("auth-int");
00154 if(!d->qop)
00155 return CURLDIGEST_NOMEM;
00156 }
00157 }
00158 else if(strequal(value, "algorithm")) {
00159 d->algorithm = strdup(content);
00160 if(!d->algorithm)
00161 return CURLDIGEST_NOMEM;
00162 if(strequal(content, "MD5-sess"))
00163 d->algo = CURLDIGESTALGO_MD5SESS;
00164 else if(strequal(content, "MD5"))
00165 d->algo = CURLDIGESTALGO_MD5;
00166 else
00167 return CURLDIGEST_BADALGO;
00168 }
00169 else {
00170
00171 }
00172 totlen = strlen(value)+strlen(content)+1;
00173
00174 if(header[strlen(value)+1] == '\"')
00175
00176
00177 totlen += 2;
00178 }
00179 else
00180 break;
00181
00182 header += totlen;
00183 if(',' == *header)
00184
00185 header++;
00186 }
00187
00188
00189
00190 if(before && !d->stale)
00191 return CURLDIGEST_BAD;
00192
00193
00194 if(!d->nonce)
00195 return CURLDIGEST_BAD;
00196 }
00197 else
00198
00199 return CURLDIGEST_NONE;
00200
00201 return CURLDIGEST_FINE;
00202 }
00203
00204
00205 static void md5_to_ascii(unsigned char *source,
00206 unsigned char *dest)
00207 {
00208 int i;
00209 for(i=0; i<16; i++)
00210 snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
00211 }
00212
00213 CURLcode Curl_output_digest(struct connectdata *conn,
00214 bool proxy,
00215 unsigned char *request,
00216 unsigned char *uripath)
00217 {
00218
00219
00220
00221 unsigned char md5buf[16];
00222 unsigned char request_digest[33];
00223 unsigned char *md5this;
00224 unsigned char *ha1;
00225 unsigned char ha2[33];
00226 char cnoncebuf[7];
00227 char *cnonce;
00228 char *tmp = NULL;
00229 struct timeval now;
00230
00231 char **allocuserpwd;
00232 char *userp;
00233 char *passwdp;
00234 struct auth *authp;
00235
00236 struct SessionHandle *data = conn->data;
00237 struct digestdata *d;
00238 #ifdef CURL_DOES_CONVERSIONS
00239 CURLcode rc;
00240
00241
00242
00243
00244 #define CURL_OUTPUT_DIGEST_CONV(a, b) \
00245 rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
00246 if (rc != CURLE_OK) { \
00247 free(b); \
00248 return rc; \
00249 }
00250 #else
00251 #define CURL_OUTPUT_DIGEST_CONV(a, b)
00252 #endif
00253
00254 if(proxy) {
00255 d = &data->state.proxydigest;
00256 allocuserpwd = &conn->allocptr.proxyuserpwd;
00257 userp = conn->proxyuser;
00258 passwdp = conn->proxypasswd;
00259 authp = &data->state.authproxy;
00260 }
00261 else {
00262 d = &data->state.digest;
00263 allocuserpwd = &conn->allocptr.userpwd;
00264 userp = conn->user;
00265 passwdp = conn->passwd;
00266 authp = &data->state.authhost;
00267 }
00268
00269
00270 if(!userp)
00271 userp=(char *)"";
00272
00273 if(!passwdp)
00274 passwdp=(char *)"";
00275
00276 if(!d->nonce) {
00277 authp->done = FALSE;
00278 return CURLE_OK;
00279 }
00280 authp->done = TRUE;
00281
00282 if(!d->nc)
00283 d->nc = 1;
00284
00285 if(!d->cnonce) {
00286
00287 now = Curl_tvnow();
00288 snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec);
00289 if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce))
00290 d->cnonce = cnonce;
00291 else
00292 return CURLE_OUT_OF_MEMORY;
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 md5this = (unsigned char *)
00307 aprintf("%s:%s:%s", userp, d->realm, passwdp);
00308 if(!md5this)
00309 return CURLE_OUT_OF_MEMORY;
00310
00311 CURL_OUTPUT_DIGEST_CONV(data, md5this);
00312 Curl_md5it(md5buf, md5this);
00313 free(md5this);
00314
00315 ha1 = (unsigned char *)malloc(33);
00316 if(!ha1)
00317 return CURLE_OUT_OF_MEMORY;
00318
00319 md5_to_ascii(md5buf, ha1);
00320
00321 if(d->algo == CURLDIGESTALGO_MD5SESS) {
00322
00323 tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
00324 if(!tmp)
00325 return CURLE_OUT_OF_MEMORY;
00326 CURL_OUTPUT_DIGEST_CONV(data, tmp);
00327 Curl_md5it(md5buf, (unsigned char *)tmp);
00328 free(tmp);
00329 md5_to_ascii(md5buf, ha1);
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
00346 if(!md5this) {
00347 free(ha1);
00348 return CURLE_OUT_OF_MEMORY;
00349 }
00350
00351 if (d->qop && strequal(d->qop, "auth-int")) {
00352
00353
00354
00355 }
00356 CURL_OUTPUT_DIGEST_CONV(data, md5this);
00357 Curl_md5it(md5buf, md5this);
00358 free(md5this);
00359 md5_to_ascii(md5buf, ha2);
00360
00361 if (d->qop) {
00362 md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
00363 ha1,
00364 d->nonce,
00365 d->nc,
00366 d->cnonce,
00367 d->qop,
00368 ha2);
00369 }
00370 else {
00371 md5this = (unsigned char *)aprintf("%s:%s:%s",
00372 ha1,
00373 d->nonce,
00374 ha2);
00375 }
00376 free(ha1);
00377 if(!md5this)
00378 return CURLE_OUT_OF_MEMORY;
00379
00380 CURL_OUTPUT_DIGEST_CONV(data, md5this);
00381 Curl_md5it(md5buf, md5this);
00382 free(md5this);
00383 md5_to_ascii(md5buf, request_digest);
00384
00385
00386
00387
00388
00389
00390
00391 Curl_safefree(*allocuserpwd);
00392
00393 if (d->qop) {
00394 *allocuserpwd =
00395 aprintf( "%sAuthorization: Digest "
00396 "username=\"%s\", "
00397 "realm=\"%s\", "
00398 "nonce=\"%s\", "
00399 "uri=\"%s\", "
00400 "cnonce=\"%s\", "
00401 "nc=%08x, "
00402 "qop=\"%s\", "
00403 "response=\"%s\"",
00404 proxy?"Proxy-":"",
00405 userp,
00406 d->realm,
00407 d->nonce,
00408 uripath,
00409 d->cnonce,
00410 d->nc,
00411 d->qop,
00412 request_digest);
00413
00414 if(strequal(d->qop, "auth"))
00415 d->nc++;
00416
00417
00418 }
00419 else {
00420 *allocuserpwd =
00421 aprintf( "%sAuthorization: Digest "
00422 "username=\"%s\", "
00423 "realm=\"%s\", "
00424 "nonce=\"%s\", "
00425 "uri=\"%s\", "
00426 "response=\"%s\"",
00427 proxy?"Proxy-":"",
00428 userp,
00429 d->realm,
00430 d->nonce,
00431 uripath,
00432 request_digest);
00433 }
00434 if(!*allocuserpwd)
00435 return CURLE_OUT_OF_MEMORY;
00436
00437
00438 if(d->opaque) {
00439
00440 tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque);
00441 if(!tmp)
00442 return CURLE_OUT_OF_MEMORY;
00443 free(*allocuserpwd);
00444 *allocuserpwd = tmp;
00445 }
00446
00447 if(d->algorithm) {
00448
00449 tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm);
00450 if(!tmp)
00451 return CURLE_OUT_OF_MEMORY;
00452 free(*allocuserpwd);
00453 *allocuserpwd = tmp;
00454 }
00455
00456
00457 tmp = (char*) realloc(*allocuserpwd, strlen(*allocuserpwd) + 3 + 1);
00458 if(!tmp)
00459 return CURLE_OUT_OF_MEMORY;
00460 strcat(tmp, "\r\n");
00461 *allocuserpwd = tmp;
00462
00463 return CURLE_OK;
00464 }
00465
00466 void Curl_digest_cleanup_one(struct digestdata *d)
00467 {
00468 if(d->nonce)
00469 free(d->nonce);
00470 d->nonce = NULL;
00471
00472 if(d->cnonce)
00473 free(d->cnonce);
00474 d->cnonce = NULL;
00475
00476 if(d->realm)
00477 free(d->realm);
00478 d->realm = NULL;
00479
00480 if(d->opaque)
00481 free(d->opaque);
00482 d->opaque = NULL;
00483
00484 if(d->qop)
00485 free(d->qop);
00486 d->qop = NULL;
00487
00488 if(d->algorithm)
00489 free(d->algorithm);
00490 d->algorithm = NULL;
00491
00492 d->nc = 0;
00493 d->algo = CURLDIGESTALGO_MD5;
00494 d->stale = FALSE;
00495 }
00496
00497
00498 void Curl_digest_cleanup(struct SessionHandle *data)
00499 {
00500 Curl_digest_cleanup_one(&data->state.digest);
00501 Curl_digest_cleanup_one(&data->state.proxydigest);
00502 }
00503
00504 #endif