]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/digest/UserRequest.cc
Fix spelling and compile issues in CommIO
[thirdparty/squid.git] / src / auth / digest / UserRequest.cc
CommitLineData
f7f3304a 1#include "squid.h"
928f3421 2#include "auth/digest/auth_digest.h"
aa110616 3#include "auth/digest/User.h"
616cfc4c 4#include "auth/digest/UserRequest.h"
928f3421 5#include "auth/State.h"
25f98340 6#include "charset.h"
a5bac1d2 7#include "HttpHeaderTools.h"
928f3421
AJ
8#include "HttpReply.h"
9#include "HttpRequest.h"
10#include "SquidTime.h"
11
c7baff40 12Auth::Digest::UserRequest::UserRequest() :
928f3421
AJ
13 nonceb64(NULL),
14 cnonce(NULL),
15 realm(NULL),
16 pszPass(NULL),
17 algorithm(NULL),
18 pszMethod(NULL),
19 qop(NULL),
20 uri(NULL),
21 response(NULL),
d232141d 22 nonce(NULL)
928f3421
AJ
23{}
24
25/**
26 * Delete the digest request structure.
27 * Does NOT delete related AuthUser structures
28 */
c7baff40 29Auth::Digest::UserRequest::~UserRequest()
928f3421 30{
8bf217bd 31 assert(LockCount()==0);
ea0695f2 32
928f3421
AJ
33 safe_free(nonceb64);
34 safe_free(cnonce);
35 safe_free(realm);
36 safe_free(pszPass);
37 safe_free(algorithm);
38 safe_free(pszMethod);
39 safe_free(qop);
40 safe_free(uri);
41 safe_free(response);
42
43 if (nonce)
44 authDigestNonceUnlink(nonce);
45}
46
928f3421 47int
c7baff40 48Auth::Digest::UserRequest::authenticated() const
928f3421 49{
d87154ee 50 if (user() != NULL && user()->credentials() == Auth::Ok)
928f3421
AJ
51 return 1;
52
53 return 0;
54}
55
56/** log a digest user in
57 */
58void
c7baff40 59Auth::Digest::UserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
928f3421 60{
928f3421
AJ
61 HASHHEX SESSIONKEY;
62 HASHHEX HA2 = "";
63 HASHHEX Response;
64
928f3421 65 /* if the check has corrupted the user, just return */
d87154ee 66 if (user() == NULL || user()->credentials() == Auth::Failed) {
928f3421
AJ
67 return;
68 }
69
d87154ee 70 Auth::User::Pointer auth_user = user();
928f3421 71
aa110616 72 Auth::Digest::User *digest_user = dynamic_cast<Auth::Digest::User*>(auth_user.getRaw());
56a49fda 73 assert(digest_user != NULL);
928f3421 74
c7baff40 75 Auth::Digest::UserRequest *digest_request = this;
56a49fda
AJ
76
77 /* do we have the HA1 */
928f3421 78 if (!digest_user->HA1created) {
d87154ee 79 auth_user->credentials(Auth::Pending);
928f3421
AJ
80 return;
81 }
82
83 if (digest_request->nonce == NULL) {
84 /* this isn't a nonce we issued */
d87154ee 85 auth_user->credentials(Auth::Failed);
928f3421
AJ
86 return;
87 }
88
89 DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL,
90 authenticateDigestNonceNonceb64(digest_request->nonce),
91 digest_request->cnonce,
92 digest_user->HA1, SESSIONKEY);
93 DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
94 digest_request->nc, digest_request->cnonce, digest_request->qop,
95 RequestMethodStr(request->method), digest_request->uri, HA2, Response);
96
97 debugs(29, 9, "\nResponse = '" << digest_request->response << "'\nsquid is = '" << Response << "'");
98
99 if (strcasecmp(digest_request->response, Response) != 0) {
100 if (!digest_request->flags.helper_queried) {
101 /* Query the helper in case the password has changed */
102 digest_request->flags.helper_queried = 1;
d87154ee 103 auth_user->credentials(Auth::Pending);
928f3421
AJ
104 return;
105 }
106
c2a7cefd 107 if (static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->PostWorkaround && request->method != Http::METHOD_GET) {
928f3421
AJ
108 /* Ugly workaround for certain very broken browsers using the
109 * wrong method to calculate the request-digest on POST request.
110 * This should be deleted once Digest authentication becomes more
111 * widespread and such broken browsers no longer are commonly
112 * used.
113 */
114 DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce),
115 digest_request->nc, digest_request->cnonce, digest_request->qop,
c2a7cefd 116 RequestMethodStr(Http::METHOD_GET), digest_request->uri, HA2, Response);
928f3421
AJ
117
118 if (strcasecmp(digest_request->response, Response)) {
d87154ee 119 auth_user->credentials(Auth::Failed);
35247d59 120 digest_request->flags.invalid_password = 1;
928f3421
AJ
121 digest_request->setDenyMessage("Incorrect password");
122 return;
123 } else {
124 const char *useragent = request->header.getStr(HDR_USER_AGENT);
125
08acdd08 126 static Ip::Address last_broken_addr;
928f3421
AJ
127 static int seen_broken_client = 0;
128
129 if (!seen_broken_client) {
130 last_broken_addr.SetNoAddr();
131 seen_broken_client = 1;
132 }
133
134 if (last_broken_addr != request->client_addr) {
c7baff40 135 debugs(29, DBG_IMPORTANT, "Digest POST bug detected from " <<
928f3421
AJ
136 request->client_addr << " using '" <<
137 (useragent ? useragent : "-") <<
138 "'. Please upgrade browser. See Bug #630 for details.");
139
140 last_broken_addr = request->client_addr;
141 }
142 }
143 } else {
d87154ee 144 auth_user->credentials(Auth::Failed);
928f3421
AJ
145 digest_request->flags.invalid_password = 1;
146 digest_request->setDenyMessage("Incorrect password");
147 return;
148 }
149
150 /* check for stale nonce */
151 if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) {
c7baff40 152 debugs(29, 3, HERE << "user '" << auth_user->username() << "' validated OK but nonce stale");
d87154ee 153 auth_user->credentials(Auth::Failed);
928f3421
AJ
154 digest_request->setDenyMessage("Stale nonce");
155 return;
156 }
157 }
158
d87154ee 159 auth_user->credentials(Auth::Ok);
928f3421
AJ
160
161 /* password was checked and did match */
c7baff40 162 debugs(29, 4, HERE << "user '" << auth_user->username() << "' validated OK");
928f3421
AJ
163
164 /* auth_user is now linked, we reset these values
165 * after external auth occurs anyway */
166 auth_user->expiretime = current_time.tv_sec;
167 return;
168}
169
51a3dd58 170Auth::Direction
c7baff40 171Auth::Digest::UserRequest::module_direction()
928f3421 172{
616cfc4c 173 if (user()->auth_type != Auth::AUTH_DIGEST)
51a3dd58 174 return Auth::CRED_ERROR;
928f3421 175
d232141d 176 switch (user()->credentials()) {
928f3421 177
d87154ee 178 case Auth::Ok:
51a3dd58 179 return Auth::CRED_VALID;
928f3421 180
d87154ee 181 case Auth::Failed:
928f3421 182 /* send new challenge */
51a3dd58 183 return Auth::CRED_CHALLENGE;
d232141d 184
d87154ee
AJ
185 case Auth::Unchecked:
186 case Auth::Pending:
51a3dd58 187 return Auth::CRED_LOOKUP;
d232141d
AJ
188
189 default:
51a3dd58 190 return Auth::CRED_ERROR;
928f3421 191 }
928f3421
AJ
192}
193
928f3421 194void
c7baff40 195Auth::Digest::UserRequest::addAuthenticationInfoHeader(HttpReply * rep, int accel)
928f3421
AJ
196{
197 http_hdr_type type;
198
199 /* don't add to authentication error pages */
200
201 if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
202 || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
203 return;
204
205 type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
206
207#if WAITING_FOR_TE
208 /* test for http/1.1 transfer chunked encoding */
209 if (chunkedtest)
210 return;
211#endif
212
372fccd6 213 if ((static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->authenticateProgram) && authDigestNonceLastRequest(nonce)) {
928f3421 214 flags.authinfo_sent = 1;
c7baff40 215 debugs(29, 9, HERE << "Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
928f3421
AJ
216 httpHeaderPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
217 }
218}
219
220#if WAITING_FOR_TE
928f3421 221void
c7baff40 222Auth::Digest::UserRequest::addAuthenticationInfoTrailer(HttpReply * rep, int accel)
928f3421
AJ
223{
224 int type;
225
226 if (!auth_user_request)
227 return;
228
229 /* has the header already been send? */
230 if (flags.authinfo_sent)
231 return;
232
233 /* don't add to authentication error pages */
234 if ((!accel && rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
235 || (accel && rep->sline.status == HTTP_UNAUTHORIZED))
236 return;
237
238 type = accel ? HDR_AUTHENTICATION_INFO : HDR_PROXY_AUTHENTICATION_INFO;
239
372fccd6 240 if ((static_cast<Auth::Digest::Config*>(digestScheme::GetInstance()->getConfig())->authenticate) && authDigestNonceLastRequest(nonce)) {
c7baff40 241 debugs(29, 9, HERE << "Sending type:" << type << " header: 'nextnonce=\"" << authenticateDigestNonceNonceb64(nonce) << "\"");
928f3421
AJ
242 httpTrailerPutStrf(&rep->header, type, "nextnonce=\"%s\"", authenticateDigestNonceNonceb64(nonce));
243 }
244}
245#endif
246
247/* send the initial data to a digest authenticator module */
248void
4c535e87 249Auth::Digest::UserRequest::module_start(AUTHCB * handler, void *data)
928f3421 250{
928f3421 251 char buf[8192];
56a49fda 252
616cfc4c 253 assert(user() != NULL && user()->auth_type == Auth::AUTH_DIGEST);
c7baff40 254 debugs(29, 9, HERE << "'\"" << user()->username() << "\":\"" << realm << "\"'");
928f3421 255
372fccd6 256 if (static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->authenticateProgram == NULL) {
d232141d 257 debugs(29, DBG_CRITICAL, "ERROR: No Digest authentication program configured.");
4c535e87 258 handler(data);
928f3421
AJ
259 return;
260 }
261
372fccd6 262 if (static_cast<Auth::Digest::Config*>(Auth::Config::Find("digest"))->utf8) {
928f3421 263 char userstr[1024];
56a49fda 264 latin1_to_utf8(userstr, sizeof(userstr), user()->username());
928f3421
AJ
265 snprintf(buf, 8192, "\"%s\":\"%s\"\n", userstr, realm);
266 } else {
56a49fda 267 snprintf(buf, 8192, "\"%s\":\"%s\"\n", user()->username(), realm);
928f3421
AJ
268 }
269
c7baff40 270 helperSubmit(digestauthenticators, buf, Auth::Digest::UserRequest::HandleReply,
1c756645 271 new Auth::StateData(this, handler, data));
928f3421
AJ
272}
273
274void
c7baff40 275Auth::Digest::UserRequest::HandleReply(void *data, char *reply)
928f3421 276{
1c756645 277 Auth::StateData *replyData = static_cast<Auth::StateData *>(data);
928f3421
AJ
278 char *t = NULL;
279 void *cbdata;
280 debugs(29, 9, HERE << "{" << (reply ? reply : "<NULL>") << "}");
281
282 if (reply) {
f207fe64
FC
283 if ((t = strchr(reply, ' '))) {
284 *t = '\0';
285 ++t;
286 }
928f3421
AJ
287
288 if (*reply == '\0' || *reply == '\n')
289 reply = NULL;
290 }
291
292 assert(replyData->auth_user_request != NULL);
c7baff40 293 Auth::UserRequest::Pointer auth_user_request = replyData->auth_user_request;
928f3421 294
928f3421 295 if (reply && (strncasecmp(reply, "ERR", 3) == 0)) {
56a49fda 296 /* allow this because the digest_request pointer is purely local */
c7baff40 297 Auth::Digest::UserRequest *digest_request = dynamic_cast<Auth::Digest::UserRequest *>(auth_user_request.getRaw());
56a49fda
AJ
298 assert(digest_request);
299
d87154ee 300 digest_request->user()->credentials(Auth::Failed);
928f3421
AJ
301 digest_request->flags.invalid_password = 1;
302
303 if (t && *t)
304 digest_request->setDenyMessage(t);
305 } else if (reply) {
56a49fda 306 /* allow this because the digest_request pointer is purely local */
aa110616 307 Auth::Digest::User *digest_user = dynamic_cast<Auth::Digest::User *>(auth_user_request->user().getRaw());
56a49fda
AJ
308 assert(digest_user != NULL);
309
928f3421
AJ
310 CvtBin(reply, digest_user->HA1);
311 digest_user->HA1created = 1;
312 }
313
314 if (cbdataReferenceValidDone(replyData->data, &cbdata))
4c535e87 315 replyData->handler(cbdata);
928f3421 316
1c756645 317 delete replyData;
928f3421 318}