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