]> git.ipfire.org Git - thirdparty/squid.git/blob - src/auth/negotiate/auth_negotiate.cc
SourceLayout: namesapce for Auth::User children
[thirdparty/squid.git] / src / auth / negotiate / auth_negotiate.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 29 Negotiate Authenticator
5 * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 /* The functions in this file handle authentication.
36 * They DO NOT perform access control or auditing.
37 * See acl.c for access control and client_side.c for auditing */
38
39
40 #include "squid.h"
41 #include "auth/negotiate/auth_negotiate.h"
42 #include "auth/Gadgets.h"
43 #include "auth/State.h"
44 #include "mgr/Registration.h"
45 #include "Store.h"
46 #include "client_side.h"
47 #include "HttpReply.h"
48 #include "HttpRequest.h"
49 #include "SquidTime.h"
50 #include "auth/negotiate/Scheme.h"
51 #include "auth/negotiate/User.h"
52 #include "auth/negotiate/UserRequest.h"
53 #include "wordlist.h"
54
55 /**
56 \defgroup AuthNegotiateInternal Negotiate Authenticator Internals
57 \ingroup AuthNegotiateAPI
58 */
59
60 /* Negotiate Scheme */
61 static AUTHSSTATS authenticateNegotiateStats;
62
63 /// \ingroup AuthNegotiateInternal
64 statefulhelper *negotiateauthenticators = NULL;
65
66 /// \ingroup AuthNegotiateInternal
67 static int authnegotiate_initialised = 0;
68
69 /// \ingroup AuthNegotiateInternal
70 Auth::Negotiate::Config negotiateConfig;
71
72 /// \ingroup AuthNegotiateInternal
73 static hash_table *proxy_auth_cache = NULL;
74
75 /*
76 *
77 * Private Functions
78 *
79 */
80
81 void
82 Auth::Negotiate::Config::rotateHelpers()
83 {
84 /* schedule closure of existing helpers */
85 if (negotiateauthenticators) {
86 helperStatefulShutdown(negotiateauthenticators);
87 }
88
89 /* NP: dynamic helper restart will ensure they start up again as needed. */
90 }
91
92 void
93 Auth::Negotiate::Config::done()
94 {
95 authnegotiate_initialised = 0;
96
97 if (negotiateauthenticators) {
98 helperStatefulShutdown(negotiateauthenticators);
99 }
100
101 if (!shutting_down)
102 return;
103
104 delete negotiateauthenticators;
105 negotiateauthenticators = NULL;
106
107 if (authenticateProgram)
108 wordlistDestroy(&authenticateProgram);
109
110 debugs(29, DBG_IMPORTANT, "Reconfigure: Negotiate authentication configuration cleared.");
111 }
112
113 void
114 Auth::Negotiate::Config::dump(StoreEntry * entry, const char *name, Auth::Config * scheme)
115 {
116 wordlist *list = authenticateProgram;
117 storeAppendPrintf(entry, "%s %s", name, "negotiate");
118
119 while (list != NULL) {
120 storeAppendPrintf(entry, " %s", list->key);
121 list = list->next;
122 }
123
124 storeAppendPrintf(entry, "\n%s negotiate children %d startup=%d idle=%d concurrency=%d\n",
125 name, authenticateChildren.n_max, authenticateChildren.n_startup, authenticateChildren.n_idle, authenticateChildren.concurrency);
126 storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "negotiate", keep_alive ? "on" : "off");
127
128 }
129
130 Auth::Negotiate::Config::Config() : keep_alive(1)
131 { }
132
133 void
134 Auth::Negotiate::Config::parse(Auth::Config * scheme, int n_configured, char *param_str)
135 {
136 if (strcasecmp(param_str, "program") == 0) {
137 if (authenticateProgram)
138 wordlistDestroy(&authenticateProgram);
139
140 parse_wordlist(&authenticateProgram);
141
142 requirePathnameExists("auth_param negotiate program", authenticateProgram->key);
143 } else if (strcasecmp(param_str, "children") == 0) {
144 authenticateChildren.parseConfig();
145 } else if (strcasecmp(param_str, "keep_alive") == 0) {
146 parse_onoff(&keep_alive);
147 } else {
148 debugs(29, DBG_CRITICAL, "ERROR: unrecognised Negotiate auth scheme parameter '" << param_str << "'");
149 }
150 }
151
152 const char *
153 Auth::Negotiate::Config::type() const
154 {
155 return Auth::Negotiate::Scheme::GetInstance()->type();
156 }
157
158 /**
159 * Initialize helpers and the like for this auth scheme.
160 * Called AFTER parsing the config file
161 */
162 void
163 Auth::Negotiate::Config::init(Auth::Config * scheme)
164 {
165 if (authenticateProgram) {
166
167 authnegotiate_initialised = 1;
168
169 if (negotiateauthenticators == NULL)
170 negotiateauthenticators = new statefulhelper("negotiateauthenticator");
171
172 if (!proxy_auth_cache)
173 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
174
175 assert(proxy_auth_cache);
176
177 negotiateauthenticators->cmdline = authenticateProgram;
178
179 negotiateauthenticators->childs = authenticateChildren;
180
181 negotiateauthenticators->ipc_type = IPC_STREAM;
182
183 helperStatefulOpenServers(negotiateauthenticators);
184
185 CBDATA_INIT_TYPE(authenticateStateData);
186 }
187 }
188
189 void
190 Auth::Negotiate::Config::registerWithCacheManager(void)
191 {
192 Mgr::RegisterAction("negotiateauthenticator",
193 "Negotiate User Authenticator Stats",
194 authenticateNegotiateStats, 0, 1);
195 }
196
197 bool
198 Auth::Negotiate::Config::active() const
199 {
200 return authnegotiate_initialised == 1;
201 }
202
203 bool
204 Auth::Negotiate::Config::configured() const
205 {
206 if (authenticateProgram && (authenticateChildren.n_max != 0)) {
207 debugs(29, 9, HERE << "returning configured");
208 return true;
209 }
210
211 debugs(29, 9, HERE << "returning unconfigured");
212 return false;
213 }
214
215 /* Negotiate Scheme */
216
217 void
218 Auth::Negotiate::Config::fixHeader(AuthUserRequest::Pointer auth_user_request, HttpReply *rep, http_hdr_type reqType, HttpRequest * request)
219 {
220 AuthNegotiateUserRequest *negotiate_request;
221
222 if (!authenticateProgram)
223 return;
224
225 /* Need keep-alive */
226 if (!request->flags.proxy_keepalive && request->flags.must_keepalive)
227 return;
228
229 /* New request, no user details */
230 if (auth_user_request == NULL) {
231 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate'");
232 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
233
234 if (!keep_alive) {
235 /* drop the connection */
236 rep->header.delByName("keep-alive");
237 request->flags.proxy_keepalive = 0;
238 }
239 } else {
240 negotiate_request = dynamic_cast<AuthNegotiateUserRequest *>(auth_user_request.getRaw());
241 assert(negotiate_request != NULL);
242
243 switch (negotiate_request->user()->credentials()) {
244
245 case Auth::Failed:
246 /* here it makes sense to drop the connection, as auth is
247 * tied to it, even if MAYBE the client could handle it - Kinkie */
248 rep->header.delByName("keep-alive");
249 request->flags.proxy_keepalive = 0;
250 /* fall through */
251
252 case Auth::Ok:
253 /* Special case: authentication finished OK but disallowed by ACL.
254 * Need to start over to give the client another chance.
255 */
256 if (negotiate_request->server_blob) {
257 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
258 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
259 safe_free(negotiate_request->server_blob);
260 } else {
261 debugs(29, 9, HERE << "Connection authenticated");
262 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
263 }
264 break;
265
266 case Auth::Unchecked:
267 /* semantic change: do not drop the connection.
268 * 2.5 implementation used to keep it open - Kinkie */
269 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate'");
270 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
271 break;
272
273 case Auth::Handshake:
274 /* we're waiting for a response from the client. Pass it the blob */
275 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
276 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
277 safe_free(negotiate_request->server_blob);
278 break;
279
280 default:
281 debugs(29, DBG_CRITICAL, "ERROR: Negotiate auth fixHeader: state " << negotiate_request->user()->credentials() << ".");
282 fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n");
283 }
284 }
285 }
286
287 static void
288 authenticateNegotiateStats(StoreEntry * sentry)
289 {
290 helperStatefulStats(sentry, negotiateauthenticators, "Negotiate Authenticator Statistics");
291 }
292
293 /*
294 * Decode a Negotiate [Proxy-]Auth string, placing the results in the passed
295 * Auth_user structure.
296 */
297 AuthUserRequest::Pointer
298 Auth::Negotiate::Config::decode(char const *proxy_auth)
299 {
300 Auth::Negotiate::User *newUser = new Auth::Negotiate::User(&negotiateConfig);
301 AuthUserRequest *auth_user_request = new AuthNegotiateUserRequest();
302 assert(auth_user_request->user() == NULL);
303
304 auth_user_request->user(newUser);
305 auth_user_request->user()->auth_type = Auth::AUTH_NEGOTIATE;
306
307 /* all we have to do is identify that it's Negotiate - the helper does the rest */
308 debugs(29, 9, HERE << "decode Negotiate authentication");
309 return auth_user_request;
310 }