]> git.ipfire.org Git - thirdparty/squid.git/blob - src/auth/basic/UserRequest.cc
merge from trunk r13423
[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/QueueNode.h"
6 #include "auth/State.h"
7 #include "charset.h"
8 #include "Debug.h"
9 #include "format/Format.h"
10 #include "HelperReply.h"
11 #include "HttpMsg.h"
12 #include "HttpRequest.h"
13 #include "MemBuf.h"
14 #include "rfc1738.h"
15 #include "SquidTime.h"
16
17 #if !defined(HELPER_INPUT_BUFFER)
18 #define HELPER_INPUT_BUFFER 8192
19 #endif
20
21 int
22 Auth::Basic::UserRequest::authenticated() const
23 {
24 Auth::Basic::User const *basic_auth = dynamic_cast<Auth::Basic::User const *>(user().getRaw());
25
26 if (basic_auth && basic_auth->authenticated())
27 return 1;
28
29 return 0;
30 }
31
32 const char *
33 Auth::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
41 /* log a basic user in
42 */
43 void
44 Auth::Basic::UserRequest::authenticate(HttpRequest * request, ConnStateData * conn, http_hdr_type type)
45 {
46 assert(user() != NULL);
47
48 /* if the password is not ok, do an identity */
49 if (!user() || user()->credentials() != Auth::Ok)
50 return;
51
52 /* are we about to recheck the credentials externally? */
53 if ((user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL) <= squid_curtime) {
54 debugs(29, 4, HERE << "credentials expired - rechecking");
55 return;
56 }
57
58 /* we have been through the external helper, and the credentials haven't expired */
59 debugs(29, 9, HERE << "user '" << user()->username() << "' authenticated");
60
61 /* Decode now takes care of finding the AuthUser struct in the cache */
62 /* after external auth occurs anyway */
63 user()->expiretime = current_time.tv_sec;
64
65 return;
66 }
67
68 Auth::Direction
69 Auth::Basic::UserRequest::module_direction()
70 {
71 /* null auth_user is checked for by Auth::UserRequest::direction() */
72 if (user()->auth_type != Auth::AUTH_BASIC)
73 return Auth::CRED_ERROR;
74
75 switch (user()->credentials()) {
76
77 case Auth::Unchecked:
78 case Auth::Pending:
79 return Auth::CRED_LOOKUP;
80
81 case Auth::Ok:
82 if (user()->expiretime + static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->credentialsTTL <= squid_curtime)
83 return Auth::CRED_LOOKUP;
84 return Auth::CRED_VALID;
85
86 case Auth::Failed:
87 return Auth::CRED_VALID;
88
89 default:
90 return Auth::CRED_ERROR;
91 }
92 }
93
94 /* send the initial data to a basic authenticator module */
95 void
96 Auth::Basic::UserRequest::startHelperLookup(HttpRequest *request, AccessLogEntry::Pointer &al, AUTHCB * handler, void *data)
97 {
98 assert(user()->auth_type == Auth::AUTH_BASIC);
99 Auth::Basic::User *basic_auth = dynamic_cast<Auth::Basic::User *>(user().getRaw());
100 assert(basic_auth != NULL);
101 debugs(29, 9, HERE << "'" << basic_auth->username() << ":" << basic_auth->passwd << "'");
102
103 if (static_cast<Auth::Basic::Config*>(Auth::Config::Find("basic"))->authenticateProgram == NULL) {
104 debugs(29, DBG_CRITICAL, "ERROR: No Basic authentication program configured.");
105 handler(data);
106 return;
107 }
108
109 /* check to see if the auth_user already has a request outstanding */
110 if (user()->credentials() == Auth::Pending) {
111 /* there is a request with the same credentials already being verified */
112
113 Auth::QueueNode *node = new Auth::QueueNode(this, handler, data);
114
115 /* queue this validation request to be infored of the pending lookup results */
116 node->next = basic_auth->queue;
117 basic_auth->queue = node;
118 return;
119 }
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];
125 static char usern[HELPER_INPUT_BUFFER];
126 static char pass[HELPER_INPUT_BUFFER];
127 if (static_cast<Auth::Basic::Config*>(user()->config)->utf8) {
128 latin1_to_utf8(usern, sizeof(usern), user()->username());
129 latin1_to_utf8(pass, sizeof(pass), basic_auth->passwd);
130 xstrncpy(usern, rfc1738_escape(usern), sizeof(usern));
131 xstrncpy(pass, rfc1738_escape(pass), sizeof(pass));
132 } else {
133 xstrncpy(usern, rfc1738_escape(user()->username()), sizeof(usern));
134 xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass));
135 }
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
142 if (sz<=0) {
143 debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. Can not build helper validation request.");
144 handler(data);
145 } else if (static_cast<size_t>(sz) >= sizeof(buf)) {
146 debugs(9, DBG_CRITICAL, "ERROR: Basic Authentication Failure. user:password exceeds " << sizeof(buf) << " bytes.");
147 handler(data);
148 } else
149 helperSubmit(basicauthenticators, buf, Auth::Basic::UserRequest::HandleReply,
150 new Auth::StateData(this, handler, data));
151 }
152
153 void
154 Auth::Basic::UserRequest::HandleReply(void *data, const HelperReply &reply)
155 {
156 Auth::StateData *r = static_cast<Auth::StateData *>(data);
157 void *cbdata;
158 debugs(29, 5, HERE << "reply=" << reply);
159
160 assert(r->auth_user_request != NULL);
161 assert(r->auth_user_request->user()->auth_type == Auth::AUTH_BASIC);
162
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
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
173 if (reply.result == HelperReply::Okay)
174 basic_auth->credentials(Auth::Ok);
175 else {
176 basic_auth->credentials(Auth::Failed);
177
178 if (reply.other().hasContent())
179 r->auth_user_request->setDenyMessage(reply.other().content());
180 }
181
182 basic_auth->expiretime = squid_curtime;
183
184 if (cbdataReferenceValidDone(r->data, &cbdata))
185 r->handler(cbdata);
186
187 cbdataReferenceDone(r->data);
188
189 while (basic_auth->queue) {
190 if (cbdataReferenceValidDone(basic_auth->queue->data, &cbdata))
191 basic_auth->queue->handler(cbdata);
192
193 Auth::QueueNode *tmpnode = basic_auth->queue->next;
194 basic_auth->queue->next = NULL;
195 delete basic_auth->queue;
196
197 basic_auth->queue = tmpnode;
198 }
199
200 delete r;
201 }