Annotation of embedaddon/curl/lib/vauth/digest_sspi.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
        !             9:  * Copyright (C) 2015 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
        !            10:  *
        !            11:  * This software is licensed as described in the file COPYING, which
        !            12:  * you should have received as part of this distribution. The terms
        !            13:  * are also available at https://curl.haxx.se/docs/copyright.html.
        !            14:  *
        !            15:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            16:  * copies of the Software, and permit persons to whom the Software is
        !            17:  * furnished to do so, under the terms of the COPYING file.
        !            18:  *
        !            19:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            20:  * KIND, either express or implied.
        !            21:  *
        !            22:  * RFC2831 DIGEST-MD5 authentication
        !            23:  *
        !            24:  ***************************************************************************/
        !            25: 
        !            26: #include "curl_setup.h"
        !            27: 
        !            28: #if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH)
        !            29: 
        !            30: #include <curl/curl.h>
        !            31: 
        !            32: #include "vauth/vauth.h"
        !            33: #include "vauth/digest.h"
        !            34: #include "urldata.h"
        !            35: #include "curl_base64.h"
        !            36: #include "warnless.h"
        !            37: #include "curl_multibyte.h"
        !            38: #include "sendf.h"
        !            39: #include "strdup.h"
        !            40: #include "strcase.h"
        !            41: 
        !            42: /* The last #include files should be: */
        !            43: #include "curl_memory.h"
        !            44: #include "memdebug.h"
        !            45: 
        !            46: /*
        !            47: * Curl_auth_is_digest_supported()
        !            48: *
        !            49: * This is used to evaluate if DIGEST is supported.
        !            50: *
        !            51: * Parameters: None
        !            52: *
        !            53: * Returns TRUE if DIGEST is supported by Windows SSPI.
        !            54: */
        !            55: bool Curl_auth_is_digest_supported(void)
        !            56: {
        !            57:   PSecPkgInfo SecurityPackage;
        !            58:   SECURITY_STATUS status;
        !            59: 
        !            60:   /* Query the security package for Digest */
        !            61:   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
        !            62:                                               &SecurityPackage);
        !            63: 
        !            64:   /* Release the package buffer as it is not required anymore */
        !            65:   if(status == SEC_E_OK) {
        !            66:     s_pSecFn->FreeContextBuffer(SecurityPackage);
        !            67:   }
        !            68: 
        !            69:   return (status == SEC_E_OK ? TRUE : FALSE);
        !            70: }
        !            71: 
        !            72: /*
        !            73:  * Curl_auth_create_digest_md5_message()
        !            74:  *
        !            75:  * This is used to generate an already encoded DIGEST-MD5 response message
        !            76:  * ready for sending to the recipient.
        !            77:  *
        !            78:  * Parameters:
        !            79:  *
        !            80:  * data    [in]     - The session handle.
        !            81:  * chlg64  [in]     - The base64 encoded challenge message.
        !            82:  * userp   [in]     - The user name in the format User or Domain\User.
        !            83:  * passwdp [in]     - The user's password.
        !            84:  * service [in]     - The service type such as http, smtp, pop or imap.
        !            85:  * outptr  [in/out] - The address where a pointer to newly allocated memory
        !            86:  *                    holding the result will be stored upon completion.
        !            87:  * outlen  [out]    - The length of the output message.
        !            88:  *
        !            89:  * Returns CURLE_OK on success.
        !            90:  */
        !            91: CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
        !            92:                                              const char *chlg64,
        !            93:                                              const char *userp,
        !            94:                                              const char *passwdp,
        !            95:                                              const char *service,
        !            96:                                              char **outptr, size_t *outlen)
        !            97: {
        !            98:   CURLcode result = CURLE_OK;
        !            99:   TCHAR *spn = NULL;
        !           100:   size_t chlglen = 0;
        !           101:   size_t token_max = 0;
        !           102:   unsigned char *input_token = NULL;
        !           103:   unsigned char *output_token = NULL;
        !           104:   CredHandle credentials;
        !           105:   CtxtHandle context;
        !           106:   PSecPkgInfo SecurityPackage;
        !           107:   SEC_WINNT_AUTH_IDENTITY identity;
        !           108:   SEC_WINNT_AUTH_IDENTITY *p_identity;
        !           109:   SecBuffer chlg_buf;
        !           110:   SecBuffer resp_buf;
        !           111:   SecBufferDesc chlg_desc;
        !           112:   SecBufferDesc resp_desc;
        !           113:   SECURITY_STATUS status;
        !           114:   unsigned long attrs;
        !           115:   TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
        !           116: 
        !           117:   /* Decode the base-64 encoded challenge message */
        !           118:   if(strlen(chlg64) && *chlg64 != '=') {
        !           119:     result = Curl_base64_decode(chlg64, &input_token, &chlglen);
        !           120:     if(result)
        !           121:       return result;
        !           122:   }
        !           123: 
        !           124:   /* Ensure we have a valid challenge message */
        !           125:   if(!input_token) {
        !           126:     infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
        !           127: 
        !           128:     return CURLE_BAD_CONTENT_ENCODING;
        !           129:   }
        !           130: 
        !           131:   /* Query the security package for DigestSSP */
        !           132:   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
        !           133:                                               &SecurityPackage);
        !           134:   if(status != SEC_E_OK) {
        !           135:     free(input_token);
        !           136: 
        !           137:     return CURLE_NOT_BUILT_IN;
        !           138:   }
        !           139: 
        !           140:   token_max = SecurityPackage->cbMaxToken;
        !           141: 
        !           142:   /* Release the package buffer as it is not required anymore */
        !           143:   s_pSecFn->FreeContextBuffer(SecurityPackage);
        !           144: 
        !           145:   /* Allocate our response buffer */
        !           146:   output_token = malloc(token_max);
        !           147:   if(!output_token) {
        !           148:     free(input_token);
        !           149: 
        !           150:     return CURLE_OUT_OF_MEMORY;
        !           151:   }
        !           152: 
        !           153:   /* Generate our SPN */
        !           154:   spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
        !           155:   if(!spn) {
        !           156:     free(output_token);
        !           157:     free(input_token);
        !           158: 
        !           159:     return CURLE_OUT_OF_MEMORY;
        !           160:   }
        !           161: 
        !           162:   if(userp && *userp) {
        !           163:     /* Populate our identity structure */
        !           164:     result = Curl_create_sspi_identity(userp, passwdp, &identity);
        !           165:     if(result) {
        !           166:       free(spn);
        !           167:       free(output_token);
        !           168:       free(input_token);
        !           169: 
        !           170:       return result;
        !           171:     }
        !           172: 
        !           173:     /* Allow proper cleanup of the identity structure */
        !           174:     p_identity = &identity;
        !           175:   }
        !           176:   else
        !           177:     /* Use the current Windows user */
        !           178:     p_identity = NULL;
        !           179: 
        !           180:   /* Acquire our credentials handle */
        !           181:   status = s_pSecFn->AcquireCredentialsHandle(NULL,
        !           182:                                               (TCHAR *) TEXT(SP_NAME_DIGEST),
        !           183:                                               SECPKG_CRED_OUTBOUND, NULL,
        !           184:                                               p_identity, NULL, NULL,
        !           185:                                               &credentials, &expiry);
        !           186: 
        !           187:   if(status != SEC_E_OK) {
        !           188:     Curl_sspi_free_identity(p_identity);
        !           189:     free(spn);
        !           190:     free(output_token);
        !           191:     free(input_token);
        !           192: 
        !           193:     return CURLE_LOGIN_DENIED;
        !           194:   }
        !           195: 
        !           196:   /* Setup the challenge "input" security buffer */
        !           197:   chlg_desc.ulVersion = SECBUFFER_VERSION;
        !           198:   chlg_desc.cBuffers  = 1;
        !           199:   chlg_desc.pBuffers  = &chlg_buf;
        !           200:   chlg_buf.BufferType = SECBUFFER_TOKEN;
        !           201:   chlg_buf.pvBuffer   = input_token;
        !           202:   chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
        !           203: 
        !           204:   /* Setup the response "output" security buffer */
        !           205:   resp_desc.ulVersion = SECBUFFER_VERSION;
        !           206:   resp_desc.cBuffers  = 1;
        !           207:   resp_desc.pBuffers  = &resp_buf;
        !           208:   resp_buf.BufferType = SECBUFFER_TOKEN;
        !           209:   resp_buf.pvBuffer   = output_token;
        !           210:   resp_buf.cbBuffer   = curlx_uztoul(token_max);
        !           211: 
        !           212:   /* Generate our response message */
        !           213:   status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
        !           214:                                                0, 0, 0, &chlg_desc, 0,
        !           215:                                                &context, &resp_desc, &attrs,
        !           216:                                                &expiry);
        !           217: 
        !           218:   if(status == SEC_I_COMPLETE_NEEDED ||
        !           219:      status == SEC_I_COMPLETE_AND_CONTINUE)
        !           220:     s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
        !           221:   else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
        !           222:     s_pSecFn->FreeCredentialsHandle(&credentials);
        !           223:     Curl_sspi_free_identity(p_identity);
        !           224:     free(spn);
        !           225:     free(output_token);
        !           226:     free(input_token);
        !           227: 
        !           228:     if(status == SEC_E_INSUFFICIENT_MEMORY)
        !           229:       return CURLE_OUT_OF_MEMORY;
        !           230: 
        !           231:     return CURLE_AUTH_ERROR;
        !           232:   }
        !           233: 
        !           234:   /* Base64 encode the response */
        !           235:   result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
        !           236:                               outptr, outlen);
        !           237: 
        !           238:   /* Free our handles */
        !           239:   s_pSecFn->DeleteSecurityContext(&context);
        !           240:   s_pSecFn->FreeCredentialsHandle(&credentials);
        !           241: 
        !           242:   /* Free the identity structure */
        !           243:   Curl_sspi_free_identity(p_identity);
        !           244: 
        !           245:   /* Free the SPN */
        !           246:   free(spn);
        !           247: 
        !           248:   /* Free the response buffer */
        !           249:   free(output_token);
        !           250: 
        !           251:   /* Free the decoded challenge message */
        !           252:   free(input_token);
        !           253: 
        !           254:   return result;
        !           255: }
        !           256: 
        !           257: /*
        !           258:  * Curl_override_sspi_http_realm()
        !           259:  *
        !           260:  * This is used to populate the domain in a SSPI identity structure
        !           261:  * The realm is extracted from the challenge message and used as the
        !           262:  * domain if it is not already explicitly set.
        !           263:  *
        !           264:  * Parameters:
        !           265:  *
        !           266:  * chlg     [in]     - The challenge message.
        !           267:  * identity [in/out] - The identity structure.
        !           268:  *
        !           269:  * Returns CURLE_OK on success.
        !           270:  */
        !           271: CURLcode Curl_override_sspi_http_realm(const char *chlg,
        !           272:                                        SEC_WINNT_AUTH_IDENTITY *identity)
        !           273: {
        !           274:   xcharp_u domain, dup_domain;
        !           275: 
        !           276:   /* If domain is blank or unset, check challenge message for realm */
        !           277:   if(!identity->Domain || !identity->DomainLength) {
        !           278:     for(;;) {
        !           279:       char value[DIGEST_MAX_VALUE_LENGTH];
        !           280:       char content[DIGEST_MAX_CONTENT_LENGTH];
        !           281: 
        !           282:       /* Pass all additional spaces here */
        !           283:       while(*chlg && ISSPACE(*chlg))
        !           284:         chlg++;
        !           285: 
        !           286:       /* Extract a value=content pair */
        !           287:       if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
        !           288:         if(strcasecompare(value, "realm")) {
        !           289: 
        !           290:           /* Setup identity's domain and length */
        !           291:           domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content);
        !           292:           if(!domain.tchar_ptr)
        !           293:             return CURLE_OUT_OF_MEMORY;
        !           294: 
        !           295:           dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
        !           296:           if(!dup_domain.tchar_ptr) {
        !           297:             Curl_unicodefree(domain.tchar_ptr);
        !           298:             return CURLE_OUT_OF_MEMORY;
        !           299:           }
        !           300: 
        !           301:           free(identity->Domain);
        !           302:           identity->Domain = dup_domain.tbyte_ptr;
        !           303:           identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
        !           304:           dup_domain.tchar_ptr = NULL;
        !           305: 
        !           306:           Curl_unicodefree(domain.tchar_ptr);
        !           307:         }
        !           308:         else {
        !           309:           /* Unknown specifier, ignore it! */
        !           310:         }
        !           311:       }
        !           312:       else
        !           313:         break; /* We're done here */
        !           314: 
        !           315:       /* Pass all additional spaces here */
        !           316:       while(*chlg && ISSPACE(*chlg))
        !           317:         chlg++;
        !           318: 
        !           319:       /* Allow the list to be comma-separated */
        !           320:       if(',' == *chlg)
        !           321:         chlg++;
        !           322:     }
        !           323:   }
        !           324: 
        !           325:   return CURLE_OK;
        !           326: }
        !           327: 
        !           328: /*
        !           329:  * Curl_auth_decode_digest_http_message()
        !           330:  *
        !           331:  * This is used to decode a HTTP DIGEST challenge message into the separate
        !           332:  * attributes.
        !           333:  *
        !           334:  * Parameters:
        !           335:  *
        !           336:  * chlg    [in]     - The challenge message.
        !           337:  * digest  [in/out] - The digest data struct being used and modified.
        !           338:  *
        !           339:  * Returns CURLE_OK on success.
        !           340:  */
        !           341: CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
        !           342:                                               struct digestdata *digest)
        !           343: {
        !           344:   size_t chlglen = strlen(chlg);
        !           345: 
        !           346:   /* We had an input token before so if there's another one now that means we
        !           347:      provided bad credentials in the previous request or it's stale. */
        !           348:   if(digest->input_token) {
        !           349:     bool stale = false;
        !           350:     const char *p = chlg;
        !           351: 
        !           352:     /* Check for the 'stale' directive */
        !           353:     for(;;) {
        !           354:       char value[DIGEST_MAX_VALUE_LENGTH];
        !           355:       char content[DIGEST_MAX_CONTENT_LENGTH];
        !           356: 
        !           357:       while(*p && ISSPACE(*p))
        !           358:         p++;
        !           359: 
        !           360:       if(!Curl_auth_digest_get_pair(p, value, content, &p))
        !           361:         break;
        !           362: 
        !           363:       if(strcasecompare(value, "stale") &&
        !           364:          strcasecompare(content, "true")) {
        !           365:         stale = true;
        !           366:         break;
        !           367:       }
        !           368: 
        !           369:       while(*p && ISSPACE(*p))
        !           370:         p++;
        !           371: 
        !           372:       if(',' == *p)
        !           373:         p++;
        !           374:     }
        !           375: 
        !           376:     if(stale)
        !           377:       Curl_auth_digest_cleanup(digest);
        !           378:     else
        !           379:       return CURLE_LOGIN_DENIED;
        !           380:   }
        !           381: 
        !           382:   /* Store the challenge for use later */
        !           383:   digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1);
        !           384:   if(!digest->input_token)
        !           385:     return CURLE_OUT_OF_MEMORY;
        !           386: 
        !           387:   digest->input_token_len = chlglen;
        !           388: 
        !           389:   return CURLE_OK;
        !           390: }
        !           391: 
        !           392: /*
        !           393:  * Curl_auth_create_digest_http_message()
        !           394:  *
        !           395:  * This is used to generate a HTTP DIGEST response message ready for sending
        !           396:  * to the recipient.
        !           397:  *
        !           398:  * Parameters:
        !           399:  *
        !           400:  * data    [in]     - The session handle.
        !           401:  * userp   [in]     - The user name in the format User or Domain\User.
        !           402:  * passwdp [in]     - The user's password.
        !           403:  * request [in]     - The HTTP request.
        !           404:  * uripath [in]     - The path of the HTTP uri.
        !           405:  * digest  [in/out] - The digest data struct being used and modified.
        !           406:  * outptr  [in/out] - The address where a pointer to newly allocated memory
        !           407:  *                    holding the result will be stored upon completion.
        !           408:  * outlen  [out]    - The length of the output message.
        !           409:  *
        !           410:  * Returns CURLE_OK on success.
        !           411:  */
        !           412: CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
        !           413:                                               const char *userp,
        !           414:                                               const char *passwdp,
        !           415:                                               const unsigned char *request,
        !           416:                                               const unsigned char *uripath,
        !           417:                                               struct digestdata *digest,
        !           418:                                               char **outptr, size_t *outlen)
        !           419: {
        !           420:   size_t token_max;
        !           421:   char *resp;
        !           422:   BYTE *output_token;
        !           423:   size_t output_token_len = 0;
        !           424:   PSecPkgInfo SecurityPackage;
        !           425:   SecBuffer chlg_buf[5];
        !           426:   SecBufferDesc chlg_desc;
        !           427:   SECURITY_STATUS status;
        !           428: 
        !           429:   (void) data;
        !           430: 
        !           431:   /* Query the security package for DigestSSP */
        !           432:   status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
        !           433:                                               &SecurityPackage);
        !           434:   if(status != SEC_E_OK)
        !           435:     return CURLE_NOT_BUILT_IN;
        !           436: 
        !           437:   token_max = SecurityPackage->cbMaxToken;
        !           438: 
        !           439:   /* Release the package buffer as it is not required anymore */
        !           440:   s_pSecFn->FreeContextBuffer(SecurityPackage);
        !           441: 
        !           442:   /* Allocate the output buffer according to the max token size as indicated
        !           443:      by the security package */
        !           444:   output_token = malloc(token_max);
        !           445:   if(!output_token) {
        !           446:     return CURLE_OUT_OF_MEMORY;
        !           447:   }
        !           448: 
        !           449:   /* If the user/passwd that was used to make the identity for http_context
        !           450:      has changed then delete that context. */
        !           451:   if((userp && !digest->user) || (!userp && digest->user) ||
        !           452:      (passwdp && !digest->passwd) || (!passwdp && digest->passwd) ||
        !           453:      (userp && digest->user && strcmp(userp, digest->user)) ||
        !           454:      (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) {
        !           455:     if(digest->http_context) {
        !           456:       s_pSecFn->DeleteSecurityContext(digest->http_context);
        !           457:       Curl_safefree(digest->http_context);
        !           458:     }
        !           459:     Curl_safefree(digest->user);
        !           460:     Curl_safefree(digest->passwd);
        !           461:   }
        !           462: 
        !           463:   if(digest->http_context) {
        !           464:     chlg_desc.ulVersion    = SECBUFFER_VERSION;
        !           465:     chlg_desc.cBuffers     = 5;
        !           466:     chlg_desc.pBuffers     = chlg_buf;
        !           467:     chlg_buf[0].BufferType = SECBUFFER_TOKEN;
        !           468:     chlg_buf[0].pvBuffer   = NULL;
        !           469:     chlg_buf[0].cbBuffer   = 0;
        !           470:     chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
        !           471:     chlg_buf[1].pvBuffer   = (void *) request;
        !           472:     chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
        !           473:     chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
        !           474:     chlg_buf[2].pvBuffer   = (void *) uripath;
        !           475:     chlg_buf[2].cbBuffer   = curlx_uztoul(strlen((const char *) uripath));
        !           476:     chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS;
        !           477:     chlg_buf[3].pvBuffer   = NULL;
        !           478:     chlg_buf[3].cbBuffer   = 0;
        !           479:     chlg_buf[4].BufferType = SECBUFFER_PADDING;
        !           480:     chlg_buf[4].pvBuffer   = output_token;
        !           481:     chlg_buf[4].cbBuffer   = curlx_uztoul(token_max);
        !           482: 
        !           483:     status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0);
        !           484:     if(status == SEC_E_OK)
        !           485:       output_token_len = chlg_buf[4].cbBuffer;
        !           486:     else { /* delete the context so a new one can be made */
        !           487:       infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n",
        !           488:             (long)status);
        !           489:       s_pSecFn->DeleteSecurityContext(digest->http_context);
        !           490:       Curl_safefree(digest->http_context);
        !           491:     }
        !           492:   }
        !           493: 
        !           494:   if(!digest->http_context) {
        !           495:     CredHandle credentials;
        !           496:     SEC_WINNT_AUTH_IDENTITY identity;
        !           497:     SEC_WINNT_AUTH_IDENTITY *p_identity;
        !           498:     SecBuffer resp_buf;
        !           499:     SecBufferDesc resp_desc;
        !           500:     unsigned long attrs;
        !           501:     TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
        !           502:     TCHAR *spn;
        !           503: 
        !           504:     /* free the copy of user/passwd used to make the previous identity */
        !           505:     Curl_safefree(digest->user);
        !           506:     Curl_safefree(digest->passwd);
        !           507: 
        !           508:     if(userp && *userp) {
        !           509:       /* Populate our identity structure */
        !           510:       if(Curl_create_sspi_identity(userp, passwdp, &identity)) {
        !           511:         free(output_token);
        !           512:         return CURLE_OUT_OF_MEMORY;
        !           513:       }
        !           514: 
        !           515:       /* Populate our identity domain */
        !           516:       if(Curl_override_sspi_http_realm((const char *) digest->input_token,
        !           517:                                        &identity)) {
        !           518:         free(output_token);
        !           519:         return CURLE_OUT_OF_MEMORY;
        !           520:       }
        !           521: 
        !           522:       /* Allow proper cleanup of the identity structure */
        !           523:       p_identity = &identity;
        !           524:     }
        !           525:     else
        !           526:       /* Use the current Windows user */
        !           527:       p_identity = NULL;
        !           528: 
        !           529:     if(userp) {
        !           530:       digest->user = strdup(userp);
        !           531: 
        !           532:       if(!digest->user) {
        !           533:         free(output_token);
        !           534:         return CURLE_OUT_OF_MEMORY;
        !           535:       }
        !           536:     }
        !           537: 
        !           538:     if(passwdp) {
        !           539:       digest->passwd = strdup(passwdp);
        !           540: 
        !           541:       if(!digest->passwd) {
        !           542:         free(output_token);
        !           543:         Curl_safefree(digest->user);
        !           544:         return CURLE_OUT_OF_MEMORY;
        !           545:       }
        !           546:     }
        !           547: 
        !           548:     /* Acquire our credentials handle */
        !           549:     status = s_pSecFn->AcquireCredentialsHandle(NULL,
        !           550:                                                 (TCHAR *) TEXT(SP_NAME_DIGEST),
        !           551:                                                 SECPKG_CRED_OUTBOUND, NULL,
        !           552:                                                 p_identity, NULL, NULL,
        !           553:                                                 &credentials, &expiry);
        !           554:     if(status != SEC_E_OK) {
        !           555:       Curl_sspi_free_identity(p_identity);
        !           556:       free(output_token);
        !           557: 
        !           558:       return CURLE_LOGIN_DENIED;
        !           559:     }
        !           560: 
        !           561:     /* Setup the challenge "input" security buffer if present */
        !           562:     chlg_desc.ulVersion    = SECBUFFER_VERSION;
        !           563:     chlg_desc.cBuffers     = 3;
        !           564:     chlg_desc.pBuffers     = chlg_buf;
        !           565:     chlg_buf[0].BufferType = SECBUFFER_TOKEN;
        !           566:     chlg_buf[0].pvBuffer   = digest->input_token;
        !           567:     chlg_buf[0].cbBuffer   = curlx_uztoul(digest->input_token_len);
        !           568:     chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
        !           569:     chlg_buf[1].pvBuffer   = (void *) request;
        !           570:     chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
        !           571:     chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
        !           572:     chlg_buf[2].pvBuffer   = NULL;
        !           573:     chlg_buf[2].cbBuffer   = 0;
        !           574: 
        !           575:     /* Setup the response "output" security buffer */
        !           576:     resp_desc.ulVersion = SECBUFFER_VERSION;
        !           577:     resp_desc.cBuffers  = 1;
        !           578:     resp_desc.pBuffers  = &resp_buf;
        !           579:     resp_buf.BufferType = SECBUFFER_TOKEN;
        !           580:     resp_buf.pvBuffer   = output_token;
        !           581:     resp_buf.cbBuffer   = curlx_uztoul(token_max);
        !           582: 
        !           583:     spn = Curl_convert_UTF8_to_tchar((char *) uripath);
        !           584:     if(!spn) {
        !           585:       s_pSecFn->FreeCredentialsHandle(&credentials);
        !           586: 
        !           587:       Curl_sspi_free_identity(p_identity);
        !           588:       free(output_token);
        !           589: 
        !           590:       return CURLE_OUT_OF_MEMORY;
        !           591:     }
        !           592: 
        !           593:     /* Allocate our new context handle */
        !           594:     digest->http_context = calloc(1, sizeof(CtxtHandle));
        !           595:     if(!digest->http_context)
        !           596:       return CURLE_OUT_OF_MEMORY;
        !           597: 
        !           598:     /* Generate our response message */
        !           599:     status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
        !           600:                                                  spn,
        !           601:                                                  ISC_REQ_USE_HTTP_STYLE, 0, 0,
        !           602:                                                  &chlg_desc, 0,
        !           603:                                                  digest->http_context,
        !           604:                                                  &resp_desc, &attrs, &expiry);
        !           605:     Curl_unicodefree(spn);
        !           606: 
        !           607:     if(status == SEC_I_COMPLETE_NEEDED ||
        !           608:        status == SEC_I_COMPLETE_AND_CONTINUE)
        !           609:       s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
        !           610:     else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
        !           611:       s_pSecFn->FreeCredentialsHandle(&credentials);
        !           612: 
        !           613:       Curl_sspi_free_identity(p_identity);
        !           614:       free(output_token);
        !           615: 
        !           616:       Curl_safefree(digest->http_context);
        !           617: 
        !           618:       if(status == SEC_E_INSUFFICIENT_MEMORY)
        !           619:         return CURLE_OUT_OF_MEMORY;
        !           620: 
        !           621:       return CURLE_AUTH_ERROR;
        !           622:     }
        !           623: 
        !           624:     output_token_len = resp_buf.cbBuffer;
        !           625: 
        !           626:     s_pSecFn->FreeCredentialsHandle(&credentials);
        !           627:     Curl_sspi_free_identity(p_identity);
        !           628:   }
        !           629: 
        !           630:   resp = malloc(output_token_len + 1);
        !           631:   if(!resp) {
        !           632:     free(output_token);
        !           633: 
        !           634:     return CURLE_OUT_OF_MEMORY;
        !           635:   }
        !           636: 
        !           637:   /* Copy the generated response */
        !           638:   memcpy(resp, output_token, output_token_len);
        !           639:   resp[output_token_len] = 0;
        !           640: 
        !           641:   /* Return the response */
        !           642:   *outptr = resp;
        !           643:   *outlen = output_token_len;
        !           644: 
        !           645:   /* Free the response buffer */
        !           646:   free(output_token);
        !           647: 
        !           648:   return CURLE_OK;
        !           649: }
        !           650: 
        !           651: /*
        !           652:  * Curl_auth_digest_cleanup()
        !           653:  *
        !           654:  * This is used to clean up the digest specific data.
        !           655:  *
        !           656:  * Parameters:
        !           657:  *
        !           658:  * digest    [in/out] - The digest data struct being cleaned up.
        !           659:  *
        !           660:  */
        !           661: void Curl_auth_digest_cleanup(struct digestdata *digest)
        !           662: {
        !           663:   /* Free the input token */
        !           664:   Curl_safefree(digest->input_token);
        !           665: 
        !           666:   /* Reset any variables */
        !           667:   digest->input_token_len = 0;
        !           668: 
        !           669:   /* Delete security context */
        !           670:   if(digest->http_context) {
        !           671:     s_pSecFn->DeleteSecurityContext(digest->http_context);
        !           672:     Curl_safefree(digest->http_context);
        !           673:   }
        !           674: 
        !           675:   /* Free the copy of user/passwd used to make the identity for http_context */
        !           676:   Curl_safefree(digest->user);
        !           677:   Curl_safefree(digest->passwd);
        !           678: }
        !           679: 
        !           680: #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>