File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / http_negotiate.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>