/* returns true iff "s" is a substring of a member of the list */
int
strListIsSubstr(const String * list, const char *s, char del)
{
    assert(list && del);
    return strStr(*list, s) != 0;

    /*
     * Note: the original code with a loop is broken because it uses strstr()
     * instead of strnstr(). If 's' contains a 'del', strListIsSubstr() may
     * return true when it should not. If 's' does not contain a 'del', the
     * implementaion is equavalent to strstr()! Thus, we replace the loop with
     * strstr() above until strnstr() is available.
     */

#ifdef BROKEN_CODE
    const char *pos = NULL;
    const char *item;
    assert(list && s);
    while (strListGetItem(list, del, &item, NULL, &pos)) {
	if (strstr(item, s))
	    return 1;
    }
    return 0;
#endif
}
Esempio n. 2
0
/* returns true if ranges are valid; inits HttpHdrRange */
int
httpHdrRangeParseInit(HttpHdrRange * range, const String * str)
{
    const char *item;
    const char *pos = NULL;
    int ilen;
    int count = 0;
    assert(range && str);
    RangeParsedCount++;
    debug(64, 8) ("parsing range field: '%s'\n", strBuf(*str));
    /* check range type */
    if (strNCaseCmp(*str, "bytes=", 6))
	return 0;
    /* skip "bytes="; hack! */
    pos = strBuf(*str) + 5;
    /* iterate through comma separated list */
    while (strListGetItem(str, ',', &item, &ilen, &pos)) {
	HttpHdrRangeSpec *spec = httpHdrRangeSpecParseCreate(item, ilen);
	/*
	 * HTTP/1.1 draft says we must ignore the whole header field if one spec
	 * is invalid. However, RFC 2068 just says that we must ignore that spec.
	 */
	if (spec)
	    stackPush(&range->specs, spec);
	count++;
    }
    debug(64, 8) ("parsed range range count: %d\n", range->specs.count);
    return range->specs.count;
}
/* returns true iff "m" is a member of the list */
int
strListIsMember(const String * list, const char *m, char del)
{
    const char *pos = NULL;
    const char *item;
    int ilen = 0;
    int mlen;
    assert(list && m);
    mlen = strlen(m);
    while (strListGetItem(list, del, &item, &ilen, &pos)) {
	if (mlen == ilen && !strncasecmp(item, m, ilen))
	    return 1;
    }
    return 0;
}
Esempio n. 4
0
/*
 * returns a pointer to a specified entry if any 
 * note that we return one entry so it does not make much sense to ask for
 * "list" headers
 */
String
httpHeaderGetByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator)
{
    String result = StringNull;
    String header;
    const char *pos = NULL;
    const char *item;
    int ilen;
    int mlen = strlen(member);

    assert(hdr);
    assert(name);

    header = httpHeaderGetByName(hdr, name);

    while (strListGetItem(&header, separator, &item, &ilen, &pos)) {
	if (strncmp(item, member, mlen) == 0 && item[mlen] == '=') {
	    stringAppend(&result, item + mlen + 1, ilen - mlen - 1);
	    break;
	}
    }
    return result;
}
Esempio n. 5
0
/*
 * returns a the value of the specified list member, if any.
 */
String
httpHeaderGetListMember(const HttpHeader * hdr, http_hdr_type id, const char *member, const char separator)
{
    String result = StringNull;
    String header;
    const char *pos = NULL;
    const char *item;
    int ilen;
    int mlen = strlen(member);

    assert(hdr);
    assert_eid(id);

    header = httpHeaderGetStrOrList(hdr, id);

    while (strListGetItem(&header, separator, &item, &ilen, &pos)) {
	if (strncmp(item, member, mlen) == 0 && item[mlen] == '=') {
	    stringAppend(&result, item + mlen + 1, ilen - mlen - 1);
	    break;
	}
    }
    stringClean(&header);
    return result;
}
Esempio n. 6
0
static void
authenticateDigestDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
{
    String temp;
    const char *item;
    const char *p;
    const char *pos = NULL;
    char *username = NULL;
    digest_nonce_h *nonce;
    int ilen;
    digest_request_h *digest_request;
    digest_user_h *digest_user;
    auth_user_t *auth_user;
    dlink_node *node;

    debug(29, 9) ("authenticateDigestDecodeAuth: beginning\n");
    assert(auth_user_request != NULL);

    digest_request = authDigestRequestNew();

    /* trim DIGEST from string */
    while (xisgraph(*proxy_auth))
	proxy_auth++;

    /* Trim leading whitespace before decoding */
    while (xisspace(*proxy_auth))
	proxy_auth++;

    stringInit(&temp, proxy_auth);
    while (strListGetItem(&temp, ',', &item, &ilen, &pos)) {
	if ((p = strchr(item, '=')) && (p - item < ilen))
	    ilen = p++ - item;
	if (!strncmp(item, "username", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    username = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found Username '%s'\n", username);
	} else if (!strncmp(item, "realm", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->realm = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found realm '%s'\n", digest_request->realm);
	} else if (!strncmp(item, "qop", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    if (*p == '\"')
		/* quote mark */
		p++;
	    digest_request->qop = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1);
	    debug(29, 9) ("authDigestDecodeAuth: Found qop '%s'\n", digest_request->qop);
	} else if (!strncmp(item, "algorithm", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    if (*p == '\"')
		/* quote mark */
		p++;
	    digest_request->algorithm = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1);
	    debug(29, 9) ("authDigestDecodeAuth: Found algorithm '%s'\n", digest_request->algorithm);
	} else if (!strncmp(item, "uri", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->uri = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found uri '%s'\n", digest_request->uri);
	} else if (!strncmp(item, "nonce", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->nonceb64 = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found nonce '%s'\n", digest_request->nonceb64);
	} else if (!strncmp(item, "nc", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    xstrncpy(digest_request->nc, p, 9);
	    debug(29, 9) ("authDigestDecodeAuth: Found noncecount '%s'\n", digest_request->nc);
	} else if (!strncmp(item, "cnonce", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->cnonce = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found cnonce '%s'\n", digest_request->cnonce);
	} else if (!strncmp(item, "response", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->response = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found response '%s'\n", digest_request->response);
	}
    }
    stringClean(&temp);


    /* now we validate the data given to us */

    /*
     * TODO: on invalid parameters we should return 400, not 407.
     * Find some clean way of doing this. perhaps return a valid
     * struct, and set the direction to clientwards combined with
     * a change to the clientwards handling code (ie let the
     * clientwards call set the error type (but limited to known
     * correct values - 400/401/407
     */

    /* first the NONCE count */
    if (digest_request->cnonce && strlen(digest_request->nc) != 8) {
	debug(29, 4) ("authenticateDigestDecode: nonce count length invalid\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* now the nonce */
    nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
    if (!nonce) {
	/* we couldn't find a matching nonce! */
	debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    digest_request->nonce = nonce;
    authDigestNonceLink(nonce);

    /* check the qop is what we expected. Note that for compatability with 
     * RFC 2069 we should support a missing qop. Tough. */
    if (!digest_request->qop || strcmp(digest_request->qop, QOP_AUTH)) {
	/* we recieved a qop option we didn't send */
	debug(29, 4) ("authenticateDigestDecode: Invalid qop option recieved\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* we can't check the URI just yet. We'll check it in the
     * authenticate phase */

    /* is the response the correct length? */

    if (!digest_request->response || strlen(digest_request->response) != 32) {
	debug(29, 4) ("authenticateDigestDecode: Response length invalid\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* do we have a username ? */
    if (!username || username[0] == '\0') {
	debug(29, 4) ("authenticateDigestDecode: Empty or not present username\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* check that we're not being hacked / the username hasn't changed */
    if (nonce->auth_user && strcmp(username, authenticateUserUsername(nonce->auth_user))) {
	debug(29, 4) ("authenticateDigestDecode: Username for the nonce does not equal the username for the request\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* if we got a qop, did we get a cnonce or did we get a cnonce wihtout a qop? */
    if ((digest_request->qop && !digest_request->cnonce)
	|| (!digest_request->qop && digest_request->cnonce)) {
	debug(29, 4) ("authenticateDigestDecode: qop without cnonce, or vice versa!\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* check the algorithm is present and supported */
    if (!digest_request->algorithm)
	digest_request->algorithm = xstrndup("MD5", 4);
    else if (strcmp(digest_request->algorithm, "MD5")
	&& strcmp(digest_request->algorithm, "MD5-sess")) {
	debug(29, 4) ("authenticateDigestDecode: invalid algorithm specified!\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* the method we'll check at the authenticate step as well */


    /* we don't send or parse opaques. Ok so we're flexable ... */

    /* find the user */

    if ((auth_user = authDigestUserFindUsername(username)) == NULL) {
	/* the user doesn't exist in the username cache yet */
	debug(29, 9) ("authDigestDecodeAuth: Creating new digest user '%s'\n", username);
	/* new auth_user */
	auth_user = authenticateAuthUserNew("digest");
	/* new scheme user data */
	digest_user = authDigestUserNew();
	/* save the username */
	digest_user->username = username;
	/* link the primary struct in */
	auth_user->scheme_data = digest_user;
	/* set the user type */
	auth_user->auth_type = AUTH_DIGEST;
	/* this auth_user struct is the one to get added to the
	 * username cache */
	/* store user in hash's */
	authenticateUserNameCacheAdd(auth_user);
	/* 
	 * Add the digest to the user so we can tell if a hacking
	 * or spoofing attack is taking place. We do this by assuming
	 * the user agent won't change user name without warning.
	 */
	authDigestUserLinkNonce(auth_user, nonce);
    } else {
	debug(29, 9) ("authDigestDecodeAuth: Found user '%s' in the user cache as '%p'\n", username, auth_user);
	digest_user = auth_user->scheme_data;
	xfree(username);
    }
    /*link the request and the user */
    auth_user_request->auth_user = auth_user;
    auth_user_request->scheme_data = digest_request;
    /* lock for the request link */
    authenticateAuthUserLock(auth_user);
    node = dlinkNodeNew();
    dlinkAdd(auth_user_request, node, &auth_user->requests);

    debug(29, 9) ("username = '******'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\ndigestnonce = '%p'\n",
	digest_user->username, digest_request->realm,
	digest_request->qop, digest_request->algorithm,
	digest_request->uri, digest_request->nonceb64,
	digest_request->nc, digest_request->cnonce, digest_request->response, nonce);

    return;
}