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

1.1     ! misho       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:  * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
        !            22:  *
        !            23:  ***************************************************************************/
        !            24: 
        !            25: #include "curl_setup.h"
        !            26: 
        !            27: #if defined(HAVE_GSSAPI) && defined(USE_SPNEGO)
        !            28: 
        !            29: #include <curl/curl.h>
        !            30: 
        !            31: #include "vauth/vauth.h"
        !            32: #include "urldata.h"
        !            33: #include "curl_base64.h"
        !            34: #include "curl_gssapi.h"
        !            35: #include "warnless.h"
        !            36: #include "curl_multibyte.h"
        !            37: #include "sendf.h"
        !            38: 
        !            39: /* The last #include files should be: */
        !            40: #include "curl_memory.h"
        !            41: #include "memdebug.h"
        !            42: 
        !            43: /*
        !            44:  * Curl_auth_is_spnego_supported()
        !            45:  *
        !            46:  * This is used to evaluate if SPNEGO (Negotiate) is supported.
        !            47:  *
        !            48:  * Parameters: None
        !            49:  *
        !            50:  * Returns TRUE if Negotiate supported by the GSS-API library.
        !            51:  */
        !            52: bool Curl_auth_is_spnego_supported(void)
        !            53: {
        !            54:   return TRUE;
        !            55: }
        !            56: 
        !            57: /*
        !            58:  * Curl_auth_decode_spnego_message()
        !            59:  *
        !            60:  * This is used to decode an already encoded SPNEGO (Negotiate) challenge
        !            61:  * message.
        !            62:  *
        !            63:  * Parameters:
        !            64:  *
        !            65:  * data        [in]     - The session handle.
        !            66:  * userp       [in]     - The user name in the format User or Domain\User.
        !            67:  * passwdp     [in]     - The user's password.
        !            68:  * service     [in]     - The service type such as http, smtp, pop or imap.
        !            69:  * host        [in]     - The host name.
        !            70:  * chlg64      [in]     - The optional base64 encoded challenge message.
        !            71:  * nego        [in/out] - The Negotiate data struct being used and modified.
        !            72:  *
        !            73:  * Returns CURLE_OK on success.
        !            74:  */
        !            75: CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
        !            76:                                          const char *user,
        !            77:                                          const char *password,
        !            78:                                          const char *service,
        !            79:                                          const char *host,
        !            80:                                          const char *chlg64,
        !            81:                                          struct negotiatedata *nego)
        !            82: {
        !            83:   CURLcode result = CURLE_OK;
        !            84:   size_t chlglen = 0;
        !            85:   unsigned char *chlg = NULL;
        !            86:   OM_uint32 major_status;
        !            87:   OM_uint32 minor_status;
        !            88:   OM_uint32 unused_status;
        !            89:   gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
        !            90:   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
        !            91:   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
        !            92: 
        !            93:   (void) user;
        !            94:   (void) password;
        !            95: 
        !            96:   if(nego->context && nego->status == GSS_S_COMPLETE) {
        !            97:     /* We finished successfully our part of authentication, but server
        !            98:      * rejected it (since we're again here). Exit with an error since we
        !            99:      * can't invent anything better */
        !           100:     Curl_auth_cleanup_spnego(nego);
        !           101:     return CURLE_LOGIN_DENIED;
        !           102:   }
        !           103: 
        !           104:   if(!nego->spn) {
        !           105:     /* Generate our SPN */
        !           106:     char *spn = Curl_auth_build_spn(service, NULL, host);
        !           107:     if(!spn)
        !           108:       return CURLE_OUT_OF_MEMORY;
        !           109: 
        !           110:     /* Populate the SPN structure */
        !           111:     spn_token.value = spn;
        !           112:     spn_token.length = strlen(spn);
        !           113: 
        !           114:     /* Import the SPN */
        !           115:     major_status = gss_import_name(&minor_status, &spn_token,
        !           116:                                    GSS_C_NT_HOSTBASED_SERVICE,
        !           117:                                    &nego->spn);
        !           118:     if(GSS_ERROR(major_status)) {
        !           119:       Curl_gss_log_error(data, "gss_import_name() failed: ",
        !           120:                          major_status, minor_status);
        !           121: 
        !           122:       free(spn);
        !           123: 
        !           124:       return CURLE_AUTH_ERROR;
        !           125:     }
        !           126: 
        !           127:     free(spn);
        !           128:   }
        !           129: 
        !           130:   if(chlg64 && *chlg64) {
        !           131:     /* Decode the base-64 encoded challenge message */
        !           132:     if(*chlg64 != '=') {
        !           133:       result = Curl_base64_decode(chlg64, &chlg, &chlglen);
        !           134:       if(result)
        !           135:         return result;
        !           136:     }
        !           137: 
        !           138:     /* Ensure we have a valid challenge message */
        !           139:     if(!chlg) {
        !           140:       infof(data, "SPNEGO handshake failure (empty challenge message)\n");
        !           141: 
        !           142:       return CURLE_BAD_CONTENT_ENCODING;
        !           143:     }
        !           144: 
        !           145:     /* Setup the challenge "input" security buffer */
        !           146:     input_token.value = chlg;
        !           147:     input_token.length = chlglen;
        !           148:   }
        !           149: 
        !           150:   /* Generate our challenge-response message */
        !           151:   major_status = Curl_gss_init_sec_context(data,
        !           152:                                            &minor_status,
        !           153:                                            &nego->context,
        !           154:                                            nego->spn,
        !           155:                                            &Curl_spnego_mech_oid,
        !           156:                                            GSS_C_NO_CHANNEL_BINDINGS,
        !           157:                                            &input_token,
        !           158:                                            &output_token,
        !           159:                                            TRUE,
        !           160:                                            NULL);
        !           161: 
        !           162:   /* Free the decoded challenge as it is not required anymore */
        !           163:   Curl_safefree(input_token.value);
        !           164: 
        !           165:   nego->status = major_status;
        !           166:   if(GSS_ERROR(major_status)) {
        !           167:     if(output_token.value)
        !           168:       gss_release_buffer(&unused_status, &output_token);
        !           169: 
        !           170:     Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
        !           171:                        major_status, minor_status);
        !           172: 
        !           173:     return CURLE_AUTH_ERROR;
        !           174:   }
        !           175: 
        !           176:   if(!output_token.value || !output_token.length) {
        !           177:     if(output_token.value)
        !           178:       gss_release_buffer(&unused_status, &output_token);
        !           179: 
        !           180:     return CURLE_AUTH_ERROR;
        !           181:   }
        !           182: 
        !           183:   /* Free previous token */
        !           184:   if(nego->output_token.length && nego->output_token.value)
        !           185:     gss_release_buffer(&unused_status, &nego->output_token);
        !           186: 
        !           187:   nego->output_token = output_token;
        !           188: 
        !           189:   return CURLE_OK;
        !           190: }
        !           191: 
        !           192: /*
        !           193:  * Curl_auth_create_spnego_message()
        !           194:  *
        !           195:  * This is used to generate an already encoded SPNEGO (Negotiate) response
        !           196:  * message ready for sending to the recipient.
        !           197:  *
        !           198:  * Parameters:
        !           199:  *
        !           200:  * data        [in]     - The session handle.
        !           201:  * nego        [in/out] - The Negotiate data struct being used and modified.
        !           202:  * outptr      [in/out] - The address where a pointer to newly allocated memory
        !           203:  *                        holding the result will be stored upon completion.
        !           204:  * outlen      [out]    - The length of the output message.
        !           205:  *
        !           206:  * Returns CURLE_OK on success.
        !           207:  */
        !           208: CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
        !           209:                                          struct negotiatedata *nego,
        !           210:                                          char **outptr, size_t *outlen)
        !           211: {
        !           212:   CURLcode result;
        !           213:   OM_uint32 minor_status;
        !           214: 
        !           215:   /* Base64 encode the already generated response */
        !           216:   result = Curl_base64_encode(data,
        !           217:                               nego->output_token.value,
        !           218:                               nego->output_token.length,
        !           219:                               outptr, outlen);
        !           220: 
        !           221:   if(result) {
        !           222:     gss_release_buffer(&minor_status, &nego->output_token);
        !           223:     nego->output_token.value = NULL;
        !           224:     nego->output_token.length = 0;
        !           225: 
        !           226:     return result;
        !           227:   }
        !           228: 
        !           229:   if(!*outptr || !*outlen) {
        !           230:     gss_release_buffer(&minor_status, &nego->output_token);
        !           231:     nego->output_token.value = NULL;
        !           232:     nego->output_token.length = 0;
        !           233: 
        !           234:     return CURLE_REMOTE_ACCESS_DENIED;
        !           235:   }
        !           236: 
        !           237:   return CURLE_OK;
        !           238: }
        !           239: 
        !           240: /*
        !           241:  * Curl_auth_cleanup_spnego()
        !           242:  *
        !           243:  * This is used to clean up the SPNEGO (Negotiate) specific data.
        !           244:  *
        !           245:  * Parameters:
        !           246:  *
        !           247:  * nego     [in/out] - The Negotiate data struct being cleaned up.
        !           248:  *
        !           249:  */
        !           250: void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
        !           251: {
        !           252:   OM_uint32 minor_status;
        !           253: 
        !           254:   /* Free our security context */
        !           255:   if(nego->context != GSS_C_NO_CONTEXT) {
        !           256:     gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER);
        !           257:     nego->context = GSS_C_NO_CONTEXT;
        !           258:   }
        !           259: 
        !           260:   /* Free the output token */
        !           261:   if(nego->output_token.value) {
        !           262:     gss_release_buffer(&minor_status, &nego->output_token);
        !           263:     nego->output_token.value = NULL;
        !           264:     nego->output_token.length = 0;
        !           265: 
        !           266:   }
        !           267: 
        !           268:   /* Free the SPN */
        !           269:   if(nego->spn != GSS_C_NO_NAME) {
        !           270:     gss_release_name(&minor_status, &nego->spn);
        !           271:     nego->spn = GSS_C_NO_NAME;
        !           272:   }
        !           273: 
        !           274:   /* Reset any variables */
        !           275:   nego->status = 0;
        !           276:   nego->noauthpersist = FALSE;
        !           277:   nego->havenoauthpersist = FALSE;
        !           278:   nego->havenegdata = FALSE;
        !           279:   nego->havemultiplerequests = FALSE;
        !           280: }
        !           281: 
        !           282: #endif /* HAVE_GSSAPI && USE_SPNEGO */

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