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