Annotation of embedaddon/curl/lib/http_negotiate.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:  ***************************************************************************/
                     22: 
                     23: #include "curl_setup.h"
                     24: 
                     25: #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
                     26: 
                     27: #include "urldata.h"
                     28: #include "sendf.h"
                     29: #include "http_negotiate.h"
                     30: #include "vauth/vauth.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: CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
                     38:                               const char *header)
                     39: {
                     40:   CURLcode result;
                     41:   struct Curl_easy *data = conn->data;
                     42:   size_t len;
                     43: 
                     44:   /* Point to the username, password, service and host */
                     45:   const char *userp;
                     46:   const char *passwdp;
                     47:   const char *service;
                     48:   const char *host;
                     49: 
                     50:   /* Point to the correct struct with this */
                     51:   struct negotiatedata *neg_ctx;
                     52:   curlnegotiate state;
                     53: 
                     54:   if(proxy) {
                     55:     userp = conn->http_proxy.user;
                     56:     passwdp = conn->http_proxy.passwd;
                     57:     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
                     58:               data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
                     59:     host = conn->http_proxy.host.name;
                     60:     neg_ctx = &conn->proxyneg;
                     61:     state = conn->proxy_negotiate_state;
                     62:   }
                     63:   else {
                     64:     userp = conn->user;
                     65:     passwdp = conn->passwd;
                     66:     service = data->set.str[STRING_SERVICE_NAME] ?
                     67:               data->set.str[STRING_SERVICE_NAME] : "HTTP";
                     68:     host = conn->host.name;
                     69:     neg_ctx = &conn->negotiate;
                     70:     state = conn->http_negotiate_state;
                     71:   }
                     72: 
                     73:   /* Not set means empty */
                     74:   if(!userp)
                     75:     userp = "";
                     76: 
                     77:   if(!passwdp)
                     78:     passwdp = "";
                     79: 
                     80:   /* Obtain the input token, if any */
                     81:   header += strlen("Negotiate");
                     82:   while(*header && ISSPACE(*header))
                     83:     header++;
                     84: 
                     85:   len = strlen(header);
                     86:   neg_ctx->havenegdata = len != 0;
                     87:   if(!len) {
                     88:     if(state == GSS_AUTHSUCC) {
                     89:       infof(conn->data, "Negotiate auth restarted\n");
                     90:       Curl_http_auth_cleanup_negotiate(conn);
                     91:     }
                     92:     else if(state != GSS_AUTHNONE) {
                     93:       /* The server rejected our authentication and hasn't supplied any more
                     94:       negotiation mechanisms */
                     95:       Curl_http_auth_cleanup_negotiate(conn);
                     96:       return CURLE_LOGIN_DENIED;
                     97:     }
                     98:   }
                     99: 
                    100:   /* Supports SSL channel binding for Windows ISS extended protection */
                    101: #if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
                    102:   neg_ctx->sslContext = conn->sslContext;
                    103: #endif
                    104: 
                    105:   /* Initialize the security context and decode our challenge */
                    106:   result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
                    107:                                            host, header, neg_ctx);
                    108: 
                    109:   if(result)
                    110:     Curl_http_auth_cleanup_negotiate(conn);
                    111: 
                    112:   return result;
                    113: }
                    114: 
                    115: CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
                    116: {
                    117:   struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
                    118:     &conn->negotiate;
                    119:   struct auth *authp = proxy ? &conn->data->state.authproxy :
                    120:     &conn->data->state.authhost;
                    121:   curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
                    122:                                  &conn->http_negotiate_state;
                    123:   char *base64 = NULL;
                    124:   size_t len = 0;
                    125:   char *userp;
                    126:   CURLcode result;
                    127: 
                    128:   authp->done = FALSE;
                    129: 
                    130:   if(*state == GSS_AUTHRECV) {
                    131:     if(neg_ctx->havenegdata) {
                    132:       neg_ctx->havemultiplerequests = TRUE;
                    133:     }
                    134:   }
                    135:   else if(*state == GSS_AUTHSUCC) {
                    136:     if(!neg_ctx->havenoauthpersist) {
                    137:       neg_ctx->noauthpersist = !neg_ctx->havemultiplerequests;
                    138:     }
                    139:   }
                    140: 
                    141:   if(neg_ctx->noauthpersist ||
                    142:     (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
                    143: 
                    144:     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
                    145:       infof(conn->data, "Curl_output_negotiate, "
                    146:        "no persistent authentication: cleanup existing context");
                    147:       Curl_http_auth_cleanup_negotiate(conn);
                    148:     }
                    149:     if(!neg_ctx->context) {
                    150:       result = Curl_input_negotiate(conn, proxy, "Negotiate");
                    151:       if(result == CURLE_AUTH_ERROR) {
                    152:         /* negotiate auth failed, let's continue unauthenticated to stay
                    153:          * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
                    154:         authp->done = TRUE;
                    155:         return CURLE_OK;
                    156:       }
                    157:       else if(result)
                    158:         return result;
                    159:     }
                    160: 
                    161:     result = Curl_auth_create_spnego_message(conn->data,
                    162:       neg_ctx, &base64, &len);
                    163:     if(result)
                    164:       return result;
                    165: 
                    166:     userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
                    167:       base64);
                    168: 
                    169:     if(proxy) {
                    170:       Curl_safefree(conn->allocptr.proxyuserpwd);
                    171:       conn->allocptr.proxyuserpwd = userp;
                    172:     }
                    173:     else {
                    174:       Curl_safefree(conn->allocptr.userpwd);
                    175:       conn->allocptr.userpwd = userp;
                    176:     }
                    177: 
                    178:     free(base64);
                    179: 
                    180:     if(userp == NULL) {
                    181:       return CURLE_OUT_OF_MEMORY;
                    182:     }
                    183: 
                    184:     *state = GSS_AUTHSENT;
                    185:   #ifdef HAVE_GSSAPI
                    186:     if(neg_ctx->status == GSS_S_COMPLETE ||
                    187:        neg_ctx->status == GSS_S_CONTINUE_NEEDED) {
                    188:       *state = GSS_AUTHDONE;
                    189:     }
                    190:   #else
                    191:   #ifdef USE_WINDOWS_SSPI
                    192:     if(neg_ctx->status == SEC_E_OK ||
                    193:        neg_ctx->status == SEC_I_CONTINUE_NEEDED) {
                    194:       *state = GSS_AUTHDONE;
                    195:     }
                    196:   #endif
                    197:   #endif
                    198:   }
                    199: 
                    200:   if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
                    201:     /* connection is already authenticated,
                    202:      * don't send a header in future requests */
                    203:     authp->done = TRUE;
                    204:   }
                    205: 
                    206:   neg_ctx->havenegdata = FALSE;
                    207: 
                    208:   return CURLE_OK;
                    209: }
                    210: 
                    211: void Curl_http_auth_cleanup_negotiate(struct connectdata *conn)
                    212: {
                    213:   conn->http_negotiate_state = GSS_AUTHNONE;
                    214:   conn->proxy_negotiate_state = GSS_AUTHNONE;
                    215: 
                    216:   Curl_auth_cleanup_spnego(&conn->negotiate);
                    217:   Curl_auth_cleanup_spnego(&conn->proxyneg);
                    218: }
                    219: 
                    220: #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */

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