Esempio n. 1
0
/* Passed the value of a "(Proxy,WWW)-Authenticate: " header field.
 * Returns 0 if valid challenge was accepted; non-zero if no valid
 * challenge was found. */
static int auth_challenge(auth_session *sess, const char *value) 
{
    char *pnt, *key, *val, *hdr, sep;
    struct auth_challenge *chall = NULL, *challenges = NULL;
    int success;

    pnt = hdr = ne_strdup(value); 

    NE_DEBUG(NE_DBG_HTTPAUTH, "Got new auth challenge: %s\n", value);

    /* The header value may be made up of one or more challenges.  We
     * split it down into attribute-value pairs, then search for
     * schemes in the pair keys. */

    while (!tokenize(&pnt, &key, &val, &sep, 1)) {

	if (val == NULL) {
            auth_scheme scheme;

	    if (strcasecmp(key, "basic") == 0) {
		scheme = auth_scheme_basic;
	    } else if (strcasecmp(key, "digest") == 0) {
		scheme = auth_scheme_digest;
            }
#ifdef HAVE_GSSAPI
            else if (strcasecmp(key, "negotiate") == 0) {
                scheme = auth_scheme_gssapi;
            }
#else
#ifdef HAVE_SSPI
            else if (strcasecmp(key, "negotiate") == 0) {
                scheme = auth_scheme_sspi_negotiate;
            } else if (strcasecmp(key, "ntlm") == 0) {
                scheme = auth_scheme_sspi_ntlm;
            }
#endif
#endif
            else {
		NE_DEBUG(NE_DBG_HTTPAUTH, "Ignoring challenge '%s'.\n", key);
                chall = NULL;
                continue;
	    }
            
            NE_DEBUG(NE_DBG_HTTPAUTH, "New '%s' challenge.\n", key);
            chall = ne_calloc(sizeof *chall);
            chall->scheme = scheme;
            chall->next = challenges;
            challenges = chall;

            if (sep == ' ' && 
                (scheme == auth_scheme_gssapi 
                 || scheme == auth_scheme_sspi_negotiate 
                 || scheme == auth_scheme_sspi_ntlm) ) {
                /* Cope with the fact that the unquoted base64
                 * paramater token doesn't match the 2617 auth-param
                 * grammar: */
                chall->opaque = ne_shave(ne_token(&pnt, ','), " \t");
                NE_DEBUG(NE_DBG_HTTPAUTH, "auth: Negotiate parameter '%s'\n",
                         chall->opaque);
                if (!pnt) break; /* stop parsing at end-of-string. */
            }
	    continue;
	} else if (chall == NULL) {
	    /* Ignore pairs for an unknown challenge. */
            NE_DEBUG(NE_DBG_HTTPAUTH, "Ignored pair: %s = %s\n", key, val);
	    continue;
	}

	/* Strip quotes off value. */
	val = ne_shave(val, "\"'");

	NE_DEBUG(NE_DBG_HTTPAUTH, "Got pair: [%s] = [%s]\n", key, val);

	if (strcasecmp(key, "realm") == 0) {
	    chall->realm = val;
	} else if (strcasecmp(key, "nonce") == 0) {
	    chall->nonce = val;
	} else if (strcasecmp(key, "opaque") == 0) {
	    chall->opaque = val;
	} else if (strcasecmp(key, "stale") == 0) {
	    /* Truth value */
	    chall->stale = (strcasecmp(val, "true") == 0);
	} else if (strcasecmp(key, "algorithm") == 0) {
	    if (strcasecmp(val, "md5") == 0) {
		chall->alg = auth_alg_md5;
	    } else if (strcasecmp(val, "md5-sess") == 0) {
		chall->alg = auth_alg_md5_sess;
	    } else {
		chall->alg = auth_alg_unknown;
	    }
	} else if (strcasecmp(key, "qop") == 0) {
            /* iterate over each token in the value */
            do {
                const char *tok = ne_shave(ne_token(&val, ','), " \t");
                
                if (strcasecmp(tok, "auth") == 0) {
                    chall->qop_auth = 1;
                }
            } while (val);
            
            chall->got_qop = chall->qop_auth;
	}
    }

    NE_DEBUG(NE_DBG_HTTPAUTH, "Finished parsing parameters.\n");

    /* Did we find any challenges */
    if (challenges == NULL) {
	ne_free(hdr);
	return -1;
    }
    
    success = 0;

#ifdef HAVE_GSSAPI
    /* Ignore Negotiate challenges from origin servers which don't
     * come over SSL. */
    if (sess->spec == &ah_proxy_class || sess->context != AUTH_ANY) {
        NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for GSSAPI.\n");
        /* Try a GSSAPI challenge */
        for (chall = challenges; chall != NULL; chall = chall->next) {
            if (chall->scheme == auth_scheme_gssapi) {
                if (!gssapi_challenge(sess, chall)) {
                    success = 1;
                    break;
                }
            }
        }
    }
#endif

#ifdef HAVE_SSPI
    if (!success) {
        NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for SSPI/Negotiate.\n");
        for (chall = challenges; chall != NULL; chall = chall->next)  {
            if (chall->scheme == auth_scheme_sspi_negotiate) {
                if (!sspi_challenge(sess, chall, 0)) {
                    success = 1;
                    break;
                }
            }
        }
    }
    
    if (!success) {
        NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for SSPI/NTLM.\n");
        for (chall = challenges; chall != NULL; chall = chall->next) {
            if (chall->scheme == auth_scheme_sspi_ntlm) {
                if (!sspi_challenge(sess, chall, 1)) {
                    success = 1;
                    break;
                }
            }
        }
    }
#endif

    /* Try a digest challenge */
    if (!success) {
        NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for Digest challenges.\n");
        for (chall = challenges; chall != NULL; chall = chall->next) {
        	if (chall->scheme == auth_scheme_digest) {
        	    if (!digest_challenge(sess, chall)) {
        		success = 1;
        		break;
        	    }
        	}
        }
    }

    if (!success) {
	NE_DEBUG(NE_DBG_HTTPAUTH, 
		 "No good Digest challenges, looking for Basic.\n");
	for (chall = challenges; chall != NULL; chall = chall->next) {
	    if (chall->scheme == auth_scheme_basic) {
		if (!basic_challenge(sess, chall)) {
		    success = 1;
		    break;
		}
	    }
	}

	if (!success) {
	    /* No good challenges - record this in the session state */
	    NE_DEBUG(NE_DBG_HTTPAUTH, "Did not understand any challenges.\n");
	}

    }
    
    /* Remember whether we can now supply the auth details */
    sess->can_handle = success;

    while (challenges != NULL) {
	chall = challenges->next;
	ne_free(challenges);
	challenges = chall;
    }

    ne_free(hdr);

    return !success;
}
Esempio n. 2
0
/* A new challenge presented by the server */
int http_auth_challenge(http_auth_session *sess, const char *value) 
{
    char **pairs, *pnt, *unquoted, *key;
    struct http_auth_chall *chall = NULL, *challenges = NULL;
    int n, success;

    DEBUG(DEBUG_HTTPAUTH, "Got new auth challenge: %s\n", value);

    /* The header value may be made up of one or more challenges.
     * We split it down into attribute-value pairs, then search for
     * schemes in the pair keys.
     */
    pairs = pair_string(value, ',', '=', HTTP_QUOTES, HTTP_WHITESPACE);

    for (n = 0; pairs[n]!=NULL; n+=2) {
	/* Look for an auth-scheme in the key */
	pnt = strchr(pairs[n], ' ');
	if (pnt != NULL) {
	    /* We have a new challenge */
	    DEBUG(DEBUG_HTTPAUTH, "New challenge.\n");
	    chall = ne_calloc(sizeof *chall);

	    chall->next = challenges;
	    challenges = chall;
	    /* Initialize the challenge parameters */
	    /* Which auth-scheme is it (case-insensitive matching) */
	    if (strncasecmp(pairs[n], "basic ", 6) == 0) {
		DEBUG(DEBUG_HTTPAUTH, "Basic scheme.\n");
		chall->scheme = http_auth_scheme_basic;
	    } else if (strncasecmp(pairs[n], "digest ", 7) == 0) {
		DEBUG(DEBUG_HTTPAUTH, "Digest scheme.\n");
		chall->scheme = http_auth_scheme_digest;
	    } else {
		DEBUG(DEBUG_HTTPAUTH, "Unknown scheme.\n");
		free(chall);
		challenges = NULL;
		break;
	    }
	    /* Now, the real key for this pair starts after the 
	     * auth-scheme... skipping whitespace */
	    while (strchr(HTTP_WHITESPACE, *(++pnt)) != NULL)
		/* nullop */;
	    key = pnt;
	} else if (chall == NULL) {
	    /* If we haven't got an auth-scheme, and we're
	     * haven't yet found a challenge, skip this pair.
	     */
	    continue;
	} else {
	    key = pairs[n];
	}
	DEBUG(DEBUG_HTTPAUTH, "Got pair: [%s] = [%s]\n", key, pairs[n+1]);
	/* Most values are quoted, so unquote them here */
	unquoted = shave_string(pairs[n+1], '"');
	/* Now parse the attribute */
	DEBUG(DEBUG_HTTPAUTH, "Unquoted pair is: [%s]\n", unquoted);
	if (strcasecmp(key, "realm") == 0) {
	    chall->realm = pairs[n+1];
	} else if (strcasecmp(key, "nonce") == 0) {
	    chall->nonce = pairs[n+1];
	} else if (strcasecmp(key, "opaque") == 0) {
	    chall->opaque = pairs[n+1];
	} else if (strcasecmp(key, "domain") == 0) {
	    chall->domain = pairs[n+1];
	} else if (strcasecmp(key, "stale") == 0) {
	    /* Truth value */
	    chall->stale = 
		(strcasecmp(unquoted, "true") == 0);
	} else if (strcasecmp(key, "algorithm") == 0) {
	    if (strcasecmp(unquoted, "md5") == 0) {
		chall->alg = http_auth_alg_md5;
	    } else if (strcasecmp(unquoted, "md5-sess") == 0) {
		chall->alg = http_auth_alg_md5_sess;
	    } else {
		chall->alg = http_auth_alg_unknown;
	    }
	} else if (strcasecmp(key, "qop") == 0) {
	    char **qops;
	    int qop;
	    qops = split_string(unquoted, ',', NULL, HTTP_WHITESPACE);
	    chall->got_qop = 1;
	    for (qop = 0; qops[qop] != NULL; qop++) {
		if (strcasecmp(qops[qop], "auth") == 0) {
		    chall->qop_auth = 1;
		} else if (strcasecmp(qops[qop], "auth-int") == 0) {
		    chall->qop_auth_int = 1;
		}
	    }
	    split_string_free(qops);
	}
	free(unquoted);
    }

    DEBUG(DEBUG_HTTPAUTH, "Finished parsing parameters.\n");

    /* Did we find any challenges */
    if (challenges == NULL) {
	pair_string_free(pairs);
	return -1;
    }
    
    success = 0;

    DEBUG(DEBUG_HTTPAUTH, "Looking for Digest challenges.\n");

    /* Try a digest challenge */
    for (chall = challenges; chall != NULL; chall = chall->next) {
	if (chall->scheme == http_auth_scheme_digest) {
	    if (!digest_challenge(sess, chall)) {
		success = 1;
		break;
	    }
	}
    }

    if (!success) {
	DEBUG(DEBUG_HTTPAUTH, "No good Digest challenges, looking for Basic.\n");
	for (chall = challenges; chall != NULL; chall = chall->next) {
	    if (chall->scheme == http_auth_scheme_basic) {
		if (!basic_challenge(sess, chall)) {
		    success = 1;
		    break;
		}
	    }
	}

	if (!success) {
	    /* No good challenges - record this in the session state */
	    DEBUG(DEBUG_HTTPAUTH, "Did not understand any challenges.\n");
	}

    }
    
    /* Remember whether we can now supply the auth details */
    sess->can_handle = success;

    while (challenges != NULL) {
	chall = challenges->next;
	free(challenges);
	challenges = chall;
    }

    /* Free up the parsed header values */
    pair_string_free(pairs);

    return !success;
}