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