MemBuf authToken;
authToken.init();
authToken.append(w1, strlen(w1));
- responseKeys.add("token",authToken.content());
+ notes.add("token",authToken.content());
} else {
// token field is mandatory on this response code
result = HelperReply::BrokenHelper;
- responseKeys.add("message","Missing 'token' data");
+ notes.add("message","Missing 'token' data");
}
} else if (!strncmp(p,"AF ",3)) {
MemBuf authToken;
authToken.init();
authToken.append(w1, strlen(w1));
- responseKeys.add("token",authToken.content());
+ notes.add("token",authToken.content());
MemBuf user;
user.init();
user.append(w2,strlen(w2));
- responseKeys.add("user",user.content());
+ notes.add("user",user.content());
} else if (w1 != NULL) {
// NTLM "user"
MemBuf user;
user.init();
user.append(w1,strlen(w1));
- responseKeys.add("user",user.content());
+ notes.add("user",user.content());
}
} else if (!strncmp(p,"NA ",3)) {
// NTLM fail-closed ERR response
// Hack for backward-compatibility: BH used to be a text message...
if (other().hasContent() && result == HelperReply::BrokenHelper) {
- responseKeys.add("message",other().content());
+ notes.add("message",other().content());
modifiableOther().clean();
}
}
char *v = strwordtok(NULL, &p);
if (v != NULL && urlDecode && (p-v) > 2) // 1-octet %-escaped requires 3 bytes
rfc1738_unescape(v);
- String value = v;
+ const String value(v?v:""); // value can be empty, but must not be NULL
- responseKeys.add(key, value);
+ notes.add(key, value);
modifiableOther().consume(p - other().content());
modifiableOther().consumeWhitespacePrefix();
}
// dump the helper key=pair "notes" list
- if (r.responseKeys.notes.size() > 0) {
+ if (r.notes.notes.size() > 0) {
os << ", notes={";
- for (Notes::NotesList::const_iterator m = r.responseKeys.notes.begin(); m != r.responseKeys.notes.end(); ++m) {
+ for (Notes::NotesList::const_iterator m = r.notes.notes.begin(); m != r.notes.notes.end(); ++m) {
for (Note::Values::iterator v = (*m)->values.begin(); v != (*m)->values.end(); ++v) {
os << ',' << (*m)->key << '=' << ConfigParser::QuoteString((*v)->value);
}
HelperReply &operator =(const HelperReply &r);
public:
- HelperReply() : result(HelperReply::Unknown), responseKeys(), whichServer(NULL) {
+ HelperReply() : result(HelperReply::Unknown), notes(), whichServer(NULL) {
other_.init(1,1);
other_.terminate();
}
MemBuf &modifiableOther() const { return *const_cast<MemBuf*>(&other_); }
/** parse a helper response line format:
- * line := [ result ] *#( key-pair )
- * key-pair := OWS token '=' ( quoted-string | token )
+ * line := [ result ] *#( kv-pair )
+ * kv-pair := OWS token '=' ( quoted-string | token )
*
* token are URL-decoded.
* quoted-string are \-escape decoded and the quotes are stripped.
BrokenHelper, // "BH" indicating failure due to helper internal problems.
// result codes for backward compatibility with NTLM/Negotiate
- // TODO: migrate to a variant of the above results with key-pair parameters
+ // TODO: migrate to a variant of the above results with kv-pair parameters
TT
} result;
// list of key=value pairs the helper produced
- Notes responseKeys;
+ Notes notes;
/// for stateful replies the responding helper 'server' needs to be preserved across callbacks
CbcPointer<helper_stateful_server> whichServer;
}
Note::Pointer
-Notes::findByName(const String ¬eKey) const
+Notes::find(const String ¬eKey) const
{
typedef Notes::NotesList::const_iterator AMLI;
for (AMLI i = notes.begin(); i != notes.end(); ++i) {
Note::Pointer
Notes::add(const String ¬eKey)
{
- Note::Pointer note = findByName(noteKey);
+ Note::Pointer note = find(noteKey);
if (note == NULL) {
note = new Note(noteKey);
notes.push_back(note);
* or NULL if none matches.
*/
const char *match(HttpRequest *request, HttpReply *reply);
+
+ /**
+ * Returns the first value for this key or an empty string.
+ */
+ const char *firstValue() const { return (values.size()>0&&values[0]->value.defined()?values[0]->value.termedBuf():""); }
+
String key; ///< The note key
Values values; ///< The possible values list for the note
};
/// return true if the notes list is empty
bool empty() { return notes.empty(); }
+ /**
+ * Adds a note key and value to the notes list.
+ * If the key name already exists in list, add the given value to its set of values.
+ */
+ void add(const String ¬eKey, const String ¬eValue);
+
+ /**
+ * Returns a pointer to an existing Note with given key name or nil.
+ */
+ Note::Pointer find(const String ¬eKey) const;
+
NotesList notes; ///< The Note::Pointer objects array list
const char *descr; ///< A short description for notes list
const char **blacklisted; ///< Null terminated list of blacklisted note keys
+
private:
/**
* Adds a note to the notes list and returns a pointer to the
*/
Note::Pointer add(const String ¬eKey);
-public:
- /**
- * Adds a note key and value to the notes list.
- * If the key name already exists in list, add the given value to its set of values.
- */
- void add(const String ¬eKey, const String ¬eValue);
-
- /**
- * Looks up a note by key name and returns a Note::Pointer to it
- */
- Note::Pointer findByName(const String ¬eKey) const;
};
class NotePairs : public HttpHeader
Auth::Digest::User *digest_user = dynamic_cast<Auth::Digest::User *>(auth_user_request->user().getRaw());
assert(digest_user != NULL);
- Note::Pointer ha1Note = reply.responseKeys.findByName("ha1");
+ Note::Pointer ha1Note = reply.notes.find("ha1");
if (ha1Note != NULL) {
- CvtBin(ha1Note->values[0]->value.termedBuf(), digest_user->HA1);
+ CvtBin(ha1Note->firstValue(), digest_user->HA1);
digest_user->HA1created = 1;
} else {
debugs(29, DBG_IMPORTANT, "ERROR: Digest auth helper did not produce a HA1. Using the wrong helper program? received: " << reply);
digest_request->user()->credentials(Auth::Failed);
digest_request->flags.invalid_password = 1;
- Note::Pointer msgNote = reply.responseKeys.findByName("message");
+ Note::Pointer msgNote = reply.notes.find("message");
if (msgNote != NULL) {
- digest_request->setDenyMessage(msgNote->values[0]->value.termedBuf());
+ digest_request->setDenyMessage(msgNote->firstValue());
} else if (reply.other().hasContent()) {
// old helpers did send ERR result but a bare message string instead of message= key name.
digest_request->setDenyMessage(reply.other().content());
safe_free(lm_request->server_blob);
lm_request->request->flags.mustKeepalive = 1;
if (lm_request->request->flags.proxyKeepalive) {
- Note::Pointer tokenNote = reply.responseKeys.findByName("token");
- lm_request->server_blob = xstrdup(tokenNote->values[0]->value.termedBuf());
+ Note::Pointer tokenNote = reply.notes.find("token");
+ lm_request->server_blob = xstrdup(tokenNote->firstValue());
auth_user_request->user()->credentials(Auth::Handshake);
auth_user_request->denyMessage("Authentication in progress");
- debugs(29, 4, HERE << "Need to challenge the client with a server token: '" << tokenNote->values[0]->value << "'");
+ debugs(29, 4, HERE << "Need to challenge the client with a server token: '" << tokenNote->firstValue() << "'");
} else {
auth_user_request->user()->credentials(Auth::Failed);
auth_user_request->denyMessage("Negotiate authentication requires a persistent connection");
break;
case HelperReply::Okay: {
- Note::Pointer userNote = reply.responseKeys.findByName("user");
- Note::Pointer tokenNote = reply.responseKeys.findByName("token");
+ Note::Pointer userNote = reply.notes.find("user");
+ Note::Pointer tokenNote = reply.notes.find("token");
if (userNote == NULL || tokenNote == NULL) {
// XXX: handle a success with no username better
/* protocol error */
}
/* we're finished, release the helper */
- auth_user_request->user()->username(userNote->values[0]->value.termedBuf());
+ auth_user_request->user()->username(userNote->firstValue());
auth_user_request->denyMessage("Login successful");
safe_free(lm_request->server_blob);
- lm_request->server_blob = xstrdup(tokenNote->values[0]->value.termedBuf());
+ lm_request->server_blob = xstrdup(tokenNote->firstValue());
lm_request->releaseAuthServer();
/* connection is authenticated */
break;
case HelperReply::Error: {
- Note::Pointer messageNote = reply.responseKeys.findByName("message");
- Note::Pointer tokenNote = reply.responseKeys.findByName("token");
+ Note::Pointer messageNote = reply.notes.find("message");
+ Note::Pointer tokenNote = reply.notes.find("token");
if (tokenNote == NULL) {
/* protocol error */
fatalf("authenticateNegotiateHandleReply: *** Unsupported helper response ***, '%s'\n", reply.other().content());
}
/* authentication failure (wrong password, etc.) */
- auth_user_request->denyMessage(messageNote->values[0]->value.termedBuf());
+ auth_user_request->denyMessage(messageNote->firstValue());
auth_user_request->user()->credentials(Auth::Failed);
safe_free(lm_request->server_blob);
- lm_request->server_blob = xstrdup(tokenNote->values[0]->value.termedBuf());
+ lm_request->server_blob = xstrdup(tokenNote->firstValue());
lm_request->releaseAuthServer();
debugs(29, 4, HERE << "Failed validating user via Negotiate. Error returned '" << reply << "'");
}
* Authenticate Negotiate start.
* If after a KK deny the user's request w/ 407 and mark the helper as
* Needing YR. */
- Note::Pointer errNote = reply.responseKeys.findByName("message");
+ Note::Pointer errNote = reply.notes.find("message");
if (reply.result == HelperReply::Unknown)
auth_user_request->denyMessage("Internal Error");
else if (errNote != NULL)
- auth_user_request->denyMessage(errNote->values[0]->value.termedBuf());
+ auth_user_request->denyMessage(errNote->firstValue());
else
auth_user_request->denyMessage("Negotiate Authentication failed with no reason given");
auth_user_request->user()->credentials(Auth::Failed);
safe_free(lm_request->server_blob);
lm_request->request->flags.mustKeepalive = 1;
if (lm_request->request->flags.proxyKeepalive) {
- Note::Pointer serverBlob = reply.responseKeys.findByName("token");
- lm_request->server_blob = xstrdup(serverBlob->values[0]->value.termedBuf());
+ Note::Pointer serverBlob = reply.notes.find("token");
+ lm_request->server_blob = xstrdup(serverBlob->firstValue());
auth_user_request->user()->credentials(Auth::Handshake);
auth_user_request->denyMessage("Authentication in progress");
- debugs(29, 4, HERE << "Need to challenge the client with a server token: '" << serverBlob->values[0]->value << "'");
+ debugs(29, 4, HERE << "Need to challenge the client with a server token: '" << serverBlob->firstValue() << "'");
} else {
auth_user_request->user()->credentials(Auth::Failed);
auth_user_request->denyMessage("NTLM authentication requires a persistent connection");
case HelperReply::Okay: {
/* we're finished, release the helper */
- Note::Pointer userLabel = reply.responseKeys.findByName("user");
- auth_user_request->user()->username(userLabel->values[0]->value.termedBuf());
+ Note::Pointer userLabel = reply.notes.find("user");
+ auth_user_request->user()->username(userLabel->firstValue());
auth_user_request->denyMessage("Login successful");
safe_free(lm_request->server_blob);
lm_request->releaseAuthServer();
- debugs(29, 4, HERE << "Successfully validated user via NTLM. Username '" << userLabel->values[0]->value << "'");
+ debugs(29, 4, HERE << "Successfully validated user via NTLM. Username '" << userLabel->firstValue() << "'");
/* connection is authenticated */
debugs(29, 4, HERE << "authenticated user " << auth_user_request->user()->username());
/* see if this is an existing user with a different proxy_auth
case HelperReply::Error: {
/* authentication failure (wrong password, etc.) */
- Note::Pointer errNote = reply.responseKeys.findByName("message");
+ Note::Pointer errNote = reply.notes.find("message");
if (errNote != NULL)
- auth_user_request->denyMessage(errNote->values[0]->value.termedBuf());
+ auth_user_request->denyMessage(errNote->firstValue());
else
auth_user_request->denyMessage("NTLM Authentication denied with no reason given");
auth_user_request->user()->credentials(Auth::Failed);
safe_free(lm_request->server_blob);
lm_request->releaseAuthServer();
- debugs(29, 4, HERE << "Failed validating user via NTLM. Error returned '" << errNote->values[0]->value << "'");
+ debugs(29, 4, HERE << "Failed validating user via NTLM. Error returned '" << errNote->firstValue() << "'");
}
break;
* Authenticate NTLM start.
* If after a KK deny the user's request w/ 407 and mark the helper as
* Needing YR. */
- Note::Pointer errNote = reply.responseKeys.findByName("message");
+ Note::Pointer errNote = reply.notes.find("message");
if (reply.result == HelperReply::Unknown)
auth_user_request->denyMessage("Internal Error");
else if (errNote != NULL)
- auth_user_request->denyMessage(errNote->values[0]->value.termedBuf());
+ auth_user_request->denyMessage(errNote->firstValue());
else
auth_user_request->denyMessage("NTLM Authentication failed with no reason given");
auth_user_request->user()->credentials(Auth::Failed);
HelperReply failReply;
/* XXX: upgrade the ipcache and fqdn cache handlers to new syntax
failReply.result= HelperReply::BrokenHelper;
- failReply.responseKeys.add("message","Temporary network problem, please retry later");
- failReply.responseKeys.add("message","DNS lookup queue overloaded");
+ failReply.notes.add("message","Temporary network problem, please retry later");
+ failReply.notes.add("message","DNS lookup queue overloaded");
*/
failReply.modifiableOther().append(t, strlen(t));
callback(data, failReply);
entryData.result = ACCESS_ALLOWED;
// XXX: handle other non-DENIED results better
- // XXX: make entryData store a proper helperReply object.
+ // XXX: make entryData store a proper HelperReply object instead of copying.
- Note::Pointer label = reply.responseKeys.findByName("tag");
+ Note::Pointer label = reply.notes.find("tag");
if (label != NULL && label->values[0]->value.size() > 0)
entryData.tag = label->values[0]->value;
- label = reply.responseKeys.findByName("message");
+ label = reply.notes.find("message");
if (label != NULL && label->values[0]->value.size() > 0)
entryData.message = label->values[0]->value;
- label = reply.responseKeys.findByName("log");
+ label = reply.notes.find("log");
if (label != NULL && label->values[0]->value.size() > 0)
entryData.log = label->values[0]->value;
#if USE_AUTH
- label = reply.responseKeys.findByName("user");
+ label = reply.notes.find("user");
if (label != NULL && label->values[0]->value.size() > 0)
entryData.user = label->values[0]->value;
- label = reply.responseKeys.findByName("password");
+ label = reply.notes.find("password");
if (label != NULL && label->values[0]->value.size() > 0)
entryData.password = label->values[0]->value;
#endif
debugs(61, 5, HERE << "reply=" << reply);
// XXX: This funtion is now kept only to check for and display this garbage use-case
- // it can be removed when the helpers are all updated to the normalized "OK/ERR key-pairs" format
+ // it can be removed when the helpers are all updated to the normalized "OK/ERR kv-pairs" format
if (reply.result == HelperReply::Unknown) {
// BACKWARD COMPATIBILITY 2012-06-15:
++n_bypassed;
HelperReply bypassReply;
bypassReply.result = HelperReply::Okay;
- bypassReply.responseKeys.add("message","URL rewrite/redirect queue too long. Bypassed.");
+ bypassReply.notes.add("message","URL rewrite/redirect queue too long. Bypassed.");
handler(data, bypassReply);
return;
}
debugs(34, DBG_IMPORTANT, HERE << "Queue overload, rejecting");
HelperReply failReply;
failReply.result = HelperReply::BrokenHelper;
- failReply.responseKeys.add("message", "error 45 Temporary network problem, please retry later");
+ failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
callback(data, failReply);
return;
}