]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/negotiate/auth_negotiate.cc
moved HttpHeaderTools.cc-related headers to HttpHeaderTools.h
[thirdparty/squid.git] / src / auth / negotiate / auth_negotiate.cc
CommitLineData
6bf4f823 1/*
262a0e14 2 * $Id$
6bf4f823 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.
26ac0430 23 *
6bf4f823 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.
26ac0430 28 *
6bf4f823 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
582c2af2 40#include "squid.h"
5817ee13 41#include "auth/negotiate/auth_negotiate.h"
3ad63615 42#include "auth/Gadgets.h"
928f3421 43#include "auth/State.h"
8a01b99e 44#include "cache_cf.h"
8822ebee 45#include "mgr/Registration.h"
6bf4f823 46#include "Store.h"
47#include "client_side.h"
a5bac1d2 48#include "HttpHeaderTools.h"
6bf4f823 49#include "HttpReply.h"
50#include "HttpRequest.h"
582c2af2 51#include "protos.h"
cc192b50 52#include "SquidTime.h"
616cfc4c 53#include "auth/negotiate/Scheme.h"
aa110616 54#include "auth/negotiate/User.h"
616cfc4c 55#include "auth/negotiate/UserRequest.h"
d295d770 56#include "wordlist.h"
6bf4f823 57
63be0a78 58/**
59 \defgroup AuthNegotiateInternal Negotiate Authenticator Internals
60 \ingroup AuthNegotiateAPI
61 */
62
6bf4f823 63/* Negotiate Scheme */
6bf4f823 64static AUTHSSTATS authenticateNegotiateStats;
65
63be0a78 66/// \ingroup AuthNegotiateInternal
928f3421 67statefulhelper *negotiateauthenticators = NULL;
6bf4f823 68
63be0a78 69/// \ingroup AuthNegotiateInternal
6bf4f823 70static int authnegotiate_initialised = 0;
71
63be0a78 72/// \ingroup AuthNegotiateInternal
372fccd6 73Auth::Negotiate::Config negotiateConfig;
6bf4f823 74
63be0a78 75/// \ingroup AuthNegotiateInternal
6bf4f823 76static hash_table *proxy_auth_cache = NULL;
77
78/*
79 *
80 * Private Functions
81 *
82 */
83
0bcb6908 84void
372fccd6 85Auth::Negotiate::Config::rotateHelpers()
0bcb6908
AJ
86{
87 /* schedule closure of existing helpers */
88 if (negotiateauthenticators) {
89 helperStatefulShutdown(negotiateauthenticators);
90 }
91
92 /* NP: dynamic helper restart will ensure they start up again as needed. */
93}
94
6bf4f823 95void
372fccd6 96Auth::Negotiate::Config::done()
6bf4f823 97{
6bf4f823 98 authnegotiate_initialised = 0;
99
5817ee13
AJ
100 if (negotiateauthenticators) {
101 helperStatefulShutdown(negotiateauthenticators);
5817ee13 102 }
6bf4f823 103
6bf4f823 104 if (!shutting_down)
105 return;
106
48d54e4d 107 delete negotiateauthenticators;
6bf4f823 108 negotiateauthenticators = NULL;
109
58ee2093
AJ
110 if (authenticateProgram)
111 wordlistDestroy(&authenticateProgram);
cdabe87d 112
372fccd6 113 debugs(29, DBG_IMPORTANT, "Reconfigure: Negotiate authentication configuration cleared.");
6bf4f823 114}
115
116void
372fccd6 117Auth::Negotiate::Config::dump(StoreEntry * entry, const char *name, Auth::Config * scheme)
6bf4f823 118{
58ee2093 119 wordlist *list = authenticateProgram;
6bf4f823 120 storeAppendPrintf(entry, "%s %s", name, "negotiate");
121
122 while (list != NULL) {
123 storeAppendPrintf(entry, " %s", list->key);
124 list = list->next;
125 }
126
404cfda1
AJ
127 storeAppendPrintf(entry, "\n%s negotiate children %d startup=%d idle=%d concurrency=%d\n",
128 name, authenticateChildren.n_max, authenticateChildren.n_startup, authenticateChildren.n_idle, authenticateChildren.concurrency);
6bf4f823 129 storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "negotiate", keep_alive ? "on" : "off");
130
131}
132
372fccd6 133Auth::Negotiate::Config::Config() : keep_alive(1)
6bf4f823 134{ }
135
136void
372fccd6 137Auth::Negotiate::Config::parse(Auth::Config * scheme, int n_configured, char *param_str)
6bf4f823 138{
139 if (strcasecmp(param_str, "program") == 0) {
58ee2093
AJ
140 if (authenticateProgram)
141 wordlistDestroy(&authenticateProgram);
6bf4f823 142
58ee2093 143 parse_wordlist(&authenticateProgram);
6bf4f823 144
58ee2093 145 requirePathnameExists("auth_param negotiate program", authenticateProgram->key);
6bf4f823 146 } else if (strcasecmp(param_str, "children") == 0) {
48d54e4d 147 authenticateChildren.parseConfig();
6bf4f823 148 } else if (strcasecmp(param_str, "keep_alive") == 0) {
149 parse_onoff(&keep_alive);
150 } else {
372fccd6 151 debugs(29, DBG_CRITICAL, "ERROR: unrecognised Negotiate auth scheme parameter '" << param_str << "'");
6bf4f823 152 }
6bf4f823 153}
154
155const char *
372fccd6 156Auth::Negotiate::Config::type() const
6bf4f823 157{
d6374be6 158 return Auth::Negotiate::Scheme::GetInstance()->type();
6bf4f823 159}
160
63be0a78 161/**
162 * Initialize helpers and the like for this auth scheme.
163 * Called AFTER parsing the config file
164 */
6bf4f823 165void
372fccd6 166Auth::Negotiate::Config::init(Auth::Config * scheme)
6bf4f823 167{
58ee2093 168 if (authenticateProgram) {
81425fb6 169
6bf4f823 170 authnegotiate_initialised = 1;
171
172 if (negotiateauthenticators == NULL)
48d54e4d 173 negotiateauthenticators = new statefulhelper("negotiateauthenticator");
6bf4f823 174
175 if (!proxy_auth_cache)
30abd221 176 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
6bf4f823 177
178 assert(proxy_auth_cache);
179
58ee2093 180 negotiateauthenticators->cmdline = authenticateProgram;
6bf4f823 181
1af735c7 182 negotiateauthenticators->childs.updateLimits(authenticateChildren);
6bf4f823 183
184 negotiateauthenticators->ipc_type = IPC_STREAM;
185
186 helperStatefulOpenServers(negotiateauthenticators);
6bf4f823 187 }
188}
189
62ee09ca 190void
372fccd6 191Auth::Negotiate::Config::registerWithCacheManager(void)
62ee09ca 192{
8822ebee 193 Mgr::RegisterAction("negotiateauthenticator",
d9fc6862
A
194 "Negotiate User Authenticator Stats",
195 authenticateNegotiateStats, 0, 1);
62ee09ca 196}
197
6bf4f823 198bool
372fccd6 199Auth::Negotiate::Config::active() const
6bf4f823 200{
201 return authnegotiate_initialised == 1;
202}
203
204bool
372fccd6 205Auth::Negotiate::Config::configured() const
6bf4f823 206{
58ee2093 207 if (authenticateProgram && (authenticateChildren.n_max != 0)) {
372fccd6 208 debugs(29, 9, HERE << "returning configured");
6bf4f823 209 return true;
210 }
211
372fccd6 212 debugs(29, 9, HERE << "returning unconfigured");
6bf4f823 213 return false;
214}
215
216/* Negotiate Scheme */
6bf4f823 217
218void
c7baff40 219Auth::Negotiate::Config::fixHeader(Auth::UserRequest::Pointer auth_user_request, HttpReply *rep, http_hdr_type reqType, HttpRequest * request)
6bf4f823 220{
58ee2093 221 if (!authenticateProgram)
6bf4f823 222 return;
223
81425fb6 224 /* Need keep-alive */
225 if (!request->flags.proxy_keepalive && request->flags.must_keepalive)
26ac0430 226 return;
81425fb6 227
6bf4f823 228 /* New request, no user details */
229 if (auth_user_request == NULL) {
372fccd6 230 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate'");
076df709 231 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
6bf4f823 232
233 if (!keep_alive) {
234 /* drop the connection */
a9925b40 235 rep->header.delByName("keep-alive");
6bf4f823 236 request->flags.proxy_keepalive = 0;
237 }
238 } else {
c7baff40 239 Auth::Negotiate::UserRequest *negotiate_request = dynamic_cast<Auth::Negotiate::UserRequest *>(auth_user_request.getRaw());
27da7c21 240 assert(negotiate_request != NULL);
241
d232141d 242 switch (negotiate_request->user()->credentials()) {
6bf4f823 243
d87154ee 244 case Auth::Failed:
6bf4f823 245 /* here it makes sense to drop the connection, as auth is
246 * tied to it, even if MAYBE the client could handle it - Kinkie */
a9925b40 247 rep->header.delByName("keep-alive");
6bf4f823 248 request->flags.proxy_keepalive = 0;
249 /* fall through */
250
d87154ee 251 case Auth::Ok:
6bf4f823 252 /* Special case: authentication finished OK but disallowed by ACL.
253 * Need to start over to give the client another chance.
254 */
6bf4f823 255 if (negotiate_request->server_blob) {
372fccd6 256 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
076df709 257 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
6bf4f823 258 safe_free(negotiate_request->server_blob);
259 } else {
372fccd6 260 debugs(29, 9, HERE << "Connection authenticated");
076df709 261 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
6bf4f823 262 }
6bf4f823 263 break;
264
d87154ee 265 case Auth::Unchecked:
6bf4f823 266 /* semantic change: do not drop the connection.
267 * 2.5 implementation used to keep it open - Kinkie */
372fccd6 268 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate'");
076df709 269 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
6bf4f823 270 break;
271
d87154ee 272 case Auth::Handshake:
6bf4f823 273 /* we're waiting for a response from the client. Pass it the blob */
372fccd6 274 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
076df709 275 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
6bf4f823 276 safe_free(negotiate_request->server_blob);
277 break;
278
6bf4f823 279 default:
372fccd6 280 debugs(29, DBG_CRITICAL, "ERROR: Negotiate auth fixHeader: state " << negotiate_request->user()->credentials() << ".");
6bf4f823 281 fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n");
282 }
283 }
284}
285
6bf4f823 286static void
287authenticateNegotiateStats(StoreEntry * sentry)
288{
81425fb6 289 helperStatefulStats(sentry, negotiateauthenticators, "Negotiate Authenticator Statistics");
6bf4f823 290}
291
6bf4f823 292/*
81425fb6 293 * Decode a Negotiate [Proxy-]Auth string, placing the results in the passed
6bf4f823 294 * Auth_user structure.
295 */
c7baff40 296Auth::UserRequest::Pointer
372fccd6 297Auth::Negotiate::Config::decode(char const *proxy_auth)
6bf4f823 298{
aa110616 299 Auth::Negotiate::User *newUser = new Auth::Negotiate::User(&negotiateConfig);
c7baff40 300 Auth::UserRequest *auth_user_request = new Auth::Negotiate::UserRequest();
6bf4f823 301 assert(auth_user_request->user() == NULL);
a33a428a 302
6bf4f823 303 auth_user_request->user(newUser);
616cfc4c 304 auth_user_request->user()->auth_type = Auth::AUTH_NEGOTIATE;
6bf4f823 305
81425fb6 306 /* all we have to do is identify that it's Negotiate - the helper does the rest */
372fccd6 307 debugs(29, 9, HERE << "decode Negotiate authentication");
6bf4f823 308 return auth_user_request;
309}