]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/basic/UserRequest.cc
SourceLayout: Basic auth: shuffle helper request functions
[thirdparty/squid.git] / src / auth / basic / UserRequest.cc
CommitLineData
928f3421 1#include "config.h"
928f3421 2#include "auth/basic/auth_basic.h"
aa110616 3#include "auth/basic/User.h"
616cfc4c 4#include "auth/basic/UserRequest.h"
fe0a0419
AJ
5#include "auth/State.h"
6#include "charset.h"
7#include "rfc1738.h"
616cfc4c 8#include "SquidTime.h"
928f3421 9
fe0a0419
AJ
10#if !defined(HELPER_INPUT_BUFFER)
11#define HELPER_INPUT_BUFFER 8192
12#endif
13
928f3421
AJ
14int
15AuthBasicUserRequest::authenticated() const
16{
aa110616 17 Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
928f3421
AJ
18
19 if (basic_auth && basic_auth->authenticated())
20 return 1;
21
22 return 0;
23}
24
25/* log a basic user in
26 */
27void
28AuthBasicUserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
29{
30 assert(user() != NULL);
31
928f3421 32 /* if the password is not ok, do an identity */
d87154ee 33 if (!user() || user()->credentials() != Auth::Ok)
928f3421
AJ
34 return;
35
36 /* are we about to recheck the credentials externally? */
372fccd6 37 if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL) <= squid_curtime) {
d232141d 38 debugs(29, 4, HERE << "credentials expired - rechecking");
928f3421
AJ
39 return;
40 }
41
42 /* we have been through the external helper, and the credentials haven't expired */
d232141d 43 debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated");
928f3421
AJ
44
45 /* Decode now takes care of finding the AuthUser struct in the cache */
46 /* after external auth occurs anyway */
d232141d 47 user()->expiretime = current_time.tv_sec;
928f3421
AJ
48
49 return;
50}
51
51a3dd58 52Auth::Direction
928f3421
AJ
53AuthBasicUserRequest::module_direction()
54{
51a3dd58 55 /* null auth_user is checked for by AuthUserRequest::direction() */
616cfc4c 56 if (user()->auth_type != Auth::AUTH_BASIC)
51a3dd58 57 return Auth::CRED_ERROR;
928f3421 58
d232141d 59 switch (user()->credentials()) {
928f3421 60
d87154ee
AJ
61 case Auth::Unchecked:
62 case Auth::Pending:
51a3dd58 63 return Auth::CRED_LOOKUP;
928f3421 64
d87154ee 65 case Auth::Ok:
372fccd6 66 if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL <= squid_curtime)
51a3dd58
AJ
67 return Auth::CRED_LOOKUP;
68 return Auth::CRED_VALID;
928f3421 69
d87154ee 70 case Auth::Failed:
51a3dd58 71 return Auth::CRED_VALID;
928f3421 72
d232141d 73 default:
51a3dd58 74 return Auth::CRED_ERROR;
d232141d 75 }
928f3421
AJ
76}
77
78/* send the initial data to a basic authenticator module */
79void
80AuthBasicUserRequest::module_start(RH * handler, void *data)
81{
616cfc4c 82 assert(user()->auth_type == Auth::AUTH_BASIC);
aa110616 83 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw());
928f3421
AJ
84 assert(basic_auth != NULL);
85 debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
86
372fccd6 87 if (static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->authenticateProgram == NULL) {
d232141d 88 debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured.");
928f3421
AJ
89 handler(data, NULL);
90 return;
91 }
92
93 /* check to see if the auth_user already has a request outstanding */
d87154ee 94 if (user()->credentials() == Auth::Pending) {
928f3421 95 /* there is a request with the same credentials already being verified */
fe0a0419
AJ
96
97 BasicAuthQueueNode *node = static_cast<BasicAuthQueueNode *>(xcalloc(1, sizeof(BasicAuthQueueNode)));
98 assert(node);
99 node->auth_user_request = this;
100 node->handler = handler;
101 node->data = cbdataReference(data);
102
103 /* queue this validation request to be infored of the pending lookup results */
104 node->next = basic_auth->auth_queue;
105 basic_auth->auth_queue = node;
928f3421
AJ
106 return;
107 }
fe0a0419
AJ
108 // otherwise submit this request to the auth helper(s) for validation
109
110 /* mark this user as having verification in progress */
111 user()->credentials(Auth::Pending);
112 char buf[HELPER_INPUT_BUFFER];
113 static char username[HELPER_INPUT_BUFFER];
114 static char pass[HELPER_INPUT_BUFFER];
115 if (static_cast<Auth::Basic::Config*>(user()->config)->utf8) {
116 latin1_to_utf8(username, sizeof(username), user()->username());
117 latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd);
118 xstrncpy(username, rfc1738_escape(username), sizeof(username));
119 xstrncpy(pass, rfc1738_escape(pass), sizeof(pass));
120 } else {
121 xstrncpy(username, rfc1738_escape(user()->username()), sizeof(username));
122 xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
123 }
124 int sz = snprintf(buf, sizeof(buf), "%s %s\n", username, pass);
125 if (sz<=0) {
126 debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. Can not build helper validation request.");
127 handler(data, NULL);
128 } else if (sz>=sizeof(buf)) {
129 debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. user:password exceeds " << sizeof(buf) << " bytes.");
130 handler(data, NULL);
131 } else
132 helperSubmit(basicauthenticators, buf, AuthBasicUserRequest::HandleReply,
133 new Auth::StateData(this, handler, data));
928f3421
AJ
134}
135
fe0a0419
AJ
136void
137AuthBasicUserRequest::HandleReply(void *data, char *reply)
138{
139 Auth::StateData *r = static_cast<Auth::StateData *>(data);
140 BasicAuthQueueNode *tmpnode;
141 char *t = NULL;
142 void *cbdata;
143 debugs(29, 9, HERE << "{" << (reply ? reply : "<NULL>") << "}");
144
145 if (reply) {
146 if ((t = strchr(reply, ' ')))
147 *t++ = '\0';
148
149 if (*reply == '\0')
150 reply = NULL;
151 }
152
153 assert(r->auth_user_request != NULL);
154 assert(r->auth_user_request->user()->auth_type == Auth::AUTH_BASIC);
155
156 /* this is okay since we only play with the Auth::Basic::User child fields below
157 * and dont pass the pointer itself anywhere */
158 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(r->auth_user_request->user().getRaw());
159
160 assert(basic_auth != NULL);
161
162 if (reply && (strncasecmp(reply, "OK", 2) == 0))
163 basic_auth->credentials(Auth::Ok);
164 else {
165 basic_auth->credentials(Auth::Failed);
166
167 if (t && *t)
168 r->auth_user_request->setDenyMessage(t);
169 }
170
171 basic_auth->expiretime = squid_curtime;
172
173 if (cbdataReferenceValidDone(r->data, &cbdata))
174 r->handler(cbdata, NULL);
175
176 cbdataReferenceDone(r->data);
177
178 while (basic_auth->auth_queue) {
179 tmpnode = basic_auth->auth_queue->next;
180
181 if (cbdataReferenceValidDone(basic_auth->auth_queue->data, &cbdata))
182 basic_auth->auth_queue->handler(cbdata, NULL);
183
184 xfree(basic_auth->auth_queue);
185
186 basic_auth->auth_queue = tmpnode;
187 }
188
189 delete r;
190}