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