Beispiel #1
0
static void set_cookie_hdl(void *userdata, const char *value)
{
    char **pairs = pair_string(value, ';', '=', "\"'", " \r\n\t");
    ne_cookie *cook;
    ne_cookie_cache *cache = userdata;
    int n;

    /* Check sanity */
    if (pairs[0] == NULL || pairs[1] == NULL) {
	/* yagaboo */
	return;
    }

    NE_DEBUG(NE_DBG_HTTP, "Got cookie name=%s\n", pairs[0]);

    /* Search for a cookie of this name */
    NE_DEBUG(NE_DBG_HTTP, "Searching for existing cookie...\n");
    for (cook = cache->cookies; cook != NULL; cook = cook->next) {
	if (strcasecmp(cook->name, pairs[0]) == 0) {
	    break;
	}
    }
    
    if (cook == NULL) {
	NE_DEBUG(NE_DBG_HTTP, "New cookie.\n");
	cook = ne_malloc(sizeof *cook);
	memset(cook, 0, sizeof *cook);
	cook->name = ne_strdup(pairs[0]);
	cook->next = cache->cookies;
	cache->cookies = cook;
    } else {
	/* Free the old value */
	ne_free(cook->value);
    }

    cook->value = ne_strdup(pairs[1]);

    for (n = 2; pairs[n] != NULL; n+=2) {
	NE_DEBUG(NE_DBG_HTTP, "Cookie parm %s=%s\n", pairs[n], pairs[n+1]);
	if (strcasecmp(pairs[n], "path") == 0) {
	    cook->path = ne_strdup(pairs[n+1]);
	} else if (strcasecmp(pairs[n], "max-age") == 0) {
	    int t = atoi(pairs[n+1]);
	    cook->expiry = time(NULL) + (time_t)t;
	} else if (strcasecmp(pairs[n], "domain") == 0) {
	    cook->domain = ne_strdup(pairs[n+1]);
	}
    }

    NE_DEBUG(NE_DBG_HTTP, "End of parms.\n");

    pair_string_free(pairs);
}
Beispiel #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;
}
Beispiel #3
0
/* Pass this the value of the 'Authentication-Info:' header field, if
 * one is received.
 * Returns:
 *    0 if it gives a valid authentication for the server 
 *    non-zero otherwise (don't believe the response in this case!).
 */
int http_auth_verify_response(http_auth_session *sess, const char *value) 
{
    char **pairs;
    http_auth_qop qop = http_auth_qop_none;
    char *nextnonce = NULL, /* for the nextnonce= value */
	*rspauth = NULL, /* for the rspauth= value */
	*cnonce = NULL, /* for the cnonce= value */
	*nc = NULL, /* for the nc= value */
	*unquoted, *qop_value = NULL;
    int n, nonce_count, okay;
    
    if (!sess->will_handle) {
	/* Ignore it */
	return 0;
    }
    
    if (sess->scheme != http_auth_scheme_digest) {
	DEBUG(DEBUG_HTTPAUTH, "Found Auth-Info header not in response to Digest credentials - dodgy.\n");
	return -1;
    }
    
    DEBUG (DEBUG_HTTPAUTH, "Auth-Info header: %s\n", value);

    pairs = pair_string(value, ',', '=', HTTP_QUOTES, HTTP_WHITESPACE);
    
    for (n = 0; pairs[n]!=NULL; n+=2) {
	unquoted = shave_string(pairs[n+1], '"');
	if (strcasecmp(pairs[n], "qop") == 0) {
	    qop_value = ne_strdup(pairs[n+1]);
	    if (strcasecmp(pairs[n+1], "auth-int") == 0) {
		qop = http_auth_qop_auth_int;
	    } else if (strcasecmp(pairs[n+1], "auth") == 0) {
		qop = http_auth_qop_auth;
	    } else {
		qop = http_auth_qop_none;
	    }
	} else if (strcasecmp(pairs[n], "nextnonce") == 0) {
	    nextnonce = ne_strdup(unquoted);
	} else if (strcasecmp(pairs[n], "rspauth") == 0) {
	    rspauth = ne_strdup(unquoted);
	} else if (strcasecmp(pairs[n], "cnonce") == 0) {
	    cnonce = ne_strdup(unquoted);
	} else if (strcasecmp(pairs[n], "nc") == 0) { 
	    nc = ne_strdup(pairs[n]);
	    if (sscanf(pairs[n+1], "%x", &nonce_count) != 1) {
		DEBUG(DEBUG_HTTPAUTH, "Couldn't scan [%s] for nonce count.\n",
		       pairs[n+1]);
	    } else {
		DEBUG(DEBUG_HTTPAUTH, "Got nonce_count: %d\n", nonce_count);
	    }
	}
	free(unquoted);
    }
    pair_string_free(pairs);

    /* Presume the worst */
    okay = -1;

    if ((qop != http_auth_qop_none) && (qop_value != NULL)) {
	if ((rspauth == NULL) || (cnonce == NULL) || (nc == NULL)) {
	    DEBUG(DEBUG_HTTPAUTH, "Missing rspauth, cnonce or nc with qop.\n");
	} else { /* Have got rspauth, cnonce and nc */
	    if (strcmp(cnonce, sess->unq_cnonce) != 0) {
		DEBUG(DEBUG_HTTPAUTH, "Response cnonce doesn't match.\n");
	    } else if (nonce_count != sess->nonce_count) { 
		DEBUG(DEBUG_HTTPAUTH, "Response nonce count doesn't match.\n");
	    } else {
		/* Calculate and check the response-digest value.
		 * joe: IMO the spec is slightly ambiguous as to whether
		 * we use the qop which WE sent, or the qop which THEY
		 * sent...  */
		struct md5_ctx a2;
		unsigned char a2_md5[16], rdig_md5[16];
		char a2_md5_ascii[33], rdig_md5_ascii[33];

		DEBUG(DEBUG_HTTPAUTH, "Calculating response-digest.\n");

		/* First off, H(A2) again. */
		md5_init_ctx(&a2);
		md5_process_bytes(":", 1, &a2);
		md5_process_bytes(sess->uri, strlen(sess->uri), &a2);
		if (qop == http_auth_qop_auth_int) {
		    unsigned char heb_md5[16];
		    char heb_md5_ascii[33];
		    /* Add on ":" H(entity-body) */
		    md5_finish_ctx(&sess->response_body, heb_md5);
		    md5_to_ascii(heb_md5, heb_md5_ascii);
		    md5_process_bytes(":", 1, &a2);
		    md5_process_bytes(heb_md5_ascii, 32, &a2);
		    DEBUG(DEBUG_HTTPAUTH, "Digested [:%s]\n", heb_md5_ascii);
		}
		md5_finish_ctx(&a2, a2_md5);
		md5_to_ascii(a2_md5, a2_md5_ascii);
		
		/* We have the stored digest-so-far of 
		 *   H(A1) ":" unq(nonce-value) 
		 *        [ ":" nc-value ":" unq(cnonce-value) ] for qop
		 * in sess->stored_rdig, to save digesting them again.
		 *
		 */
		if (qop != http_auth_qop_none) {
		    /* Add in qop-value */
		    DEBUG(DEBUG_HTTPAUTH, "Digesting qop-value [%s:].\n", 
			   qop_value);
		    md5_process_bytes(qop_value, strlen(qop_value), 
				       &sess->stored_rdig);
		    md5_process_bytes(":", 1, &sess->stored_rdig);
		}
		/* Digest ":" H(A2) */
		md5_process_bytes(a2_md5_ascii, 32, &sess->stored_rdig);
		/* All done */
		md5_finish_ctx(&sess->stored_rdig, rdig_md5);
		md5_to_ascii(rdig_md5, rdig_md5_ascii);

		DEBUG(DEBUG_HTTPAUTH, "Calculated response-digest of: [%s]\n",
		       rdig_md5_ascii);
		DEBUG(DEBUG_HTTPAUTH, "Given response-digest of:      [%s]\n",
		       rspauth);

		/* And... do they match? */
		okay = (strcasecmp(rdig_md5_ascii, rspauth) == 0)?0:-1;
		DEBUG(DEBUG_HTTPAUTH, "Matched: %s\n", okay?"nope":"YES!");
	    }
	    free(rspauth);
	    free(cnonce);
	    free(nc);
	}
	free(qop_value);
    } else {
	DEBUG(DEBUG_HTTPAUTH, "No qop directive, auth okay.\n");
	okay = 0;
    }

    /* Check for a nextnonce */
    if (nextnonce != NULL) {
	DEBUG(DEBUG_HTTPAUTH, "Found nextnonce of [%s].\n", nextnonce);
	if (sess->unq_nonce != NULL)
	    free(sess->unq_nonce);
	sess->unq_nonce = nextnonce;
    }

    return okay;
}