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