Annotation of embedaddon/curl/lib/vauth/spnego_gssapi.c, revision 1.1.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>