Squid Web Cache v8/master
Loading...
Searching...
No Matches
negotiate_sspi_auth.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2026 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/*
10 * negotiate_sspi_auth: helper for Negotiate Authentication for Squid Cache
11 *
12 * (C)2005 Guido Serassio - Acme Consulting S.r.l.
13 *
14 * Authors:
15 * Guido Serassio <guido.serassio@acmeconsulting.it>
16 * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
17 *
18 * With contributions from others mentioned in the change history section
19 * below.
20 *
21 * Based on previous work of Francesco Chemolli and Robert Collins.
22 *
23 * Dependencies: Windows 2000 and later.
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 2 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License along
36 * with this program; if not, see <https://www.gnu.org/licenses/>.
37 *
38 * History:
39 *
40 * Version 1.0
41 * 29-10-2005 Guido Serassio
42 * First release.
43 */
44
45#include "squid.h"
46#include "base64.h"
48#include "ntlmauth/ntlmauth.h"
50#include "sspi/sspwin32.h"
51#include "util.h"
52
53#include <cctype>
54#if HAVE_GETOPT_H
55#include <getopt.h>
56#endif
57
59static int have_serverblob;
60
61/* A couple of harmless helper macros */
62#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
63#ifdef __GNUC__
64#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
65#define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
66#else
67/* no gcc, no debugging. varargs macros are a gcc extension */
68#define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
69#define SEND3(X,Y,Z) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z);
70#endif
71
72/*
73 * options:
74 * -d enable debugging.
75 * -v enable verbose Negotiate packet debugging.
76 */
77char *my_program_name = nullptr;
78
79static void
81{
82 fprintf(stderr,
83 "Usage: %s [-d] [-v] [-h]\n"
84 " -d enable debugging.\n"
85 " -v enable verbose Negotiate packet debugging.\n"
86 " -h this message\n\n",
88}
89
90static void
91process_options(int argc, char *argv[])
92{
93 int opt, had_error = 0;
94
95 opterr = 0;
96 while (-1 != (opt = getopt(argc, argv, "hdv"))) {
97 switch (opt) {
98 case 'd':
99 debug_enabled = 1;
100 break;
101 case 'v':
102 debug_enabled = 1;
104 break;
105 case 'h':
106 usage();
107 exit(EXIT_SUCCESS);
108 case '?':
109 opt = optopt;
110 [[fallthrough]];
111 default:
112 fprintf(stderr, "ERROR: unknown option: -%c. Exiting\n", opt);
113 usage();
114 had_error = 1;
115 }
116 }
117 if (had_error)
118 exit(EXIT_FAILURE);
119}
120
121static bool
122token_decode(size_t *decodedLen, uint8_t decoded[], const char *buf)
123{
124 struct base64_decode_ctx ctx;
125 base64_decode_init(&ctx);
126 if (!base64_decode_update(&ctx, decodedLen, decoded, strlen(buf), buf) ||
127 !base64_decode_final(&ctx)) {
128 SEND("BH base64 decode failed");
129 fprintf(stderr, "ERROR: base64 decoding failed for: '%s'\n", buf);
130 return false;
131 }
132 return true;
133}
134
135static int
137{
138 char buf[HELPER_INPUT_BUFFER];
139 uint8_t decoded[HELPER_INPUT_BUFFER];
140 size_t decodedLen = 0;
141 char helper_command[3];
142 char *c;
143 int status;
144 int oversized = 0;
145 char *ErrorMessage;
146 static char cred[SSP_MAX_CRED_LEN + 1];
147 BOOL Done = FALSE;
148
149 do {
150 if (!fgets(buf, HELPER_INPUT_BUFFER, stdin))
151 return 0;
152
153 c = static_cast<char*>(memchr(buf, '\n', HELPER_INPUT_BUFFER));
154 if (c) {
155 if (oversized) {
156 SEND("BH illegal request received");
157 fprintf(stderr, "ERROR: Illegal request received: '%s'\n", buf);
158 return 1;
159 }
160 *c = '\0';
161 } else {
162 fprintf(stderr, "No newline in '%s'\n", buf);
163 oversized = 1;
164 }
165 } while (!c);
166
167 if ((strlen(buf) > 3) && Negotiate_packet_debug_enabled) {
168 if (!token_decode(&decodedLen, decoded, buf+3))
169 return 1;
170 xstrncpy(helper_command, buf, sizeof(helper_command));
171 debug("Got '%s' from Squid with data:\n", helper_command);
172 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
173 } else
174 debug("Got '%s' from Squid\n", buf);
175
176 if (memcmp(buf, "YR ", 3) == 0) { /* refresh-request */
177 /* figure out what we got */
178 if (!decodedLen /* already decoded */ && !token_decode(&decodedLen, decoded, buf+3))
179 return 1;
180 if (decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */
181 SEND("NA * Packet format error");
182 return 1;
183 }
184 /* Obtain server blob against SSPI */
185 c = (char *) SSP_MakeNegotiateBlob(decoded, decodedLen, &Done, &status, cred);
186
187 if (status == SSP_OK) {
188 if (Done) {
189 lc(cred); /* let's lowercase them for our convenience */
190 have_serverblob = 0;
191 Done = FALSE;
193 if (!token_decode(&decodedLen, decoded, c))
194 return 1;
195 debug("sending 'AF' %s to squid with data:\n", cred);
196 if (c != NULL)
197 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
198 else
199 fprintf(stderr, "No data available.\n");
200 printf("AF %s %s\n", c, cred);
201 } else
202 SEND3("AF %s %s", c, cred);
203 } else {
205 if (!token_decode(&decodedLen, decoded, c))
206 return 1;
207 debug("sending 'TT' to squid with data:\n");
208 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
209 printf("TT %s\n", c);
210 } else {
211 SEND2("TT %s", c);
212 }
213 have_serverblob = 1;
214 }
215 } else
216 SEND("BH can't obtain server blob");
217 return 1;
218 }
219 if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */
220 if (!have_serverblob) {
221 SEND("BH invalid server blob");
222 return 1;
223 }
224 /* figure out what we got */
225 if (!decodedLen /* already decoded */ && !token_decode(&decodedLen, decoded, buf+3))
226 return 1;
227 if (decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */
228 SEND("NA * Packet format error");
229 return 1;
230 }
231 /* check against SSPI */
232 c = (char *) SSP_ValidateNegotiateCredentials(decoded, decodedLen, &Done, &status, cred);
233
234 if (status == SSP_ERROR) {
235 const auto n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
236 FORMAT_MESSAGE_IGNORE_INSERTS,
237 nullptr,
238 GetLastError(),
239 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
240 (LPTSTR) & ErrorMessage,
241 0,
242 nullptr);
243 if (!n) {
244 SEND2("NA * Windows error: %s", GetLastError());
245 return 1;
246 }
247 if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n')
248 ErrorMessage[strlen(ErrorMessage) - 1] = '\0';
249 if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r')
250 ErrorMessage[strlen(ErrorMessage) - 1] = '\0';
251 SEND2("NA * %s", ErrorMessage);
252 LocalFree(ErrorMessage);
253 return 1;
254 }
255 if (Done) {
256 lc(cred); /* let's lowercase them for our convenience */
257 have_serverblob = 0;
258 Done = FALSE;
260 if (!token_decode(&decodedLen, decoded, c))
261 return 1;
262 debug("sending 'AF' %s to squid with data:\n", cred);
263 if (c != NULL)
264 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
265 else
266 fprintf(stderr, "No data available.\n");
267 printf("AF %s %s\n", c, cred);
268 } else {
269 SEND3("AF %s %s", c, cred);
270 }
271 return 1;
272 } else {
274 if (!token_decode(&decodedLen, decoded, c))
275 return 1;
276 debug("sending 'TT' to squid with data:\n");
277 hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen);
278 printf("TT %s\n", c);
279 } else
280 SEND2("TT %s", c);
281 return 1;
282 }
283
284 } else { /* not an auth-request */
285 SEND("BH illegal request received");
286 fprintf(stderr, "Illegal request received: '%s'\n", buf);
287 return 1;
288 }
289 SEND("BH detected protocol error");
290 return 1;
291 /********* END ********/
292}
293
294int
295main(int argc, char *argv[])
296{
297 my_program_name = argv[0];
298
299 process_options(argc, argv);
300
301 debug("%s " VERSION " " SQUID_BUILD_INFO " starting up...\n", my_program_name);
302
304 fprintf(stderr, "FATAL: %s: can't initialize SSPI, exiting.\n", argv[0]);
305 exit(EXIT_FAILURE);
306 }
307 debug("SSPI initialized OK\n");
308
309 atexit(UnloadSecurityDll);
310
311 /* initialize FDescs */
312 setbuf(stdout, nullptr);
313 setbuf(stderr, nullptr);
314
315 while (manage_request()) {
316 /* everything is done within manage_request */
317 }
318 return EXIT_SUCCESS;
319}
320
#define VERSION
Definition autoconf.h:1670
#define SQUID_BUILD_INFO
Definition autoconf.h:1413
void base64_decode_init(struct base64_decode_ctx *ctx)
Definition base64.cc:54
int base64_decode_update(struct base64_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, const char *src)
Definition base64.cc:129
int base64_decode_final(struct base64_decode_ctx *ctx)
Definition base64.cc:159
#define HELPER_INPUT_BUFFER
int debug_enabled
Definition debug.cc:13
void debug(const char *format,...)
Definition debug.cc:19
#define FALSE
Definition defines.h:16
int optopt
Definition getopt.c:49
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition getopt.c:62
int opterr
Definition getopt.c:47
int main()
#define SEND3(X, Y, Z)
static bool token_decode(size_t *decodedLen, uint8_t decoded[], const char *buf)
#define SEND(X)
static int manage_request()
static void usage()
static void process_options(int argc, char *argv[])
char * my_program_name
static int have_serverblob
int Negotiate_packet_debug_enabled
#define SEND2(X, Y)
void UnloadSecurityDll(void)
Definition sspwin32.cc:77
HMODULE LoadSecurityDll(int mode, const char *SSP_Package)
Definition sspwin32.cc:104
#define SSP_MAX_CRED_LEN
Definition sspwin32.h:45
#define SSP_OK
Definition sspwin32.h:49
#define NEGOTIATE_PACKAGE_NAME
Definition sspwin32.h:19
#define SSP_NTLM
Definition sspwin32.h:43
#define SSP_ERROR
Definition sspwin32.h:50
void lc(char *string)
void hex_dump(unsigned char *data, int size)
#define NULL
Definition types.h:145
char * xstrncpy(char *dst, const char *src, size_t n)
Definition xstring.cc:37