]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HelperReply.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / HelperReply.cc
CommitLineData
ab332e27
AJ
1/*
2 * DEBUG: section 84 Helper process maintenance
3 * AUTHOR: Amos Jeffries
4 */
0272dd08 5#include "squid.h"
7bbefa01 6#include "ConfigParser.h"
602d9612 7#include "Debug.h"
0272dd08 8#include "helper.h"
602d9612 9#include "HelperReply.h"
7bbefa01 10#include "rfc1738.h"
ab332e27 11#include "SquidString.h"
0272dd08 12
05e52854 13HelperReply::HelperReply(char *buf, size_t len) :
0272dd08
AJ
14 result(HelperReply::Unknown),
15 whichServer(NULL)
7bbefa01 16{
05e52854 17 parse(buf,len);
7bbefa01
AJ
18}
19
20void
05e52854 21HelperReply::parse(char *buf, size_t len)
0272dd08 22{
602fab5b 23 debugs(84, 3, "Parsing helper buffer");
0272dd08 24 // check we have something to parse
e166785a 25 if (!buf || len < 1) {
aef3208d
AJ
26 // empty line response was the old URL-rewriter interface ERR response.
27 result = HelperReply::Error;
e166785a 28 // for now ensure that legacy handlers are not presented with NULL strings.
602fab5b 29 debugs(84, 3, "Reply length is smaller than 1 or none at all ");
e166785a
AJ
30 other_.init(1,1);
31 other_.terminate();
0272dd08 32 return;
e166785a 33 }
0272dd08 34
7bbefa01 35 char *p = buf;
723fd4c1 36 bool sawNA = false;
0272dd08 37
e166785a
AJ
38 // optimization: do not consider parsing result code if the response is short.
39 // URL-rewriter may return relative URLs or empty response for a large portion
40 // of its replies.
0272dd08 41 if (len >= 2) {
602fab5b 42 debugs(84, 3, "Buff length is larger than 2");
0272dd08 43 // some helper formats (digest auth, URL-rewriter) just send a data string
e166785a
AJ
44 // we must also check for the ' ' character after the response token (if anything)
45 if (!strncmp(p,"OK",2) && (len == 2 || p[2] == ' ')) {
602fab5b 46 debugs(84, 3, "helper Result = OK");
0272dd08
AJ
47 result = HelperReply::Okay;
48 p+=2;
e166785a 49 } else if (!strncmp(p,"ERR",3) && (len == 3 || p[3] == ' ')) {
602fab5b 50 debugs(84, 3, "helper Result = ERR");
0272dd08
AJ
51 result = HelperReply::Error;
52 p+=3;
e166785a 53 } else if (!strncmp(p,"BH",2) && (len == 2 || p[2] == ' ')) {
602fab5b 54 debugs(84, 3, "helper Result = BH");
0272dd08
AJ
55 result = HelperReply::BrokenHelper;
56 p+=2;
57 } else if (!strncmp(p,"TT ",3)) {
58 // NTLM challenge token
59 result = HelperReply::TT;
e166785a 60 p+=3;
d850d8ee 61 // followed by an auth token
7bbefa01 62 char *w1 = strwordtok(NULL, &p);
b7719af4
AJ
63 if (w1 != NULL) {
64 MemBuf authToken;
65 authToken.init();
66 authToken.append(w1, strlen(w1));
fd7f26ea 67 notes.add("token",authToken.content());
b7719af4
AJ
68 } else {
69 // token field is mandatory on this response code
70 result = HelperReply::BrokenHelper;
fd7f26ea 71 notes.add("message","Missing 'token' data");
b7719af4 72 }
7bbefa01 73
0272dd08 74 } else if (!strncmp(p,"AF ",3)) {
e082eaba 75 // NTLM/Negotate OK response
7bbefa01 76 result = HelperReply::Okay;
e082eaba 77 p+=3;
0b7a812f 78 // followed by:
7bbefa01 79 // an optional auth token and user field
0b7a812f 80 // or, an optional username field
7bbefa01
AJ
81 char *w1 = strwordtok(NULL, &p);
82 char *w2 = strwordtok(NULL, &p);
83 if (w2 != NULL) {
84 // Negotiate "token user"
85 MemBuf authToken;
0b7a812f 86 authToken.init();
7bbefa01 87 authToken.append(w1, strlen(w1));
fd7f26ea 88 notes.add("token",authToken.content());
7bbefa01
AJ
89
90 MemBuf user;
0b7a812f 91 user.init();
7bbefa01 92 user.append(w2,strlen(w2));
fd7f26ea 93 notes.add("user",user.content());
7bbefa01
AJ
94
95 } else if (w1 != NULL) {
96 // NTLM "user"
97 MemBuf user;
0b7a812f 98 user.init();
7bbefa01 99 user.append(w1,strlen(w1));
fd7f26ea 100 notes.add("user",user.content());
e082eaba 101 }
0272dd08
AJ
102 } else if (!strncmp(p,"NA ",3)) {
103 // NTLM fail-closed ERR response
7bbefa01 104 result = HelperReply::Error;
e166785a 105 p+=3;
723fd4c1 106 sawNA=true;
0272dd08
AJ
107 }
108
dacb64b9 109 for (; xisspace(*p); ++p); // skip whitespace
0272dd08
AJ
110 }
111
112 const mb_size_t blobSize = (buf+len-p);
e166785a 113 other_.init(blobSize+1, blobSize+1);
0272dd08
AJ
114 other_.append(p, blobSize); // remainders of the line.
115
116 // NULL-terminate so the helper callback handlers do not buffer-overrun
117 other_.terminate();
ab332e27 118
723fd4c1
AJ
119 // Hack for backward-compatibility: Do not parse for kv-pairs on NA response
120 if (!sawNA)
121 parseResponseKeys();
7bbefa01 122
723fd4c1
AJ
123 // Hack for backward-compatibility: BH and NA used to be a text message...
124 if (other().hasContent() && (sawNA || result == HelperReply::BrokenHelper)) {
fd7f26ea 125 notes.add("message",other().content());
7bbefa01 126 modifiableOther().clean();
ab332e27
AJ
127 }
128}
129
7bbefa01 130void
05e52854 131HelperReply::parseResponseKeys()
ab332e27 132{
7bbefa01 133 // parse a "key=value" pair off the 'other()' buffer.
1d972b9a 134 while (other().hasContent()) {
7bbefa01 135 char *p = modifiableOther().content();
1d972b9a 136 while (*p && *p != '=' && *p != ' ') ++p;
7bbefa01
AJ
137 if (*p != '=')
138 return; // done. Not a key.
139
24eac830
AJ
140 // whitespace between key and value is prohibited.
141 // workaround strwordtok() which skips whitespace prefix.
142 if (xisspace(*(p+1)))
143 return; // done. Not a key.
144
7bbefa01
AJ
145 *p = '\0';
146 ++p;
147
cf9f0261 148 const char *key = other().content();
7bbefa01
AJ
149
150 // the value may be a quoted string or a token
05e52854 151 const bool urlDecode = (*p != '"'); // check before moving p.
7bbefa01 152 char *v = strwordtok(NULL, &p);
05e52854 153 if (v != NULL && urlDecode && (p-v) > 2) // 1-octet %-escaped requires 3 bytes
7bbefa01 154 rfc1738_unescape(v);
7bbefa01 155
cf9f0261 156 notes.add(key, v ? v : ""); // value can be empty, but must not be NULL
7bbefa01
AJ
157
158 modifiableOther().consume(p - other().content());
24eac830 159 modifiableOther().consumeWhitespacePrefix();
ab332e27 160 }
0272dd08
AJ
161}
162
163std::ostream &
164operator <<(std::ostream &os, const HelperReply &r)
165{
166 os << "{result=";
154be258 167 switch (r.result) {
0272dd08
AJ
168 case HelperReply::Okay:
169 os << "OK";
170 break;
171 case HelperReply::Error:
172 os << "ERR";
ab332e27 173 break;
0272dd08
AJ
174 case HelperReply::BrokenHelper:
175 os << "BH";
176 break;
177 case HelperReply::TT:
178 os << "TT";
179 break;
0272dd08
AJ
180 case HelperReply::Unknown:
181 os << "Unknown";
182 break;
183 }
184
7bbefa01 185 // dump the helper key=pair "notes" list
cf9f0261 186 if (!r.notes.empty()) {
7bbefa01 187 os << ", notes={";
7e6ef752 188 os << r.notes.toString("; ");
7bbefa01
AJ
189 os << "}";
190 }
191
0272dd08
AJ
192 if (r.other().hasContent())
193 os << ", other: \"" << r.other().content() << '\"';
194
195 os << '}';
196
197 return os;
198}