]> git.ipfire.org Git - thirdparty/squid.git/blame_incremental - src/auth/negotiate/Config.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / auth / negotiate / Config.cc
... / ...
CommitLineData
1/*
2 * Copyright (C) 1996-2020 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/* DEBUG: section 29 Negotiate Authenticator */
10
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
15#include "squid.h"
16#include "auth/Gadgets.h"
17#include "auth/negotiate/Config.h"
18#include "auth/negotiate/Scheme.h"
19#include "auth/negotiate/User.h"
20#include "auth/negotiate/UserRequest.h"
21#include "auth/State.h"
22#include "cache_cf.h"
23#include "client_side.h"
24#include "helper.h"
25#include "http/Stream.h"
26#include "HttpHeaderTools.h"
27#include "HttpReply.h"
28#include "HttpRequest.h"
29#include "mgr/Registration.h"
30#include "SquidTime.h"
31#include "Store.h"
32#include "wordlist.h"
33
34static AUTHSSTATS authenticateNegotiateStats;
35
36statefulhelper *negotiateauthenticators = NULL;
37
38static int authnegotiate_initialised = 0;
39
40static hash_table *proxy_auth_cache = NULL;
41
42void
43Auth::Negotiate::Config::rotateHelpers()
44{
45 /* schedule closure of existing helpers */
46 if (negotiateauthenticators) {
47 helperStatefulShutdown(negotiateauthenticators);
48 }
49
50 /* NP: dynamic helper restart will ensure they start up again as needed. */
51}
52
53void
54Auth::Negotiate::Config::done()
55{
56 Auth::SchemeConfig::done();
57
58 authnegotiate_initialised = 0;
59
60 if (negotiateauthenticators) {
61 helperStatefulShutdown(negotiateauthenticators);
62 }
63
64 if (!shutting_down)
65 return;
66
67 delete negotiateauthenticators;
68 negotiateauthenticators = NULL;
69
70 if (authenticateProgram)
71 wordlistDestroy(&authenticateProgram);
72
73 debugs(29, DBG_IMPORTANT, "Reconfigure: Negotiate authentication configuration cleared.");
74}
75
76const char *
77Auth::Negotiate::Config::type() const
78{
79 return Auth::Negotiate::Scheme::GetInstance()->type();
80}
81
82/**
83 * Initialize helpers and the like for this auth scheme.
84 * Called AFTER parsing the config file
85 */
86void
87Auth::Negotiate::Config::init(Auth::SchemeConfig *)
88{
89 if (authenticateProgram) {
90
91 authnegotiate_initialised = 1;
92
93 if (negotiateauthenticators == NULL)
94 negotiateauthenticators = new statefulhelper("negotiateauthenticator");
95
96 if (!proxy_auth_cache)
97 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
98
99 assert(proxy_auth_cache);
100
101 negotiateauthenticators->cmdline = authenticateProgram;
102
103 negotiateauthenticators->childs.updateLimits(authenticateChildren);
104
105 negotiateauthenticators->ipc_type = IPC_STREAM;
106
107 helperStatefulOpenServers(negotiateauthenticators);
108 }
109}
110
111void
112Auth::Negotiate::Config::registerWithCacheManager(void)
113{
114 Mgr::RegisterAction("negotiateauthenticator",
115 "Negotiate User Authenticator Stats",
116 authenticateNegotiateStats, 0, 1);
117}
118
119bool
120Auth::Negotiate::Config::active() const
121{
122 return authnegotiate_initialised == 1;
123}
124
125bool
126Auth::Negotiate::Config::configured() const
127{
128 if (authenticateProgram && (authenticateChildren.n_max != 0)) {
129 debugs(29, 9, HERE << "returning configured");
130 return true;
131 }
132
133 debugs(29, 9, HERE << "returning unconfigured");
134 return false;
135}
136
137void
138Auth::Negotiate::Config::fixHeader(Auth::UserRequest::Pointer auth_user_request, HttpReply *rep, Http::HdrType reqType, HttpRequest * request)
139{
140 if (!authenticateProgram)
141 return;
142
143 /* Need keep-alive */
144 if (!request->flags.proxyKeepalive && request->flags.mustKeepalive)
145 return;
146
147 /* New request, no user details */
148 if (auth_user_request == NULL) {
149 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate'");
150 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
151
152 if (!keep_alive) {
153 /* drop the connection */
154 rep->header.delByName("keep-alive");
155 request->flags.proxyKeepalive = false;
156 }
157 } else {
158 Auth::Negotiate::UserRequest *negotiate_request = dynamic_cast<Auth::Negotiate::UserRequest *>(auth_user_request.getRaw());
159 assert(negotiate_request != NULL);
160
161 switch (negotiate_request->user()->credentials()) {
162
163 case Auth::Failed:
164 /* here it makes sense to drop the connection, as auth is
165 * tied to it, even if MAYBE the client could handle it - Kinkie */
166 rep->header.delByName("keep-alive");
167 request->flags.proxyKeepalive = false;
168 /* fall through */
169
170 case Auth::Ok:
171 /* Special case: authentication finished OK but disallowed by ACL.
172 * Need to start over to give the client another chance.
173 */
174 if (negotiate_request->server_blob) {
175 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
176 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
177 safe_free(negotiate_request->server_blob);
178 } else {
179 debugs(29, 9, HERE << "Connection authenticated");
180 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
181 }
182 break;
183
184 case Auth::Unchecked:
185 /* semantic change: do not drop the connection.
186 * 2.5 implementation used to keep it open - Kinkie */
187 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate'");
188 httpHeaderPutStrf(&rep->header, reqType, "Negotiate");
189 break;
190
191 case Auth::Handshake:
192 /* we're waiting for a response from the client. Pass it the blob */
193 debugs(29, 9, HERE << "Sending type:" << reqType << " header: 'Negotiate " << negotiate_request->server_blob << "'");
194 httpHeaderPutStrf(&rep->header, reqType, "Negotiate %s", negotiate_request->server_blob);
195 safe_free(negotiate_request->server_blob);
196 break;
197
198 default:
199 debugs(29, DBG_CRITICAL, "ERROR: Negotiate auth fixHeader: state " << negotiate_request->user()->credentials() << ".");
200 fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n");
201 }
202 }
203}
204
205static void
206authenticateNegotiateStats(StoreEntry * sentry)
207{
208 if (negotiateauthenticators)
209 negotiateauthenticators->packStatsInto(sentry, "Negotiate Authenticator Statistics");
210}
211
212/*
213 * Decode a Negotiate [Proxy-]Auth string, placing the results in the passed
214 * Auth_user structure.
215 */
216Auth::UserRequest::Pointer
217Auth::Negotiate::Config::decode(char const *proxy_auth, const HttpRequest *, const char *aRequestRealm)
218{
219 Auth::Negotiate::User *newUser = new Auth::Negotiate::User(Auth::SchemeConfig::Find("negotiate"), aRequestRealm);
220 Auth::UserRequest *auth_user_request = new Auth::Negotiate::UserRequest();
221 assert(auth_user_request->user() == NULL);
222
223 auth_user_request->user(newUser);
224 auth_user_request->user()->auth_type = Auth::AUTH_NEGOTIATE;
225
226 auth_user_request->user()->BuildUserKey(proxy_auth, aRequestRealm);
227
228 /* all we have to do is identify that it's Negotiate - the helper does the rest */
229 debugs(29, 9, HERE << "decode Negotiate authentication");
230 return auth_user_request;
231}
232