00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "curl_setup.h"
00033
00034 #include <curl/curl.h>
00035 #include "urldata.h"
00036
00037 #include "curl_base64.h"
00038 #include "curl_md5.h"
00039 #include "vauth/vauth.h"
00040 #include "vtls/vtls.h"
00041 #include "curl_hmac.h"
00042 #include "curl_sasl.h"
00043 #include "warnless.h"
00044 #include "strtok.h"
00045 #include "sendf.h"
00046 #include "non-ascii.h"
00047
00048 #include "curl_printf.h"
00049 #include "curl_memory.h"
00050 #include "memdebug.h"
00051
00052
00053 const struct {
00054 const char *name;
00055 size_t len;
00056 unsigned int bit;
00057 } mechtable[] = {
00058 { "LOGIN", 5, SASL_MECH_LOGIN },
00059 { "PLAIN", 5, SASL_MECH_PLAIN },
00060 { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 },
00061 { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
00062 { "GSSAPI", 6, SASL_MECH_GSSAPI },
00063 { "EXTERNAL", 8, SASL_MECH_EXTERNAL },
00064 { "NTLM", 4, SASL_MECH_NTLM },
00065 { "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
00066 { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER },
00067 { ZERO_NULL, 0, 0 }
00068 };
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
00082 {
00083 #if defined(USE_KERBEROS5)
00084
00085 if(authused == SASL_MECH_GSSAPI) {
00086 Curl_auth_gssapi_cleanup(&conn->krb5);
00087 }
00088 #endif
00089
00090 #if defined(USE_NTLM)
00091
00092 if(authused == SASL_MECH_NTLM) {
00093 Curl_auth_ntlm_cleanup(&conn->ntlm);
00094 }
00095 #endif
00096
00097 #if !defined(USE_KERBEROS5) && !defined(USE_NTLM)
00098
00099 (void)conn;
00100 (void)authused;
00101 #endif
00102 }
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len)
00118 {
00119 unsigned int i;
00120 char c;
00121
00122 for(i = 0; mechtable[i].name; i++) {
00123 if(maxlen >= mechtable[i].len &&
00124 !memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
00125 if(len)
00126 *len = mechtable[i].len;
00127
00128 if(maxlen == mechtable[i].len)
00129 return mechtable[i].bit;
00130
00131 c = ptr[mechtable[i].len];
00132 if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
00133 return mechtable[i].bit;
00134 }
00135 }
00136
00137 return 0;
00138 }
00139
00140
00141
00142
00143
00144
00145 CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
00146 const char *value, size_t len)
00147 {
00148 CURLcode result = CURLE_OK;
00149 unsigned int mechbit;
00150 size_t mechlen;
00151
00152 if(!len)
00153 return CURLE_URL_MALFORMAT;
00154
00155 if(sasl->resetprefs) {
00156 sasl->resetprefs = FALSE;
00157 sasl->prefmech = SASL_AUTH_NONE;
00158 }
00159
00160 if(!strncmp(value, "*", len))
00161 sasl->prefmech = SASL_AUTH_DEFAULT;
00162 else {
00163 mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
00164 if(mechbit && mechlen == len)
00165 sasl->prefmech |= mechbit;
00166 else
00167 result = CURLE_URL_MALFORMAT;
00168 }
00169
00170 return result;
00171 }
00172
00173
00174
00175
00176
00177
00178 void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
00179 {
00180 sasl->params = params;
00181 sasl->state = SASL_STOP;
00182 sasl->authmechs = SASL_AUTH_NONE;
00183 sasl->prefmech = SASL_AUTH_DEFAULT;
00184 sasl->authused = SASL_AUTH_NONE;
00185 sasl->resetprefs = TRUE;
00186 sasl->mutual_auth = FALSE;
00187 sasl->force_ir = FALSE;
00188 }
00189
00190
00191
00192
00193
00194
00195 static void state(struct SASL *sasl, struct connectdata *conn,
00196 saslstate newstate)
00197 {
00198 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
00199
00200 static const char * const names[]={
00201 "STOP",
00202 "PLAIN",
00203 "LOGIN",
00204 "LOGIN_PASSWD",
00205 "EXTERNAL",
00206 "CRAMMD5",
00207 "DIGESTMD5",
00208 "DIGESTMD5_RESP",
00209 "NTLM",
00210 "NTLM_TYPE2MSG",
00211 "GSSAPI",
00212 "GSSAPI_TOKEN",
00213 "GSSAPI_NO_DATA",
00214 "OAUTH2",
00215 "OAUTH2_RESP",
00216 "CANCEL",
00217 "FINAL",
00218
00219 };
00220
00221 if(sasl->state != newstate)
00222 infof(conn->data, "SASL %p state change from %s to %s\n",
00223 (void *)sasl, names[sasl->state], names[newstate]);
00224 #else
00225 (void) conn;
00226 #endif
00227
00228 sasl->state = newstate;
00229 }
00230
00231
00232
00233
00234
00235
00236 bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
00237 {
00238
00239 if(conn->bits.user_passwd)
00240 return TRUE;
00241
00242
00243 if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
00244 return TRUE;
00245
00246 return FALSE;
00247 }
00248
00249
00250
00251
00252
00253
00254 CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
00255 bool force_ir, saslprogress *progress)
00256 {
00257 CURLcode result = CURLE_OK;
00258 struct Curl_easy *data = conn->data;
00259 unsigned int enabledmechs;
00260 const char *mech = NULL;
00261 char *resp = NULL;
00262 size_t len = 0;
00263 saslstate state1 = SASL_STOP;
00264 saslstate state2 = SASL_FINAL;
00265 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00266 conn->host.name;
00267 const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
00268 #if defined(USE_KERBEROS5)
00269 const char *service = data->set.str[STRING_SERVICE_NAME] ?
00270 data->set.str[STRING_SERVICE_NAME] :
00271 sasl->params->service;
00272 #endif
00273
00274 sasl->force_ir = force_ir;
00275 sasl->authused = 0;
00276 enabledmechs = sasl->authmechs & sasl->prefmech;
00277 *progress = SASL_IDLE;
00278
00279
00280
00281 if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
00282 mech = SASL_MECH_STRING_EXTERNAL;
00283 state1 = SASL_EXTERNAL;
00284 sasl->authused = SASL_MECH_EXTERNAL;
00285
00286 if(force_ir || data->set.sasl_ir)
00287 result = Curl_auth_create_external_message(data, conn->user, &resp,
00288 &len);
00289 }
00290 else if(conn->bits.user_passwd) {
00291 #if defined(USE_KERBEROS5)
00292 if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
00293 Curl_auth_user_contains_domain(conn->user)) {
00294 sasl->mutual_auth = FALSE;
00295 mech = SASL_MECH_STRING_GSSAPI;
00296 state1 = SASL_GSSAPI;
00297 state2 = SASL_GSSAPI_TOKEN;
00298 sasl->authused = SASL_MECH_GSSAPI;
00299
00300 if(force_ir || data->set.sasl_ir)
00301 result = Curl_auth_create_gssapi_user_message(data, conn->user,
00302 conn->passwd,
00303 service,
00304 data->easy_conn->
00305 host.name,
00306 sasl->mutual_auth,
00307 NULL, &conn->krb5,
00308 &resp, &len);
00309 }
00310 else
00311 #endif
00312 #ifndef CURL_DISABLE_CRYPTO_AUTH
00313 if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
00314 Curl_auth_is_digest_supported()) {
00315 mech = SASL_MECH_STRING_DIGEST_MD5;
00316 state1 = SASL_DIGESTMD5;
00317 sasl->authused = SASL_MECH_DIGEST_MD5;
00318 }
00319 else if(enabledmechs & SASL_MECH_CRAM_MD5) {
00320 mech = SASL_MECH_STRING_CRAM_MD5;
00321 state1 = SASL_CRAMMD5;
00322 sasl->authused = SASL_MECH_CRAM_MD5;
00323 }
00324 else
00325 #endif
00326 #ifdef USE_NTLM
00327 if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
00328 mech = SASL_MECH_STRING_NTLM;
00329 state1 = SASL_NTLM;
00330 state2 = SASL_NTLM_TYPE2MSG;
00331 sasl->authused = SASL_MECH_NTLM;
00332
00333 if(force_ir || data->set.sasl_ir)
00334 result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
00335 &conn->ntlm, &resp, &len);
00336 }
00337 else
00338 #endif
00339 if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) {
00340 mech = SASL_MECH_STRING_OAUTHBEARER;
00341 state1 = SASL_OAUTH2;
00342 state2 = SASL_OAUTH2_RESP;
00343 sasl->authused = SASL_MECH_OAUTHBEARER;
00344
00345 if(force_ir || data->set.sasl_ir)
00346 result = Curl_auth_create_oauth_bearer_message(data, conn->user,
00347 hostname,
00348 port,
00349 conn->oauth_bearer,
00350 &resp, &len);
00351 }
00352 else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) {
00353 mech = SASL_MECH_STRING_XOAUTH2;
00354 state1 = SASL_OAUTH2;
00355 sasl->authused = SASL_MECH_XOAUTH2;
00356
00357 if(force_ir || data->set.sasl_ir)
00358 result = Curl_auth_create_oauth_bearer_message(data, conn->user,
00359 NULL, 0,
00360 conn->oauth_bearer,
00361 &resp, &len);
00362 }
00363 else if(enabledmechs & SASL_MECH_LOGIN) {
00364 mech = SASL_MECH_STRING_LOGIN;
00365 state1 = SASL_LOGIN;
00366 state2 = SASL_LOGIN_PASSWD;
00367 sasl->authused = SASL_MECH_LOGIN;
00368
00369 if(force_ir || data->set.sasl_ir)
00370 result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
00371 }
00372 else if(enabledmechs & SASL_MECH_PLAIN) {
00373 mech = SASL_MECH_STRING_PLAIN;
00374 state1 = SASL_PLAIN;
00375 sasl->authused = SASL_MECH_PLAIN;
00376
00377 if(force_ir || data->set.sasl_ir)
00378 result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
00379 &resp, &len);
00380 }
00381 }
00382
00383 if(!result && mech) {
00384 if(resp && sasl->params->maxirlen &&
00385 strlen(mech) + len > sasl->params->maxirlen) {
00386 free(resp);
00387 resp = NULL;
00388 }
00389
00390 result = sasl->params->sendauth(conn, mech, resp);
00391 if(!result) {
00392 *progress = SASL_INPROGRESS;
00393 state(sasl, conn, resp ? state2 : state1);
00394 }
00395 }
00396
00397 free(resp);
00398
00399 return result;
00400 }
00401
00402
00403
00404
00405
00406
00407 CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
00408 int code, saslprogress *progress)
00409 {
00410 CURLcode result = CURLE_OK;
00411 struct Curl_easy *data = conn->data;
00412 saslstate newstate = SASL_FINAL;
00413 char *resp = NULL;
00414 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
00415 conn->host.name;
00416 const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
00417 #if !defined(CURL_DISABLE_CRYPTO_AUTH)
00418 char *serverdata;
00419 char *chlg = NULL;
00420 size_t chlglen = 0;
00421 #endif
00422 #if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5)
00423 const char *service = data->set.str[STRING_SERVICE_NAME] ?
00424 data->set.str[STRING_SERVICE_NAME] :
00425 sasl->params->service;
00426 #endif
00427 size_t len = 0;
00428
00429 *progress = SASL_INPROGRESS;
00430
00431 if(sasl->state == SASL_FINAL) {
00432 if(code != sasl->params->finalcode)
00433 result = CURLE_LOGIN_DENIED;
00434 *progress = SASL_DONE;
00435 state(sasl, conn, SASL_STOP);
00436 return result;
00437 }
00438
00439 if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
00440 code != sasl->params->contcode) {
00441 *progress = SASL_DONE;
00442 state(sasl, conn, SASL_STOP);
00443 return CURLE_LOGIN_DENIED;
00444 }
00445
00446 switch(sasl->state) {
00447 case SASL_STOP:
00448 *progress = SASL_DONE;
00449 return result;
00450 case SASL_PLAIN:
00451 result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
00452 &resp,
00453 &len);
00454 break;
00455 case SASL_LOGIN:
00456 result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
00457 newstate = SASL_LOGIN_PASSWD;
00458 break;
00459 case SASL_LOGIN_PASSWD:
00460 result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len);
00461 break;
00462 case SASL_EXTERNAL:
00463 result = Curl_auth_create_external_message(data, conn->user, &resp, &len);
00464 break;
00465
00466 #ifndef CURL_DISABLE_CRYPTO_AUTH
00467 case SASL_CRAMMD5:
00468 sasl->params->getmessage(data->state.buffer, &serverdata);
00469 result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen);
00470 if(!result)
00471 result = Curl_auth_create_cram_md5_message(data, chlg, conn->user,
00472 conn->passwd, &resp, &len);
00473 free(chlg);
00474 break;
00475 case SASL_DIGESTMD5:
00476 sasl->params->getmessage(data->state.buffer, &serverdata);
00477 result = Curl_auth_create_digest_md5_message(data, serverdata,
00478 conn->user, conn->passwd,
00479 service,
00480 &resp, &len);
00481 newstate = SASL_DIGESTMD5_RESP;
00482 break;
00483 case SASL_DIGESTMD5_RESP:
00484 resp = strdup("");
00485 if(!resp)
00486 result = CURLE_OUT_OF_MEMORY;
00487 break;
00488 #endif
00489
00490 #ifdef USE_NTLM
00491 case SASL_NTLM:
00492
00493 result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
00494 &conn->ntlm, &resp, &len);
00495 newstate = SASL_NTLM_TYPE2MSG;
00496 break;
00497 case SASL_NTLM_TYPE2MSG:
00498
00499 sasl->params->getmessage(data->state.buffer, &serverdata);
00500 result = Curl_auth_decode_ntlm_type2_message(data, serverdata,
00501 &conn->ntlm);
00502 if(!result)
00503 result = Curl_auth_create_ntlm_type3_message(data, conn->user,
00504 conn->passwd, &conn->ntlm,
00505 &resp, &len);
00506 break;
00507 #endif
00508
00509 #if defined(USE_KERBEROS5)
00510 case SASL_GSSAPI:
00511 result = Curl_auth_create_gssapi_user_message(data, conn->user,
00512 conn->passwd,
00513 service,
00514 data->easy_conn->host.name,
00515 sasl->mutual_auth, NULL,
00516 &conn->krb5,
00517 &resp, &len);
00518 newstate = SASL_GSSAPI_TOKEN;
00519 break;
00520 case SASL_GSSAPI_TOKEN:
00521 sasl->params->getmessage(data->state.buffer, &serverdata);
00522 if(sasl->mutual_auth) {
00523
00524
00525 result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
00526 NULL, NULL,
00527 sasl->mutual_auth,
00528 serverdata, &conn->krb5,
00529 &resp, &len);
00530 newstate = SASL_GSSAPI_NO_DATA;
00531 }
00532 else
00533
00534 result = Curl_auth_create_gssapi_security_message(data, serverdata,
00535 &conn->krb5,
00536 &resp, &len);
00537 break;
00538 case SASL_GSSAPI_NO_DATA:
00539 sasl->params->getmessage(data->state.buffer, &serverdata);
00540
00541 result = Curl_auth_create_gssapi_security_message(data, serverdata,
00542 &conn->krb5,
00543 &resp, &len);
00544 break;
00545 #endif
00546
00547 case SASL_OAUTH2:
00548
00549 if(sasl->authused == SASL_MECH_OAUTHBEARER) {
00550 result = Curl_auth_create_oauth_bearer_message(data, conn->user,
00551 hostname,
00552 port,
00553 conn->oauth_bearer,
00554 &resp, &len);
00555
00556
00557 newstate = SASL_OAUTH2_RESP;
00558 }
00559 else
00560 result = Curl_auth_create_oauth_bearer_message(data, conn->user,
00561 NULL, 0,
00562 conn->oauth_bearer,
00563 &resp, &len);
00564 break;
00565
00566 case SASL_OAUTH2_RESP:
00567
00568 if(code == sasl->params->finalcode) {
00569
00570 *progress = SASL_DONE;
00571 state(sasl, conn, SASL_STOP);
00572 return result;
00573 }
00574 else if(code == sasl->params->contcode) {
00575
00576
00577 resp = strdup("AQ==");
00578 if(!resp)
00579 result = CURLE_OUT_OF_MEMORY;
00580 break;
00581 }
00582 else {
00583 *progress = SASL_DONE;
00584 state(sasl, conn, SASL_STOP);
00585 return CURLE_LOGIN_DENIED;
00586 }
00587
00588 case SASL_CANCEL:
00589
00590 sasl->authmechs ^= sasl->authused;
00591
00592
00593 result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress);
00594 newstate = sasl->state;
00595 break;
00596 default:
00597 failf(data, "Unsupported SASL authentication mechanism");
00598 result = CURLE_UNSUPPORTED_PROTOCOL;
00599 break;
00600 }
00601
00602 switch(result) {
00603 case CURLE_BAD_CONTENT_ENCODING:
00604
00605 result = sasl->params->sendcont(conn, "*");
00606 newstate = SASL_CANCEL;
00607 break;
00608 case CURLE_OK:
00609 if(resp)
00610 result = sasl->params->sendcont(conn, resp);
00611 break;
00612 default:
00613 newstate = SASL_STOP;
00614 *progress = SASL_DONE;
00615 break;
00616 }
00617
00618 free(resp);
00619
00620 state(sasl, conn, newstate);
00621
00622 return result;
00623 }