]>
Commit | Line | Data |
---|---|---|
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 |
14 | int |
15 | AuthBasicUserRequest::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 | */ | |
27 | void | |
28 | AuthBasicUserRequest::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 | 52 | Auth::Direction |
928f3421 AJ |
53 | AuthBasicUserRequest::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 */ | |
79 | void | |
80 | AuthBasicUserRequest::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 |
136 | void |
137 | AuthBasicUserRequest::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 | } |