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