diff options
| author | Patrick Monnerat <pm@datasphere.ch> | 2015-01-27 17:24:55 +0100 | 
|---|---|---|
| committer | Patrick Monnerat <pm@datasphere.ch> | 2015-01-27 17:24:55 +0100 | 
| commit | 0d24f644735924524bcffff75ace4bd7b7a2e05a (patch) | |
| tree | 7021e64d949bb2bcec90a3adc8f9c2314c94cec6 | |
| parent | e1bb13c09f8d4cb8d1499fc9f51734729cdcdf2c (diff) | |
sasl: implement EXTERNAL authentication mechanism.
  Its use is only enabled by explicit requirement in URL (;AUTH=EXTERNAL) and
by not setting the password.
| -rw-r--r-- | lib/curl_sasl.c | 188 | ||||
| -rw-r--r-- | lib/curl_sasl.h | 13 | ||||
| -rw-r--r-- | lib/imap.c | 6 | ||||
| -rw-r--r-- | lib/pop3.c | 6 | ||||
| -rw-r--r-- | lib/smtp.c | 5 | 
5 files changed, 139 insertions, 79 deletions
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 347f1a302..2d55836cd 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -368,6 +368,30 @@ static CURLcode sasl_create_login_message(struct SessionHandle *data,    return Curl_base64_encode(data, valuep, vlen, outptr, outlen);  } +/* + * sasl_create_external_message() + * + * This is used to generate an already encoded EXTERNAL message containing + * the user name ready for sending to the recipient. + * + * Parameters: + * + * data    [in]     - The session handle. + * user    [in]     - The user name. + * outptr  [in/out] - The address where a pointer to newly allocated memory + *                    holding the result will be stored upon completion. + * outlen  [out]    - The length of the output message. + * + * Returns CURLE_OK on success. + */ +static CURLcode sasl_create_external_message(struct SessionHandle *data, +                                          const char *user, char **outptr, +                                          size_t *outlen) +{ +  /* This is the same formatting as the login message. */ +  return sasl_create_login_message(data, user, outptr, outlen); +} +  #ifndef CURL_DISABLE_CRYPTO_AUTH   /*   * sasl_decode_cram_md5_message() @@ -1257,7 +1281,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,      }      if(strnequal(value, "*", len)) -      sasl->prefmech = SASL_AUTH_ANY; +      sasl->prefmech = SASL_AUTH_DEFAULT;      else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) &&              mechlen == len)        sasl->prefmech |= mechbit; @@ -1277,7 +1301,7 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)    sasl->params = params;           /* Set protocol dependent parameters */    sasl->state = SASL_STOP;         /* Not yet running */    sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ -  sasl->prefmech = SASL_AUTH_ANY;  /* Prefer all mechanisms */ +  sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */    sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */    sasl->resetprefs = TRUE;         /* Reset prefmech upon AUTH parsing. */    sasl->mutual_auth = FALSE;       /* No mutual authentication (GSSAPI only) */ @@ -1299,6 +1323,7 @@ static void state(struct SASL *sasl,      "PLAIN",      "LOGIN",      "LOGIN_PASSWD", +    "EXTERNAL",      "CRAMMD5",      "DIGESTMD5",      "DIGESTMD5_RESP", @@ -1322,6 +1347,23 @@ static void state(struct SASL *sasl,  }  /* + * Curl_sasl_can_authenticate() + * + * Check if we have enough auth data and capabilities to authenticate. + */ + +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) +{ +  if(conn->bits.user_passwd) +    return TRUE;        /* Credentials provided */ + +  if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL) +    return TRUE;        /* Can authenticate without password */ + +  return FALSE; +} + +/*   * Curl_sasl_start()   *   * Calculate the required login details for SASL authentication. @@ -1345,80 +1387,89 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,    /* Calculate the supported authentication mechanism, by decreasing order of     *      security, as well as the initial response where appropriate */ -#if defined(USE_KERBEROS5) -  if(enabledmechs & SASL_MECH_GSSAPI) { -    sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ -    mech = SASL_MECH_STRING_GSSAPI; -    state1 = SASL_GSSAPI; -    state2 = SASL_GSSAPI_TOKEN; -    sasl->authused = SASL_MECH_GSSAPI; +  if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { +    mech = SASL_MECH_STRING_EXTERNAL; +    state1 = SASL_EXTERNAL; +    sasl->authused = SASL_MECH_EXTERNAL;      if(force_ir || data->set.sasl_ir) -      result = Curl_sasl_create_gssapi_user_message(data, conn->user, -                                                    conn->passwd, -                                                    sasl->params->service, -                                                    sasl->mutual_auth, -                                                    NULL, &conn->krb5, -                                                    &resp, &len); +      result = sasl_create_external_message(data, conn->user, &resp, &len);    } -  else +  else if(conn->bits.user_passwd) { +#if defined(USE_KERBEROS5) +    if(enabledmechs & SASL_MECH_GSSAPI) { +      sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ +      mech = SASL_MECH_STRING_GSSAPI; +      state1 = SASL_GSSAPI; +      state2 = SASL_GSSAPI_TOKEN; +      sasl->authused = SASL_MECH_GSSAPI; + +      if(force_ir || data->set.sasl_ir) +        result = Curl_sasl_create_gssapi_user_message(data, conn->user, +                                                      conn->passwd, +                                                      sasl->params->service, +                                                      sasl->mutual_auth, +                                                      NULL, &conn->krb5, +                                                      &resp, &len); +    } +    else  #endif  #ifndef CURL_DISABLE_CRYPTO_AUTH -  if(enabledmechs & SASL_MECH_DIGEST_MD5) { -    mech = SASL_MECH_STRING_DIGEST_MD5; -    state1 = SASL_DIGESTMD5; -    sasl->authused = SASL_MECH_DIGEST_MD5; -  } -  else if(enabledmechs & SASL_MECH_CRAM_MD5) { -    mech = SASL_MECH_STRING_CRAM_MD5; -    state1 = SASL_CRAMMD5; -    sasl->authused = SASL_MECH_CRAM_MD5; -  } -  else +    if(enabledmechs & SASL_MECH_DIGEST_MD5) { +      mech = SASL_MECH_STRING_DIGEST_MD5; +      state1 = SASL_DIGESTMD5; +      sasl->authused = SASL_MECH_DIGEST_MD5; +    } +    else if(enabledmechs & SASL_MECH_CRAM_MD5) { +      mech = SASL_MECH_STRING_CRAM_MD5; +      state1 = SASL_CRAMMD5; +      sasl->authused = SASL_MECH_CRAM_MD5; +    } +    else  #endif  #ifdef USE_NTLM -  if(enabledmechs & SASL_MECH_NTLM) { -    mech = SASL_MECH_STRING_NTLM; -    state1 = SASL_NTLM; -    state2 = SASL_NTLM_TYPE2MSG; -    sasl->authused = SASL_MECH_NTLM; - -    if(force_ir || data->set.sasl_ir) -      result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, -                                                   &conn->ntlm, &resp, &len); -    } -  else +    if(enabledmechs & SASL_MECH_NTLM) { +      mech = SASL_MECH_STRING_NTLM; +      state1 = SASL_NTLM; +      state2 = SASL_NTLM_TYPE2MSG; +      sasl->authused = SASL_MECH_NTLM; + +      if(force_ir || data->set.sasl_ir) +        result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, +                                                     &conn->ntlm, &resp, &len); +      } +    else  #endif -  if((((enabledmechs & SASL_MECH_XOAUTH2) && -      sasl->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) { -    mech = SASL_MECH_STRING_XOAUTH2; -    state1 = SASL_XOAUTH2; -    sasl->authused = SASL_MECH_XOAUTH2; - -    if(force_ir || data->set.sasl_ir) -      result = sasl_create_xoauth2_message(data, conn->user, -                                           conn->xoauth2_bearer, &resp, &len); -  } -  else if(enabledmechs & SASL_MECH_LOGIN) { -    mech = SASL_MECH_STRING_LOGIN; -    state1 = SASL_LOGIN; -    state2 = SASL_LOGIN_PASSWD; -    sasl->authused = SASL_MECH_LOGIN; - -    if(force_ir || data->set.sasl_ir) -      result = sasl_create_login_message(data, conn->user, &resp, &len); -  } -  else if(enabledmechs & SASL_MECH_PLAIN) { -    mech = SASL_MECH_STRING_PLAIN; -    state1 = SASL_PLAIN; -    sasl->authused = SASL_MECH_PLAIN; - -    if(force_ir || data->set.sasl_ir) -      result = sasl_create_plain_message(data, conn->user, conn->passwd, -                                         &resp, &len); +    if((((enabledmechs & SASL_MECH_XOAUTH2) && +        sasl->prefmech != SASL_AUTH_DEFAULT)) || conn->xoauth2_bearer) { +      mech = SASL_MECH_STRING_XOAUTH2; +      state1 = SASL_XOAUTH2; +      sasl->authused = SASL_MECH_XOAUTH2; + +      if(force_ir || data->set.sasl_ir) +        result = sasl_create_xoauth2_message(data, conn->user, +                                             conn->xoauth2_bearer, +                                             &resp, &len); +    } +    else if(enabledmechs & SASL_MECH_LOGIN) { +      mech = SASL_MECH_STRING_LOGIN; +      state1 = SASL_LOGIN; +      state2 = SASL_LOGIN_PASSWD; +      sasl->authused = SASL_MECH_LOGIN; + +      if(force_ir || data->set.sasl_ir) +        result = sasl_create_login_message(data, conn->user, &resp, &len); +    } +    else if(enabledmechs & SASL_MECH_PLAIN) { +      mech = SASL_MECH_STRING_PLAIN; +      state1 = SASL_PLAIN; +      sasl->authused = SASL_MECH_PLAIN; + +      if(force_ir || data->set.sasl_ir) +        result = sasl_create_plain_message(data, conn->user, conn->passwd, +                                           &resp, &len); +    }    } -  else -    state2 = SASL_STOP;    /* No authentication started */    if(!result) {      if(resp && sasl->params->maxirlen && @@ -1490,6 +1541,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,    case SASL_LOGIN_PASSWD:      result = sasl_create_login_message(data, conn->passwd, &resp, &len);      break; +  case SASL_EXTERNAL: +    result = sasl_create_external_message(data, conn->user, &resp, &len); +    break;  #ifndef CURL_DISABLE_CRYPTO_AUTH    case SASL_CRAMMD5: diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h index e4a594c53..985ca416e 100644 --- a/lib/curl_sasl.h +++ b/lib/curl_sasl.h @@ -39,10 +39,6 @@ struct ntlmdata;  struct kerberos5data;  #endif -/* Authentication mechanism values */ -#define SASL_AUTH_NONE          0 -#define SASL_AUTH_ANY           ~0U -  /* Authentication mechanism flags */  #define SASL_MECH_LOGIN             (1 << 0)  #define SASL_MECH_PLAIN             (1 << 1) @@ -53,6 +49,11 @@ struct kerberos5data;  #define SASL_MECH_NTLM              (1 << 6)  #define SASL_MECH_XOAUTH2           (1 << 7) +/* Authentication mechanism values */ +#define SASL_AUTH_NONE          0 +#define SASL_AUTH_ANY           ~0U +#define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) +  /* Authentication mechanism strings */  #define SASL_MECH_STRING_LOGIN      "LOGIN"  #define SASL_MECH_STRING_PLAIN      "PLAIN" @@ -74,6 +75,7 @@ typedef enum {    SASL_PLAIN,    SASL_LOGIN,    SASL_LOGIN_PASSWD, +  SASL_EXTERNAL,    SASL_CRAMMD5,    SASL_DIGESTMD5,    SASL_DIGESTMD5_RESP, @@ -228,6 +230,9 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,  /* Initializes an SASL structure */  void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); +/* Check if we have enough auth data and capabilities to authenticate */ +bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); +  /* Calculate the required login details for SASL authentication  */  CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,                           bool force_ir, saslprogress *progress); diff --git a/lib/imap.c b/lib/imap.c index c5c8e4aea..2d037eeb3 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -612,9 +612,9 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)    struct imap_conn *imapc = &conn->proto.imapc;    saslprogress progress; -  /* Check we have a username and password to authenticate with and end the +  /* Check we have enough data to authenticate with and end the       connect phase if we don't */ -  if(!conn->bits.user_passwd) { +  if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {      state(conn, IMAP_STOP);      return result;    } @@ -1962,7 +1962,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn)    case SASL_AUTH_NONE:      imapc->preftype = IMAP_TYPE_NONE;      break; -  case SASL_AUTH_ANY: +  case SASL_AUTH_DEFAULT:      imapc->preftype = IMAP_TYPE_ANY;      break;    default: diff --git a/lib/pop3.c b/lib/pop3.c index a7213a44e..d3b59f249 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -543,9 +543,9 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)    struct pop3_conn *pop3c = &conn->proto.pop3c;    saslprogress progress = SASL_IDLE; -  /* Check we have a username and password to authenticate with and end the +  /* Check we have enough data to authenticate with and end the       connect phase if we don't */ -  if(!conn->bits.user_passwd) { +  if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {      state(conn, POP3_STOP);      return result;    } @@ -1425,7 +1425,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)      case SASL_AUTH_NONE:        pop3c->preftype = POP3_TYPE_NONE;        break; -    case SASL_AUTH_ANY: +    case SASL_AUTH_DEFAULT:        pop3c->preftype = POP3_TYPE_ANY;        break;      default: diff --git a/lib/smtp.c b/lib/smtp.c index ca1ab2cec..550725a93 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -486,9 +486,10 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)    struct smtp_conn *smtpc = &conn->proto.smtpc;    saslprogress progress; -  /* Check we have a username and password to authenticate with, and the +  /* Check we have enough data to authenticate with, and the       server supports authentiation, and end the connect phase if not */ -  if(!conn->bits.user_passwd || !smtpc->auth_supported) { +  if(!smtpc->auth_supported || +      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {      state(conn, SMTP_STOP);      return result;    }  | 
