]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/basic/UserRequest.cc
Move compat/unsafe.h protections from libcompat to source maintenance
[thirdparty/squid.git] / src / auth / basic / UserRequest.cc
CommitLineData
f7f3304a 1#include "squid.h"
928f3421 2#include "auth/basic/auth_basic.h"
aa110616 3#include "auth/basic/User.h"
616cfc4c 4#include "auth/basic/UserRequest.h"
bf929433 5#include "auth/QueueNode.h"
fe0a0419
AJ
6#include "auth/State.h"
7#include "charset.h"
582c2af2 8#include "Debug.h"
e166785a 9#include "HelperReply.h"
d4806c91
CT
10#include "HttpMsg.h"
11#include "HttpRequest.h"
12#include "format/Format.h"
13#include "MemBuf.h"
fe0a0419 14#include "rfc1738.h"
616cfc4c 15#include "SquidTime.h"
928f3421 16
fe0a0419
AJ
17#if !defined(HELPER_INPUT_BUFFER)
18#define HELPER_INPUT_BUFFER 8192
19#endif
20
928f3421 21int
c7baff40 22Auth::Basic::UserRequest::authenticated() const
928f3421 23{
aa110616 24 Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
928f3421
AJ
25
26 if (basic_auth && basic_auth->authenticated())
27 return 1;
28
29 return 0;
30}
31
d4806c91
CT
32const char *
33Auth::Basic::UserRequest::credentialsStr()
34{
35 Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
36 if (basic_auth)
37 return basic_auth->passwd;
38 return NULL;
39}
40
928f3421
AJ
41/* log a basic user in
42 */
43void
c7baff40 44Auth::Basic::UserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
928f3421
AJ
45{
46 assert(user() != NULL);
47
928f3421 48 /* if the password is not ok, do an identity */
d87154ee 49 if (!user() || user()->credentials() != Auth::Ok)
928f3421
AJ
50 return;
51
52 /* are we about to recheck the credentials externally? */
372fccd6 53 if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL) <= squid_curtime) {
d232141d 54 debugs(29, 4, HERE << "credentials expired - rechecking");
928f3421
AJ
55 return;
56 }
57
58 /* we have been through the external helper, and the credentials haven't expired */
d232141d 59 debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated");
928f3421
AJ
60
61 /* Decode now takes care of finding the AuthUser struct in the cache */
62 /* after external auth occurs anyway */
d232141d 63 user()->expiretime = current_time.tv_sec;
928f3421
AJ
64
65 return;
66}
67
51a3dd58 68Auth::Direction
c7baff40 69Auth::Basic::UserRequest::module_direction()
928f3421 70{
c7baff40 71 /* null auth_user is checked for by Auth::UserRequest::direction() */
616cfc4c 72 if (user()->auth_type != Auth::AUTH_BASIC)
51a3dd58 73 return Auth::CRED_ERROR;
928f3421 74
d232141d 75 switch (user()->credentials()) {
928f3421 76
d87154ee
AJ
77 case Auth::Unchecked:
78 case Auth::Pending:
51a3dd58 79 return Auth::CRED_LOOKUP;
928f3421 80
d87154ee 81 case Auth::Ok:
372fccd6 82 if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL <= squid_curtime)
51a3dd58
AJ
83 return Auth::CRED_LOOKUP;
84 return Auth::CRED_VALID;
928f3421 85
d87154ee 86 case Auth::Failed:
51a3dd58 87 return Auth::CRED_VALID;
928f3421 88
d232141d 89 default:
51a3dd58 90 return Auth::CRED_ERROR;
d232141d 91 }
928f3421
AJ
92}
93
94/* send the initial data to a basic authenticator module */
95void
d4806c91 96Auth::Basic::UserRequest::module_start(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data)
928f3421 97{
616cfc4c 98 assert(user()->auth_type == Auth::AUTH_BASIC);
aa110616 99 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw());
928f3421
AJ
100 assert(basic_auth != NULL);
101 debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
102
372fccd6 103 if (static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->authenticateProgram == NULL) {
d232141d 104 debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured.");
4c535e87 105 handler(data);
928f3421
AJ
106 return;
107 }
108
109 /* check to see if the auth_user already has a request outstanding */
d87154ee 110 if (user()->credentials() == Auth::Pending) {
928f3421 111 /* there is a request with the same credentials already being verified */
fe0a0419 112
bf929433 113 Auth::QueueNode *node = new Auth::QueueNode(this, handler, data);
fe0a0419
AJ
114
115 /* queue this validation request to be infored of the pending lookup results */
bf929433
AJ
116 node->next = basic_auth->queue;
117 basic_auth->queue = node;
928f3421
AJ
118 return;
119 }
fe0a0419
AJ
120 // otherwise submit this request to the auth helper(s) for validation
121
122 /* mark this user as having verification in progress */
123 user()->credentials(Auth::Pending);
124 char buf[HELPER_INPUT_BUFFER];
9dca980d 125 static char usern[HELPER_INPUT_BUFFER];
fe0a0419
AJ
126 static char pass[HELPER_INPUT_BUFFER];
127 if (static_cast<Auth::Basic::Config*>(user()->config)->utf8) {
9dca980d 128 latin1_to_utf8(usern, sizeof(usern), user()->username());
fe0a0419 129 latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd);
9dca980d 130 xstrncpy(usern, rfc1738_escape(usern), sizeof(usern));
fe0a0419
AJ
131 xstrncpy(pass, rfc1738_escape(pass), sizeof(pass));
132 } else {
9dca980d 133 xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern));
fe0a0419
AJ
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
e166785a 154Auth::Basic::UserRequest::HandleReply(void *data, const HelperReply &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
165 r->auth_user_request->user()->notes.appendNewOnly(&reply.notes);
166
fe0a0419
AJ
167 /* this is okay since we only play with the Auth::Basic::User child fields below
168 * and dont pass the pointer itself anywhere */
169 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(r->auth_user_request->user().getRaw());
170
171 assert(basic_auth != NULL);
172
e166785a 173 if (reply.result == HelperReply::Okay)
fe0a0419
AJ
174 basic_auth->credentials(Auth::Ok);
175 else {
176 basic_auth->credentials(Auth::Failed);
177
e166785a
AJ
178 if (reply.other().hasContent())
179 r->auth_user_request->setDenyMessage(reply.other().content());
fe0a0419
AJ
180 }
181
182 basic_auth->expiretime = squid_curtime;
183
184 if (cbdataReferenceValidDone(r->data, &cbdata))
4c535e87 185 r->handler(cbdata);
fe0a0419
AJ
186
187 cbdataReferenceDone(r->data);
188
bf929433
AJ
189 while (basic_auth->queue) {
190 if (cbdataReferenceValidDone(basic_auth->queue->data, &cbdata))
191 basic_auth->queue->handler(cbdata);
fe0a0419 192
bf929433
AJ
193 Auth::QueueNode *tmpnode = basic_auth->queue->next;
194 basic_auth->queue->next = NULL;
195 delete basic_auth->queue;
fe0a0419 196
bf929433 197 basic_auth->queue = tmpnode;
fe0a0419
AJ
198 }
199
200 delete r;
201}