]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/negotiate/wrapper/negotiate_wrapper.cc
mkrelease: allow two digits for minor release numbers (#1837)
[thirdparty/squid.git] / src / auth / negotiate / wrapper / negotiate_wrapper.cc
CommitLineData
ca02e0ec 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
ca02e0ec
AJ
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
eb3dea38
MM
9/*
10 * -----------------------------------------------------------------------------
11 *
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
13 *
14 * Copyright (C) 2011 Markus Moeller. All rights reserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
29 *
30 * -----------------------------------------------------------------------------
31 */
eb3dea38 32
f7f3304a 33#include "squid.h"
8bdd0cec 34#include "base64.h"
eb3dea38 35
074d6a40
AJ
36#include <cerrno>
37#include <cstring>
38#include <cstdlib>
39#include <ctime>
eb3dea38
MM
40#if HAVE_NETDB_H
41#include <netdb.h>
42#endif
43#if HAVE_UNISTD_H
44#include <unistd.h>
45#endif
eb3dea38
MM
46
47#if !defined(HAVE_DECL_XMALLOC) || !HAVE_DECL_XMALLOC
48#define xmalloc malloc
49#endif
50#if !defined(HAVE_DECL_XSTRDUP) || !HAVE_DECL_XSTRDUP
51#define xstrdup strdup
52#endif
53#if !defined(HAVE_DECL_XFREE) || !HAVE_DECL_XFREE
54#define xfree free
55#endif
56
57#undef PROGRAM
58#define PROGRAM "negotiate_wrapper"
59#undef VERSION
60#define VERSION "1.0.1"
61
62#ifndef MAX_AUTHTOKEN_LEN
63#define MAX_AUTHTOKEN_LEN 65535
64#endif
65
66static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
67
68static const char *
69LogTime()
70{
eb3dea38
MM
71 struct timeval now;
72 static time_t last_t = 0;
73 static char buf[128];
74
aee3523a 75 gettimeofday(&now, nullptr);
eb3dea38 76 if (now.tv_sec != last_t) {
3a2e0253
AJ
77 time_t *tmp = (time_t *) & now.tv_sec;
78 struct tm *tm = localtime(tmp);
eb3dea38
MM
79 strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
80 last_t = now.tv_sec;
81 }
82 return buf;
83}
84
8b082ed9
FC
85static void
86usage()
eb3dea38
MM
87{
88 fprintf(stderr, "Usage: \n");
89 fprintf(stderr, "negotiate_wrapper [-h] [-d] --ntlm ntlm helper + arguments --kerberos kerberos helper + arguments\n");
90 fprintf(stderr, "-h help\n");
91 fprintf(stderr, "-d full debug\n");
92 fprintf(stderr, "--ntlm full ntlm helper path with arguments\n");
93 fprintf(stderr, "--kerberos full kerberos helper path with arguments\n");
94}
95
af845cee
AJ
96static void
97closeFds(FILE *a, FILE *b, FILE *c, FILE *d)
98{
e0702229 99 if (a)
af845cee 100 fclose(a);
e0702229 101 if (b)
af845cee 102 fclose(b);
e0702229 103 if (c)
af845cee 104 fclose(c);
e0702229 105 if (d)
af845cee
AJ
106 fclose(d);
107}
108
109static int
110processingLoop(FILE *FDKIN, FILE *FDKOUT, FILE *FDNIN, FILE *FDNOUT)
eb3dea38
MM
111{
112 char buf[MAX_AUTHTOKEN_LEN];
113 char tbuff[MAX_AUTHTOKEN_LEN];
114 char buff[MAX_AUTHTOKEN_LEN+2];
a86a4d3c 115 char *c;
04b008df 116 size_t length;
aee3523a 117 uint8_t *token = nullptr;
af845cee
AJ
118
119 while (1) {
aee3523a 120 if (fgets(buf, sizeof(buf) - 1, stdin) == nullptr) {
e3a5c24c 121 xfree(token);
af845cee
AJ
122 if (ferror(stdin)) {
123 if (debug_enabled)
124 fprintf(stderr,
125 "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
126 LogTime(), PROGRAM, ferror(stdin),
127 strerror(ferror(stdin)));
128
129 fprintf(stdout, "BH input error\n");
130 return 1; /* BIIG buffer */
131 }
132 fprintf(stdout, "BH input error\n");
133 return 0;
134 }
135 c = static_cast<char*>(memchr(buf, '\n', sizeof(buf) - 1));
136 if (c) {
137 *c = '\0';
138 length = c - buf;
139 if (debug_enabled)
a20724e4 140 fprintf(stderr, "%s| %s: Got '%s' from squid (length: %zu).\n",
af845cee
AJ
141 LogTime(), PROGRAM, buf, length);
142 } else {
143 if (debug_enabled)
144 fprintf(stderr, "%s| %s: Oversized message\n", LogTime(),
145 PROGRAM);
146 fprintf(stdout, "BH Oversized message\n");
147 continue;
148 }
149
150 if (buf[0] == '\0') {
151 if (debug_enabled)
152 fprintf(stderr, "%s| %s: Invalid request\n", LogTime(),
153 PROGRAM);
154 fprintf(stdout, "BH Invalid request\n");
155 continue;
156 }
157 if (strlen(buf) < 2) {
158 if (debug_enabled)
159 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
160 PROGRAM, buf);
161 fprintf(stdout, "BH Invalid request\n");
162 continue;
163 }
164 if (!strncmp(buf, "QQ", 2)) {
165 fprintf(stdout, "BH quit command\n");
92c2f0bd 166 xfree(token);
af845cee
AJ
167 return 0;
168 }
169 if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
170 if (debug_enabled)
171 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
172 PROGRAM, buf);
173 fprintf(stdout, "BH Invalid request\n");
174 continue;
175 }
176 if (strlen(buf) <= 3) {
177 if (debug_enabled)
178 fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
179 LogTime(), PROGRAM, buf);
180 fprintf(stdout, "BH Invalid negotiate request\n");
181 continue;
182 }
183 length = BASE64_DECODE_LENGTH(strlen(buf+3));
184 if (debug_enabled)
a20724e4 185 fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %zu).\n",
04b008df 186 LogTime(), PROGRAM, buf + 3, length);
af845cee 187
e3a5c24c 188 safe_free(token);
04b008df 189 if (!(token = static_cast<uint8_t *>(xmalloc(length+1)))) {
af845cee
AJ
190 fprintf(stderr, "%s| %s: Error allocating memory for token\n", LogTime(), PROGRAM);
191 return 1;
192 }
193
194 struct base64_decode_ctx ctx;
195 base64_decode_init(&ctx);
196 size_t dstLen = 0;
1d11e9b3 197 if (!base64_decode_update(&ctx, &dstLen, token, strlen(buf+3), buf+3) ||
af845cee
AJ
198 !base64_decode_final(&ctx)) {
199 if (debug_enabled)
200 fprintf(stderr, "%s| %s: Invalid base64 token [%s]\n", LogTime(), PROGRAM, buf+3);
201 fprintf(stdout, "BH Invalid negotiate request token\n");
202 continue;
203 }
04b008df 204 assert(dstLen <= length);
af845cee
AJ
205 length = dstLen;
206 token[dstLen] = '\0';
207
208 if ((static_cast<size_t>(length) >= sizeof(ntlmProtocol) + 1) &&
209 (!memcmp(token, ntlmProtocol, sizeof ntlmProtocol))) {
af845cee
AJ
210 if (debug_enabled)
211 fprintf(stderr, "%s| %s: received type %d NTLM token\n",
212 LogTime(), PROGRAM, (int) *((unsigned char *) token +
213 sizeof ntlmProtocol));
214 fprintf(FDNIN, "%s\n",buf);
aee3523a 215 if (fgets(tbuff, sizeof(tbuff) - 1, FDNOUT) == nullptr) {
e3a5c24c 216 xfree(token);
af845cee
AJ
217 if (ferror(FDNOUT)) {
218 fprintf(stderr,
219 "fgets() failed! dying..... errno=%d (%s)\n",
220 ferror(FDNOUT), strerror(ferror(FDNOUT)));
221 return 1;
222 }
223 fprintf(stderr, "%s| %s: Error reading NTLM helper response\n",
224 LogTime(), PROGRAM);
225 return 0;
226 }
3238ca57
AR
227
228 if (!memchr(tbuff, '\n', sizeof(tbuff) - 1)) {
229 fprintf(stderr, "%s| %s: Oversized NTLM helper response\n",
230 LogTime(), PROGRAM);
231 return 0;
232 }
233
af845cee 234 /*
e3a5c24c
AJ
235 * Need to translate NTLM reply to Negotiate reply:
236 * AF user => AF blob user
237 * NA reason => NA blob reason
238 * Set blob to '='
239 */
af845cee
AJ
240 if (strlen(tbuff) >= 3 && (!strncmp(tbuff,"AF ",3) || !strncmp(tbuff,"NA ",3))) {
241 strncpy(buff,tbuff,3);
242 buff[3]='=';
243 for (unsigned int i=2; i<=strlen(tbuff); ++i)
244 buff[i+2] = tbuff[i];
245 } else {
246 strcpy(buff,tbuff);
247 }
248 } else {
af845cee
AJ
249 if (debug_enabled)
250 fprintf(stderr, "%s| %s: received Kerberos token\n",
251 LogTime(), PROGRAM);
252
253 fprintf(FDKIN, "%s\n",buf);
aee3523a 254 if (fgets(buff, sizeof(buff) - 1, FDKOUT) == nullptr) {
e3a5c24c 255 xfree(token);
af845cee
AJ
256 if (ferror(FDKOUT)) {
257 fprintf(stderr,
258 "fgets() failed! dying..... errno=%d (%s)\n",
259 ferror(FDKOUT), strerror(ferror(FDKOUT)));
260 return 1;
261 }
262 fprintf(stderr, "%s| %s: Error reading Kerberos helper response\n",
263 LogTime(), PROGRAM);
264 return 0;
265 }
3238ca57
AR
266
267 if (!memchr(buff, '\n', sizeof(buff) - 1)) {
268 fprintf(stderr, "%s| %s: Oversized Kerberos helper response\n",
269 LogTime(), PROGRAM);
270 return 0;
271 }
af845cee 272 }
265d1cc5 273 buff[sizeof(buff)-1] = '\0'; // paranoid; already terminated correctly
af845cee
AJ
274 fprintf(stdout,"%s",buff);
275 if (debug_enabled)
276 fprintf(stderr, "%s| %s: Return '%s'\n",
277 LogTime(), PROGRAM, buff);
278 }
279
e3a5c24c 280 xfree(token);
af845cee
AJ
281 return 1;
282}
283
284int
285main(int argc, char *const argv[])
286{
eb3dea38
MM
287 int nstart = 0, kstart = 0;
288 int nend = 0, kend = 0;
eb3dea38 289 char **nargs, **kargs;
eb3dea38 290 int fpid;
eb3dea38
MM
291 int pkin[2];
292 int pkout[2];
293 int pnin[2];
294 int pnout[2];
295
aee3523a
AR
296 setbuf(stdout, nullptr);
297 setbuf(stdin, nullptr);
eb3dea38
MM
298
299 if (argc ==1 || !strncasecmp(argv[1],"-h",2)) {
300 usage();
24885773 301 exit(EXIT_SUCCESS);
eb3dea38
MM
302 }
303
72841dbb 304 int j = 1;
eb3dea38 305 if (!strncasecmp(argv[1],"-d",2)) {
af845cee 306 debug_enabled = 1;
eb3dea38
MM
307 j = 2;
308 }
309
72841dbb 310 for (int i=j; i<argc; ++i) {
eb3dea38
MM
311 if (!strncasecmp(argv[i],"--ntlm",6))
312 nstart = i;
313 if (!strncasecmp(argv[i],"--kerberos",10))
314 kstart = i;
315 }
316 if (nstart > kstart) {
317 kend = nstart-1;
318 nend = argc-1;
319 } else {
320 kend = argc-1;
321 nend = kstart-1;
322 }
323 if (nstart == 0 || kstart == 0 || kend-kstart <= 0 || nend-nstart <= 0 ) {
324 usage();
24885773 325 exit(EXIT_SUCCESS);
eb3dea38
MM
326 }
327
af845cee 328 if (debug_enabled)
eb3dea38
MM
329 fprintf(stderr, "%s| %s: Starting version %s\n", LogTime(), PROGRAM,
330 VERSION);
331
aee3523a 332 if ((nargs = (char **)xmalloc((nend-nstart+1)*sizeof(char *))) == nullptr) {
eb3dea38 333 fprintf(stderr, "%s| %s: Error allocating memory for ntlm helper\n", LogTime(), PROGRAM);
24885773 334 exit(EXIT_FAILURE);
eb3dea38
MM
335 }
336 memcpy(nargs,argv+nstart+1,(nend-nstart)*sizeof(char *));
aee3523a 337 nargs[nend-nstart]=nullptr;
af845cee 338 if (debug_enabled) {
eb3dea38 339 fprintf(stderr, "%s| %s: NTLM command: ", LogTime(), PROGRAM);
72841dbb 340 for (int i=0; i<nend-nstart; ++i)
eb3dea38
MM
341 fprintf(stderr, "%s ", nargs[i]);
342 fprintf(stderr, "\n");
343 }
aee3523a 344 if ((kargs = (char **)xmalloc((kend-kstart+1)*sizeof(char *))) == nullptr) {
eb3dea38 345 fprintf(stderr, "%s| %s: Error allocating memory for kerberos helper\n", LogTime(), PROGRAM);
24885773 346 exit(EXIT_FAILURE);
eb3dea38
MM
347 }
348 memcpy(kargs,argv+kstart+1,(kend-kstart)*sizeof(char *));
aee3523a 349 kargs[kend-kstart]=nullptr;
af845cee 350 if (debug_enabled) {
eb3dea38 351 fprintf(stderr, "%s| %s: Kerberos command: ", LogTime(), PROGRAM);
72841dbb 352 for (int i=0; i<kend-kstart; ++i)
eb3dea38
MM
353 fprintf(stderr, "%s ", kargs[i]);
354 fprintf(stderr, "\n");
355 }
356 /*
357 Fork Kerberos helper and NTLM helper and manage IO to send NTLM requests
358 to the right helper. squid must keep session state
359 */
360
3a2e0253
AJ
361 if (pipe(pkin) < 0) {
362 fprintf(stderr, "%s| %s: Could not assign streams for pkin\n", LogTime(), PROGRAM);
24885773 363 exit(EXIT_FAILURE);
3a2e0253
AJ
364 }
365 if (pipe(pkout) < 0) {
366 fprintf(stderr, "%s| %s: Could not assign streams for pkout\n", LogTime(), PROGRAM);
24885773 367 exit(EXIT_FAILURE);
3a2e0253
AJ
368 }
369
bd05c0b5 370 if (( fpid = fork()) < 0 ) {
eb3dea38 371 fprintf(stderr, "%s| %s: Failed first fork\n", LogTime(), PROGRAM);
24885773 372 exit(EXIT_FAILURE);
eb3dea38
MM
373 }
374
375 if ( fpid == 0 ) {
376 /* First Child for Kerberos helper */
377
378 close(pkin[1]);
379 dup2(pkin[0],STDIN_FILENO);
380 close(pkin[0]);
381
382 close(pkout[0]);
383 dup2(pkout[1],STDOUT_FILENO);
384 close(pkout[1]);
385
aee3523a
AR
386 setbuf(stdin, nullptr);
387 setbuf(stdout, nullptr);
eb3dea38
MM
388
389 execv(kargs[0], kargs);
390 fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, kargs[0], strerror(errno));
24885773 391 exit(EXIT_FAILURE);
eb3dea38
MM
392 }
393
394 close(pkin[0]);
395 close(pkout[1]);
396
3a2e0253
AJ
397 if (pipe(pnin) < 0) {
398 fprintf(stderr, "%s| %s: Could not assign streams for pnin\n", LogTime(), PROGRAM);
24885773 399 exit(EXIT_FAILURE);
3a2e0253
AJ
400 }
401 if (pipe(pnout) < 0) {
402 fprintf(stderr, "%s| %s: Could not assign streams for pnout\n", LogTime(), PROGRAM);
24885773 403 exit(EXIT_FAILURE);
3a2e0253 404 }
eb3dea38 405
bd05c0b5 406 if (( fpid = fork()) < 0 ) {
eb3dea38 407 fprintf(stderr, "%s| %s: Failed second fork\n", LogTime(), PROGRAM);
24885773 408 exit(EXIT_FAILURE);
eb3dea38
MM
409 }
410
411 if ( fpid == 0 ) {
412 /* Second Child for NTLM helper */
413
414 close(pnin[1]);
415 dup2(pnin[0],STDIN_FILENO);
416 close(pnin[0]);
417
418 close(pnout[0]);
419 dup2(pnout[1],STDOUT_FILENO);
420 close(pnout[1]);
421
aee3523a
AR
422 setbuf(stdin, nullptr);
423 setbuf(stdout, nullptr);
eb3dea38
MM
424
425 execv(nargs[0], nargs);
426 fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, nargs[0], strerror(errno));
24885773 427 exit(EXIT_FAILURE);
eb3dea38
MM
428 }
429
430 close(pnin[0]);
431 close(pnout[1]);
432
af845cee
AJ
433 FILE *FDKIN=fdopen(pkin[1],"w");
434 FILE *FDKOUT=fdopen(pkout[0],"r");
eb3dea38 435
af845cee
AJ
436 FILE *FDNIN=fdopen(pnin[1],"w");
437 FILE *FDNOUT=fdopen(pnout[0],"r");
eb3dea38
MM
438
439 if (!FDKIN || !FDKOUT || !FDNIN || !FDNOUT) {
a86a4d3c 440 fprintf(stderr, "%s| %s: Could not assign streams for FDKIN/FDKOUT/FDNIN/FDNOUT\n", LogTime(), PROGRAM);
af845cee 441 closeFds(FDKIN, FDKOUT, FDNIN, FDNOUT);
24885773 442 exit(EXIT_FAILURE);
eb3dea38
MM
443 }
444
aee3523a
AR
445 setbuf(FDKIN, nullptr);
446 setbuf(FDKOUT, nullptr);
447 setbuf(FDNIN, nullptr);
448 setbuf(FDNOUT, nullptr);
eb3dea38 449
af845cee
AJ
450 int result = processingLoop(FDKIN, FDKOUT, FDNIN, FDNOUT);
451 closeFds(FDKIN, FDKOUT, FDNIN, FDNOUT);
452 return result;
eb3dea38 453}
f53969cc 454