]> git.ipfire.org Git - thirdparty/squid.git/blob - src/auth/negotiate/Config.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / auth / negotiate / Config.cc
1 /*
2 * Copyright (C) 1996-2021 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
34 static AUTHSSTATS authenticateNegotiateStats;
35
36 statefulhelper *negotiateauthenticators = NULL;
37
38 static int authnegotiate_initialised = 0;
39
40 static hash_table *proxy_auth_cache = NULL;
41
42 void
43 Auth::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
53 void
54 Auth::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
76 const char *
77 Auth::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 */
86 void
87 Auth::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
111 void
112 Auth::Negotiate::Config::registerWithCacheManager(void)
113 {
114 Mgr::RegisterAction("negotiateauthenticator",
115 "Negotiate User Authenticator Stats",
116 authenticateNegotiateStats, 0, 1);
117 }
118
119 bool
120 Auth::Negotiate::Config::active() const
121 {
122 return authnegotiate_initialised == 1;
123 }
124
125 bool
126 Auth::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
137 void
138 Auth::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
205 static void
206 authenticateNegotiateStats(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 */
216 Auth::UserRequest::Pointer
217 Auth::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