]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/basic/UserRequest.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / auth / basic / UserRequest.cc
CommitLineData
bbc27441 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
f7f3304a 9#include "squid.h"
12daeef6 10#include "auth/basic/Config.h"
aa110616 11#include "auth/basic/User.h"
616cfc4c 12#include "auth/basic/UserRequest.h"
bf929433 13#include "auth/QueueNode.h"
fe0a0419 14#include "auth/State.h"
582c2af2 15#include "Debug.h"
86c63190 16#include "format/Format.h"
24438ec5
AJ
17#include "helper.h"
18#include "helper/Reply.h"
d4806c91 19#include "HttpRequest.h"
d4806c91 20#include "MemBuf.h"
fe0a0419 21#include "rfc1738.h"
616cfc4c 22#include "SquidTime.h"
928f3421 23
fe0a0419
AJ
24#if !defined(HELPER_INPUT_BUFFER)
25#define HELPER_INPUT_BUFFER 8192
26#endif
27
928f3421 28int
c7baff40 29Auth::Basic::UserRequest::authenticated() const
928f3421 30{
aa110616 31 Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
928f3421
AJ
32
33 if (basic_auth && basic_auth->authenticated())
34 return 1;
35
36 return 0;
37}
38
d4806c91
CT
39const char *
40Auth::Basic::UserRequest::credentialsStr()
41{
42 Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
43 if (basic_auth)
44 return basic_auth->passwd;
45 return NULL;
46}
47
928f3421
AJ
48/* log a basic user in
49 */
50void
789217a2 51Auth::Basic::UserRequest::authenticate(HttpRequest *, ConnStateData *, Http::HdrType)
928f3421
AJ
52{
53 assert(user() != NULL);
54
928f3421 55 /* if the password is not ok, do an identity */
d87154ee 56 if (!user() || user()->credentials() != Auth::Ok)
928f3421
AJ
57 return;
58
59 /* are we about to recheck the credentials externally? */
dc79fed8 60 if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->credentialsTTL) <= squid_curtime) {
d232141d 61 debugs(29, 4, HERE << "credentials expired - rechecking");
928f3421
AJ
62 return;
63 }
64
65 /* we have been through the external helper, and the credentials haven't expired */
d232141d 66 debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated");
928f3421
AJ
67
68 /* Decode now takes care of finding the AuthUser struct in the cache */
69 /* after external auth occurs anyway */
d232141d 70 user()->expiretime = current_time.tv_sec;
928f3421
AJ
71}
72
51a3dd58 73Auth::Direction
c7baff40 74Auth::Basic::UserRequest::module_direction()
928f3421 75{
c7baff40 76 /* null auth_user is checked for by Auth::UserRequest::direction() */
616cfc4c 77 if (user()->auth_type != Auth::AUTH_BASIC)
51a3dd58 78 return Auth::CRED_ERROR;
928f3421 79
d232141d 80 switch (user()->credentials()) {
928f3421 81
d87154ee
AJ
82 case Auth::Unchecked:
83 case Auth::Pending:
51a3dd58 84 return Auth::CRED_LOOKUP;
928f3421 85
d87154ee 86 case Auth::Ok:
dc79fed8 87 if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->credentialsTTL <= squid_curtime)
51a3dd58
AJ
88 return Auth::CRED_LOOKUP;
89 return Auth::CRED_VALID;
928f3421 90
d87154ee 91 case Auth::Failed:
51a3dd58 92 return Auth::CRED_VALID;
928f3421 93
d232141d 94 default:
51a3dd58 95 return Auth::CRED_ERROR;
d232141d 96 }
928f3421
AJ
97}
98
99/* send the initial data to a basic authenticator module */
100void
30c3f584 101Auth::Basic::UserRequest::startHelperLookup(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data)
928f3421 102{
616cfc4c 103 assert(user()->auth_type == Auth::AUTH_BASIC);
aa110616 104 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw());
928f3421
AJ
105 assert(basic_auth != NULL);
106 debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
107
dc79fed8 108 if (static_cast<Auth::Basic::Config*>(Auth::SchemeConfig::Find("basic"))->authenticateProgram == NULL) {
d232141d 109 debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured.");
4c535e87 110 handler(data);
928f3421
AJ
111 return;
112 }
113
114 /* check to see if the auth_user already has a request outstanding */
d87154ee 115 if (user()->credentials() == Auth::Pending) {
928f3421 116 /* there is a request with the same credentials already being verified */
fe0a0419 117
bf929433 118 Auth::QueueNode *node = new Auth::QueueNode(this, handler, data);
fe0a0419
AJ
119
120 /* queue this validation request to be infored of the pending lookup results */
bf929433
AJ
121 node->next = basic_auth->queue;
122 basic_auth->queue = node;
928f3421
AJ
123 return;
124 }
fe0a0419
AJ
125 // otherwise submit this request to the auth helper(s) for validation
126
127 /* mark this user as having verification in progress */
128 user()->credentials(Auth::Pending);
129 char buf[HELPER_INPUT_BUFFER];
9dca980d 130 static char usern[HELPER_INPUT_BUFFER];
fe0a0419 131 static char pass[HELPER_INPUT_BUFFER];
7e851a3e
SK
132
133 xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern));
134 xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
135
d4806c91
CT
136 int sz = 0;
137 if (const char *keyExtras = helperRequestKeyExtras(request, al))
138 sz = snprintf(buf, sizeof(buf), "%s %s %s\n", usern, pass, keyExtras);
139 else
140 sz = snprintf(buf, sizeof(buf), "%s %s\n", usern, pass);
141
fe0a0419
AJ
142 if (sz<=0) {
143 debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. Can not build helper validation request.");
4c535e87 144 handler(data);
56946509 145 } else if (static_cast<size_t>(sz) >= sizeof(buf)) {
fe0a0419 146 debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. user:password exceeds " << sizeof(buf) << " bytes.");
4c535e87 147 handler(data);
fe0a0419 148 } else
c7baff40 149 helperSubmit(basicauthenticators, buf, Auth::Basic::UserRequest::HandleReply,
fe0a0419 150 new Auth::StateData(this, handler, data));
928f3421
AJ
151}
152
fe0a0419 153void
24438ec5 154Auth::Basic::UserRequest::HandleReply(void *data, const Helper::Reply &reply)
fe0a0419
AJ
155{
156 Auth::StateData *r = static_cast<Auth::StateData *>(data);
fe0a0419 157 void *cbdata;
e166785a 158 debugs(29, 5, HERE << "reply=" << reply);
fe0a0419
AJ
159
160 assert(r->auth_user_request != NULL);
161 assert(r->auth_user_request->user()->auth_type == Auth::AUTH_BASIC);
162
71e7400c
AJ
163 // add new helper kv-pair notes to the credentials object
164 // so that any transaction using those credentials can access them
d665de37
A
165 static const NotePairs::Names appendables = { SBuf("group"), SBuf("tag") };
166 r->auth_user_request->user()->notes.replaceOrAddOrAppend(&reply.notes, appendables);
71e7400c 167
fe0a0419 168 /* this is okay since we only play with the Auth::Basic::User child fields below
61beade2 169 * and do not pass the pointer itself anywhere */
fe0a0419
AJ
170 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(r->auth_user_request->user().getRaw());
171
172 assert(basic_auth != NULL);
173
2428ce02 174 if (reply.result == Helper::Okay)
fe0a0419
AJ
175 basic_auth->credentials(Auth::Ok);
176 else {
177 basic_auth->credentials(Auth::Failed);
178
e166785a
AJ
179 if (reply.other().hasContent())
180 r->auth_user_request->setDenyMessage(reply.other().content());
fe0a0419
AJ
181 }
182
183 basic_auth->expiretime = squid_curtime;
184
185 if (cbdataReferenceValidDone(r->data, &cbdata))
4c535e87 186 r->handler(cbdata);
fe0a0419
AJ
187
188 cbdataReferenceDone(r->data);
189
bf929433
AJ
190 while (basic_auth->queue) {
191 if (cbdataReferenceValidDone(basic_auth->queue->data, &cbdata))
192 basic_auth->queue->handler(cbdata);
fe0a0419 193
bf929433
AJ
194 Auth::QueueNode *tmpnode = basic_auth->queue->next;
195 basic_auth->queue->next = NULL;
196 delete basic_auth->queue;
fe0a0419 197
bf929433 198 basic_auth->queue = tmpnode;
fe0a0419
AJ
199 }
200
201 delete r;
202}
f53969cc 203