1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl
22 *
23 * RFC2195 CRAM-MD5 authentication
24 * RFC2617 Basic and Digest Access Authentication
25 * RFC2831 DIGEST-MD5 authentication
26 * RFC4422 Simple Authentication and Security Layer (SASL)
27 * RFC4616 PLAIN authentication
28 * RFC5802 SCRAM-SHA-1 authentication
29 * RFC7677 SCRAM-SHA-256 authentication
30 * RFC6749 OAuth 2.0 Authorization Framework
31 * RFC7628 A Set of SASL Mechanisms for OAuth
32 * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
33 *
34 ***************************************************************************/
35
36 #include "curl_setup.h"
37
38 #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
39 !defined(CURL_DISABLE_POP3) || \
40 (!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
41
42 #include <curl/curl.h>
43 #include "urldata.h"
44
45 #include "curl_base64.h"
46 #include "curl_md5.h"
47 #include "vauth/vauth.h"
48 #include "cfilters.h"
49 #include "vtls/vtls.h"
50 #include "curl_hmac.h"
51 #include "curl_sasl.h"
52 #include "warnless.h"
53 #include "strtok.h"
54 #include "sendf.h"
55 /* The last 3 #include files should be in this order */
56 #include "curl_printf.h"
57 #include "curl_memory.h"
58 #include "memdebug.h"
59
60 /* Supported mechanisms */
61 static const struct {
62 const char *name; /* Name */
63 size_t len; /* Name length */
64 unsigned short bit; /* Flag bit */
65 } mechtable[] = {
66 { "LOGIN", 5, SASL_MECH_LOGIN },
67 { "PLAIN", 5, SASL_MECH_PLAIN },
68 { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 },
69 { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
70 { "GSSAPI", 6, SASL_MECH_GSSAPI },
71 { "EXTERNAL", 8, SASL_MECH_EXTERNAL },
72 { "NTLM", 4, SASL_MECH_NTLM },
73 { "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
74 { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER },
75 { "SCRAM-SHA-1", 11, SASL_MECH_SCRAM_SHA_1 },
76 { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
77 { ZERO_NULL, 0, 0 }
78 };
79
80 /*
81 * Curl_sasl_cleanup()
82 *
83 * This is used to cleanup any libraries or curl modules used by the sasl
84 * functions.
85 *
86 * Parameters:
87 *
88 * conn [in] - The connection data.
89 * authused [in] - The authentication mechanism used.
90 */
Curl_sasl_cleanup(struct connectdata * conn,unsigned short authused)91 void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
92 {
93 (void)conn;
94 (void)authused;
95
96 #if defined(USE_KERBEROS5)
97 /* Cleanup the gssapi structure */
98 if(authused == SASL_MECH_GSSAPI) {
99 Curl_auth_cleanup_gssapi(&conn->krb5);
100 }
101 #endif
102
103 #if defined(USE_GSASL)
104 /* Cleanup the GSASL structure */
105 if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
106 Curl_auth_gsasl_cleanup(&conn->gsasl);
107 }
108 #endif
109
110 #if defined(USE_NTLM)
111 /* Cleanup the NTLM structure */
112 if(authused == SASL_MECH_NTLM) {
113 Curl_auth_cleanup_ntlm(&conn->ntlm);
114 }
115 #endif
116 }
117
118 /*
119 * Curl_sasl_decode_mech()
120 *
121 * Convert a SASL mechanism name into a token.
122 *
123 * Parameters:
124 *
125 * ptr [in] - The mechanism string.
126 * maxlen [in] - Maximum mechanism string length.
127 * len [out] - If not NULL, effective name length.
128 *
129 * Returns the SASL mechanism token or 0 if no match.
130 */
Curl_sasl_decode_mech(const char * ptr,size_t maxlen,size_t * len)131 unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
132 size_t *len)
133 {
134 unsigned int i;
135 char c;
136
137 for(i = 0; mechtable[i].name; i++) {
138 if(maxlen >= mechtable[i].len &&
139 !memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
140 if(len)
141 *len = mechtable[i].len;
142
143 if(maxlen == mechtable[i].len)
144 return mechtable[i].bit;
145
146 c = ptr[mechtable[i].len];
147 if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
148 return mechtable[i].bit;
149 }
150 }
151
152 return 0;
153 }
154
155 /*
156 * Curl_sasl_parse_url_auth_option()
157 *
158 * Parse the URL login options.
159 */
Curl_sasl_parse_url_auth_option(struct SASL * sasl,const char * value,size_t len)160 CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
161 const char *value, size_t len)
162 {
163 CURLcode result = CURLE_OK;
164 size_t mechlen;
165
166 if(!len)
167 return CURLE_URL_MALFORMAT;
168
169 if(sasl->resetprefs) {
170 sasl->resetprefs = FALSE;
171 sasl->prefmech = SASL_AUTH_NONE;
172 }
173
174 if(!strncmp(value, "*", len))
175 sasl->prefmech = SASL_AUTH_DEFAULT;
176 else {
177 unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
178 if(mechbit && mechlen == len)
179 sasl->prefmech |= mechbit;
180 else
181 result = CURLE_URL_MALFORMAT;
182 }
183
184 return result;
185 }
186
187 /*
188 * Curl_sasl_init()
189 *
190 * Initializes the SASL structure.
191 */
Curl_sasl_init(struct SASL * sasl,struct Curl_easy * data,const struct SASLproto * params)192 void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
193 const struct SASLproto *params)
194 {
195 unsigned long auth = data->set.httpauth;
196
197 sasl->params = params; /* Set protocol dependent parameters */
198 sasl->state = SASL_STOP; /* Not yet running */
199 sasl->curmech = NULL; /* No mechanism yet. */
200 sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
201 sasl->prefmech = params->defmechs; /* Default preferred mechanisms */
202 sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */
203 sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
204 sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
205 sasl->force_ir = FALSE; /* Respect external option */
206
207 if(auth != CURLAUTH_BASIC) {
208 unsigned short mechs = SASL_AUTH_NONE;
209
210 /* If some usable http authentication options have been set, determine
211 new defaults from them. */
212 if(auth & CURLAUTH_BASIC)
213 mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
214 if(auth & CURLAUTH_DIGEST)
215 mechs |= SASL_MECH_DIGEST_MD5;
216 if(auth & CURLAUTH_NTLM)
217 mechs |= SASL_MECH_NTLM;
218 if(auth & CURLAUTH_BEARER)
219 mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
220 if(auth & CURLAUTH_GSSAPI)
221 mechs |= SASL_MECH_GSSAPI;
222
223 if(mechs != SASL_AUTH_NONE)
224 sasl->prefmech = mechs;
225 }
226 }
227
228 /*
229 * sasl_state()
230 *
231 * This is the ONLY way to change SASL state!
232 */
sasl_state(struct SASL * sasl,struct Curl_easy * data,saslstate newstate)233 static void sasl_state(struct SASL *sasl, struct Curl_easy *data,
234 saslstate newstate)
235 {
236 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
237 /* for debug purposes */
238 static const char * const names[]={
239 "STOP",
240 "PLAIN",
241 "LOGIN",
242 "LOGIN_PASSWD",
243 "EXTERNAL",
244 "CRAMMD5",
245 "DIGESTMD5",
246 "DIGESTMD5_RESP",
247 "NTLM",
248 "NTLM_TYPE2MSG",
249 "GSSAPI",
250 "GSSAPI_TOKEN",
251 "GSSAPI_NO_DATA",
252 "OAUTH2",
253 "OAUTH2_RESP",
254 "GSASL",
255 "CANCEL",
256 "FINAL",
257 /* LAST */
258 };
259
260 if(sasl->state != newstate)
261 infof(data, "SASL %p state change from %s to %s",
262 (void *)sasl, names[sasl->state], names[newstate]);
263 #else
264 (void) data;
265 #endif
266
267 sasl->state = newstate;
268 }
269
270 #if defined(USE_NTLM) || defined(USE_GSASL) || defined(USE_KERBEROS5) || \
271 !defined(CURL_DISABLE_DIGEST_AUTH)
272 /* Get the SASL server message and convert it to binary. */
get_server_message(struct SASL * sasl,struct Curl_easy * data,struct bufref * out)273 static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
274 struct bufref *out)
275 {
276 CURLcode result = CURLE_OK;
277
278 result = sasl->params->getmessage(data, out);
279 if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) {
280 unsigned char *msg;
281 size_t msglen;
282 const char *serverdata = (const char *) Curl_bufref_ptr(out);
283
284 if(!*serverdata || *serverdata == '=')
285 Curl_bufref_set(out, NULL, 0, NULL);
286 else {
287 result = Curl_base64_decode(serverdata, &msg, &msglen);
288 if(!result)
289 Curl_bufref_set(out, msg, msglen, curl_free);
290 }
291 }
292 return result;
293 }
294 #endif
295
296 /* Encode the outgoing SASL message. */
build_message(struct SASL * sasl,struct bufref * msg)297 static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
298 {
299 CURLcode result = CURLE_OK;
300
301 if(sasl->params->flags & SASL_FLAG_BASE64) {
302 if(!Curl_bufref_ptr(msg)) /* Empty message. */
303 Curl_bufref_set(msg, "", 0, NULL);
304 else if(!Curl_bufref_len(msg)) /* Explicit empty response. */
305 Curl_bufref_set(msg, "=", 1, NULL);
306 else {
307 char *base64;
308 size_t base64len;
309
310 result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
311 Curl_bufref_len(msg), &base64, &base64len);
312 if(!result)
313 Curl_bufref_set(msg, base64, base64len, curl_free);
314 }
315 }
316
317 return result;
318 }
319
320 /*
321 * Curl_sasl_can_authenticate()
322 *
323 * Check if we have enough auth data and capabilities to authenticate.
324 */
Curl_sasl_can_authenticate(struct SASL * sasl,struct Curl_easy * data)325 bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
326 {
327 /* Have credentials been provided? */
328 if(data->state.aptr.user)
329 return TRUE;
330
331 /* EXTERNAL can authenticate without a username and/or password */
332 if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
333 return TRUE;
334
335 return FALSE;
336 }
337
338 /*
339 * Curl_sasl_start()
340 *
341 * Calculate the required login details for SASL authentication.
342 */
Curl_sasl_start(struct SASL * sasl,struct Curl_easy * data,bool force_ir,saslprogress * progress)343 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
344 bool force_ir, saslprogress *progress)
345 {
346 CURLcode result = CURLE_OK;
347 struct connectdata *conn = data->conn;
348 unsigned short enabledmechs;
349 const char *mech = NULL;
350 struct bufref resp;
351 saslstate state1 = SASL_STOP;
352 saslstate state2 = SASL_FINAL;
353 const char *hostname, *disp_hostname;
354 int port;
355 #if defined(USE_KERBEROS5) || defined(USE_NTLM)
356 const char *service = data->set.str[STRING_SERVICE_NAME] ?
357 data->set.str[STRING_SERVICE_NAME] :
358 sasl->params->service;
359 #endif
360 const char *oauth_bearer = data->set.str[STRING_BEARER];
361 struct bufref nullmsg;
362
363 Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
364 Curl_bufref_init(&nullmsg);
365 Curl_bufref_init(&resp);
366 sasl->force_ir = force_ir; /* Latch for future use */
367 sasl->authused = 0; /* No mechanism used yet */
368 enabledmechs = sasl->authmechs & sasl->prefmech;
369 *progress = SASL_IDLE;
370
371 /* Calculate the supported authentication mechanism, by decreasing order of
372 security, as well as the initial response where appropriate */
373 if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
374 mech = SASL_MECH_STRING_EXTERNAL;
375 state1 = SASL_EXTERNAL;
376 sasl->authused = SASL_MECH_EXTERNAL;
377
378 if(force_ir || data->set.sasl_ir)
379 Curl_auth_create_external_message(conn->user, &resp);
380 }
381 else if(data->state.aptr.user) {
382 #if defined(USE_KERBEROS5)
383 if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
384 Curl_auth_user_contains_domain(conn->user)) {
385 sasl->mutual_auth = FALSE;
386 mech = SASL_MECH_STRING_GSSAPI;
387 state1 = SASL_GSSAPI;
388 state2 = SASL_GSSAPI_TOKEN;
389 sasl->authused = SASL_MECH_GSSAPI;
390
391 if(force_ir || data->set.sasl_ir)
392 result = Curl_auth_create_gssapi_user_message(data, conn->user,
393 conn->passwd,
394 service,
395 conn->host.name,
396 sasl->mutual_auth,
397 NULL, &conn->krb5,
398 &resp);
399 }
400 else
401 #endif
402 #ifdef USE_GSASL
403 if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
404 Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
405 &conn->gsasl)) {
406 mech = SASL_MECH_STRING_SCRAM_SHA_256;
407 sasl->authused = SASL_MECH_SCRAM_SHA_256;
408 state1 = SASL_GSASL;
409 state2 = SASL_GSASL;
410
411 result = Curl_auth_gsasl_start(data, conn->user,
412 conn->passwd, &conn->gsasl);
413 if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
414 result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
415 }
416 else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
417 Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
418 &conn->gsasl)) {
419 mech = SASL_MECH_STRING_SCRAM_SHA_1;
420 sasl->authused = SASL_MECH_SCRAM_SHA_1;
421 state1 = SASL_GSASL;
422 state2 = SASL_GSASL;
423
424 result = Curl_auth_gsasl_start(data, conn->user,
425 conn->passwd, &conn->gsasl);
426 if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
427 result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
428 }
429 else
430 #endif
431 #ifndef CURL_DISABLE_DIGEST_AUTH
432 if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
433 Curl_auth_is_digest_supported()) {
434 mech = SASL_MECH_STRING_DIGEST_MD5;
435 state1 = SASL_DIGESTMD5;
436 sasl->authused = SASL_MECH_DIGEST_MD5;
437 }
438 else if(enabledmechs & SASL_MECH_CRAM_MD5) {
439 mech = SASL_MECH_STRING_CRAM_MD5;
440 state1 = SASL_CRAMMD5;
441 sasl->authused = SASL_MECH_CRAM_MD5;
442 }
443 else
444 #endif
445 #ifdef USE_NTLM
446 if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
447 mech = SASL_MECH_STRING_NTLM;
448 state1 = SASL_NTLM;
449 state2 = SASL_NTLM_TYPE2MSG;
450 sasl->authused = SASL_MECH_NTLM;
451
452 if(force_ir || data->set.sasl_ir)
453 result = Curl_auth_create_ntlm_type1_message(data,
454 conn->user, conn->passwd,
455 service,
456 hostname,
457 &conn->ntlm, &resp);
458 }
459 else
460 #endif
461 if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
462 mech = SASL_MECH_STRING_OAUTHBEARER;
463 state1 = SASL_OAUTH2;
464 state2 = SASL_OAUTH2_RESP;
465 sasl->authused = SASL_MECH_OAUTHBEARER;
466
467 if(force_ir || data->set.sasl_ir)
468 result = Curl_auth_create_oauth_bearer_message(conn->user,
469 hostname,
470 port,
471 oauth_bearer,
472 &resp);
473 }
474 else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
475 mech = SASL_MECH_STRING_XOAUTH2;
476 state1 = SASL_OAUTH2;
477 sasl->authused = SASL_MECH_XOAUTH2;
478
479 if(force_ir || data->set.sasl_ir)
480 result = Curl_auth_create_xoauth_bearer_message(conn->user,
481 oauth_bearer,
482 &resp);
483 }
484 else if(enabledmechs & SASL_MECH_PLAIN) {
485 mech = SASL_MECH_STRING_PLAIN;
486 state1 = SASL_PLAIN;
487 sasl->authused = SASL_MECH_PLAIN;
488
489 if(force_ir || data->set.sasl_ir)
490 result = Curl_auth_create_plain_message(conn->sasl_authzid,
491 conn->user, conn->passwd,
492 &resp);
493 }
494 else if(enabledmechs & SASL_MECH_LOGIN) {
495 mech = SASL_MECH_STRING_LOGIN;
496 state1 = SASL_LOGIN;
497 state2 = SASL_LOGIN_PASSWD;
498 sasl->authused = SASL_MECH_LOGIN;
499
500 if(force_ir || data->set.sasl_ir)
501 Curl_auth_create_login_message(conn->user, &resp);
502 }
503 }
504
505 if(!result && mech) {
506 sasl->curmech = mech;
507 if(Curl_bufref_ptr(&resp))
508 result = build_message(sasl, &resp);
509
510 if(sasl->params->maxirlen &&
511 strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
512 Curl_bufref_free(&resp);
513
514 if(!result)
515 result = sasl->params->sendauth(data, mech, &resp);
516
517 if(!result) {
518 *progress = SASL_INPROGRESS;
519 sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
520 }
521 }
522
523 Curl_bufref_free(&resp);
524 return result;
525 }
526
527 /*
528 * Curl_sasl_continue()
529 *
530 * Continue the authentication.
531 */
Curl_sasl_continue(struct SASL * sasl,struct Curl_easy * data,int code,saslprogress * progress)532 CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
533 int code, saslprogress *progress)
534 {
535 CURLcode result = CURLE_OK;
536 struct connectdata *conn = data->conn;
537 saslstate newstate = SASL_FINAL;
538 struct bufref resp;
539 const char *hostname, *disp_hostname;
540 int port;
541 #if defined(USE_KERBEROS5) || defined(USE_NTLM) \
542 || !defined(CURL_DISABLE_DIGEST_AUTH)
543 const char *service = data->set.str[STRING_SERVICE_NAME] ?
544 data->set.str[STRING_SERVICE_NAME] :
545 sasl->params->service;
546 #endif
547 const char *oauth_bearer = data->set.str[STRING_BEARER];
548 struct bufref serverdata;
549
550 Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
551 Curl_bufref_init(&serverdata);
552 Curl_bufref_init(&resp);
553 *progress = SASL_INPROGRESS;
554
555 if(sasl->state == SASL_FINAL) {
556 if(code != sasl->params->finalcode)
557 result = CURLE_LOGIN_DENIED;
558 *progress = SASL_DONE;
559 sasl_state(sasl, data, SASL_STOP);
560 return result;
561 }
562
563 if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
564 code != sasl->params->contcode) {
565 *progress = SASL_DONE;
566 sasl_state(sasl, data, SASL_STOP);
567 return CURLE_LOGIN_DENIED;
568 }
569
570 switch(sasl->state) {
571 case SASL_STOP:
572 *progress = SASL_DONE;
573 return result;
574 case SASL_PLAIN:
575 result = Curl_auth_create_plain_message(conn->sasl_authzid,
576 conn->user, conn->passwd, &resp);
577 break;
578 case SASL_LOGIN:
579 Curl_auth_create_login_message(conn->user, &resp);
580 newstate = SASL_LOGIN_PASSWD;
581 break;
582 case SASL_LOGIN_PASSWD:
583 Curl_auth_create_login_message(conn->passwd, &resp);
584 break;
585 case SASL_EXTERNAL:
586 Curl_auth_create_external_message(conn->user, &resp);
587 break;
588 #ifdef USE_GSASL
589 case SASL_GSASL:
590 result = get_server_message(sasl, data, &serverdata);
591 if(!result)
592 result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
593 if(!result && Curl_bufref_len(&resp) > 0)
594 newstate = SASL_GSASL;
595 break;
596 #endif
597 #ifndef CURL_DISABLE_DIGEST_AUTH
598 case SASL_CRAMMD5:
599 result = get_server_message(sasl, data, &serverdata);
600 if(!result)
601 result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
602 conn->passwd, &resp);
603 break;
604 case SASL_DIGESTMD5:
605 result = get_server_message(sasl, data, &serverdata);
606 if(!result)
607 result = Curl_auth_create_digest_md5_message(data, &serverdata,
608 conn->user, conn->passwd,
609 service, &resp);
610 if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
611 newstate = SASL_DIGESTMD5_RESP;
612 break;
613 case SASL_DIGESTMD5_RESP:
614 /* Keep response NULL to output an empty line. */
615 break;
616 #endif
617
618 #ifdef USE_NTLM
619 case SASL_NTLM:
620 /* Create the type-1 message */
621 result = Curl_auth_create_ntlm_type1_message(data,
622 conn->user, conn->passwd,
623 service, hostname,
624 &conn->ntlm, &resp);
625 newstate = SASL_NTLM_TYPE2MSG;
626 break;
627 case SASL_NTLM_TYPE2MSG:
628 /* Decode the type-2 message */
629 result = get_server_message(sasl, data, &serverdata);
630 if(!result)
631 result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
632 &conn->ntlm);
633 if(!result)
634 result = Curl_auth_create_ntlm_type3_message(data, conn->user,
635 conn->passwd, &conn->ntlm,
636 &resp);
637 break;
638 #endif
639
640 #if defined(USE_KERBEROS5)
641 case SASL_GSSAPI:
642 result = Curl_auth_create_gssapi_user_message(data, conn->user,
643 conn->passwd,
644 service,
645 conn->host.name,
646 sasl->mutual_auth, NULL,
647 &conn->krb5,
648 &resp);
649 newstate = SASL_GSSAPI_TOKEN;
650 break;
651 case SASL_GSSAPI_TOKEN:
652 result = get_server_message(sasl, data, &serverdata);
653 if(!result) {
654 if(sasl->mutual_auth) {
655 /* Decode the user token challenge and create the optional response
656 message */
657 result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
658 NULL, NULL,
659 sasl->mutual_auth,
660 &serverdata,
661 &conn->krb5,
662 &resp);
663 newstate = SASL_GSSAPI_NO_DATA;
664 }
665 else
666 /* Decode the security challenge and create the response message */
667 result = Curl_auth_create_gssapi_security_message(data,
668 conn->sasl_authzid,
669 &serverdata,
670 &conn->krb5,
671 &resp);
672 }
673 break;
674 case SASL_GSSAPI_NO_DATA:
675 /* Decode the security challenge and create the response message */
676 result = get_server_message(sasl, data, &serverdata);
677 if(!result)
678 result = Curl_auth_create_gssapi_security_message(data,
679 conn->sasl_authzid,
680 &serverdata,
681 &conn->krb5,
682 &resp);
683 break;
684 #endif
685
686 case SASL_OAUTH2:
687 /* Create the authorization message */
688 if(sasl->authused == SASL_MECH_OAUTHBEARER) {
689 result = Curl_auth_create_oauth_bearer_message(conn->user,
690 hostname,
691 port,
692 oauth_bearer,
693 &resp);
694
695 /* Failures maybe sent by the server as continuations for OAUTHBEARER */
696 newstate = SASL_OAUTH2_RESP;
697 }
698 else
699 result = Curl_auth_create_xoauth_bearer_message(conn->user,
700 oauth_bearer,
701 &resp);
702 break;
703
704 case SASL_OAUTH2_RESP:
705 /* The continuation is optional so check the response code */
706 if(code == sasl->params->finalcode) {
707 /* Final response was received so we are done */
708 *progress = SASL_DONE;
709 sasl_state(sasl, data, SASL_STOP);
710 return result;
711 }
712 else if(code == sasl->params->contcode) {
713 /* Acknowledge the continuation by sending a 0x01 response. */
714 Curl_bufref_set(&resp, "\x01", 1, NULL);
715 break;
716 }
717 else {
718 *progress = SASL_DONE;
719 sasl_state(sasl, data, SASL_STOP);
720 return CURLE_LOGIN_DENIED;
721 }
722
723 case SASL_CANCEL:
724 /* Remove the offending mechanism from the supported list */
725 sasl->authmechs ^= sasl->authused;
726
727 /* Start an alternative SASL authentication */
728 return Curl_sasl_start(sasl, data, sasl->force_ir, progress);
729 default:
730 failf(data, "Unsupported SASL authentication mechanism");
731 result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
732 break;
733 }
734
735 Curl_bufref_free(&serverdata);
736
737 switch(result) {
738 case CURLE_BAD_CONTENT_ENCODING:
739 /* Cancel dialog */
740 result = sasl->params->cancelauth(data, sasl->curmech);
741 newstate = SASL_CANCEL;
742 break;
743 case CURLE_OK:
744 result = build_message(sasl, &resp);
745 if(!result)
746 result = sasl->params->contauth(data, sasl->curmech, &resp);
747 break;
748 default:
749 newstate = SASL_STOP; /* Stop on error */
750 *progress = SASL_DONE;
751 break;
752 }
753
754 Curl_bufref_free(&resp);
755
756 sasl_state(sasl, data, newstate);
757
758 return result;
759 }
760 #endif /* protocols are enabled that use SASL */
761