/* 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 }
/* 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; }
/* * 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; }
/* * 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; }
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; }