]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/auth/negotiate/wrapper/negotiate_wrapper.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
10 * -----------------------------------------------------------------------------
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
14 * Copyright (C) 2011 Markus Moeller. All rights reserved.
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.
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.
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.
30 * -----------------------------------------------------------------------------
47 #if !defined(HAVE_DECL_XMALLOC) || !HAVE_DECL_XMALLOC
48 #define xmalloc malloc
50 #if !defined(HAVE_DECL_XSTRDUP) || !HAVE_DECL_XSTRDUP
51 #define xstrdup strdup
53 #if !defined(HAVE_DECL_XFREE) || !HAVE_DECL_XFREE
58 #define PROGRAM "negotiate_wrapper"
60 #define VERSION "1.0.1"
62 #ifndef MAX_AUTHTOKEN_LEN
63 #define MAX_AUTHTOKEN_LEN 65535
66 static const unsigned char ntlmProtocol
[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
72 static time_t last_t
= 0;
75 gettimeofday(&now
, nullptr);
76 if (now
.tv_sec
!= last_t
) {
77 time_t *tmp
= (time_t *) & now
.tv_sec
;
78 struct tm
*tm
= localtime(tmp
);
79 strftime(buf
, 127, "%Y/%m/%d %H:%M:%S", tm
);
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");
97 closeFds(FILE *a
, FILE *b
, FILE *c
, FILE *d
)
110 processingLoop(FILE *FDKIN
, FILE *FDKOUT
, FILE *FDNIN
, FILE *FDNOUT
)
112 char buf
[MAX_AUTHTOKEN_LEN
];
113 char tbuff
[MAX_AUTHTOKEN_LEN
];
114 char buff
[MAX_AUTHTOKEN_LEN
+2];
117 uint8_t *token
= nullptr;
120 if (fgets(buf
, sizeof(buf
) - 1, stdin
) == nullptr) {
125 "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
126 LogTime(), PROGRAM
, ferror(stdin
),
127 strerror(ferror(stdin
)));
129 fprintf(stdout
, "BH input error\n");
130 return 1; /* BIIG buffer */
132 fprintf(stdout
, "BH input error\n");
135 c
= static_cast<char*>(memchr(buf
, '\n', sizeof(buf
) - 1));
140 fprintf(stderr
, "%s| %s: Got '%s' from squid (length: %zu).\n",
141 LogTime(), PROGRAM
, buf
, length
);
144 fprintf(stderr
, "%s| %s: Oversized message\n", LogTime(),
146 fprintf(stdout
, "BH Oversized message\n");
150 if (buf
[0] == '\0') {
152 fprintf(stderr
, "%s| %s: Invalid request\n", LogTime(),
154 fprintf(stdout
, "BH Invalid request\n");
157 if (strlen(buf
) < 2) {
159 fprintf(stderr
, "%s| %s: Invalid request [%s]\n", LogTime(),
161 fprintf(stdout
, "BH Invalid request\n");
164 if (!strncmp(buf
, "QQ", 2)) {
165 fprintf(stdout
, "BH quit command\n");
169 if (strncmp(buf
, "YR", 2) && strncmp(buf
, "KK", 2)) {
171 fprintf(stderr
, "%s| %s: Invalid request [%s]\n", LogTime(),
173 fprintf(stdout
, "BH Invalid request\n");
176 if (strlen(buf
) <= 3) {
178 fprintf(stderr
, "%s| %s: Invalid negotiate request [%s]\n",
179 LogTime(), PROGRAM
, buf
);
180 fprintf(stdout
, "BH Invalid negotiate request\n");
183 length
= BASE64_DECODE_LENGTH(strlen(buf
+3));
185 fprintf(stderr
, "%s| %s: Decode '%s' (decoded length: %zu).\n",
186 LogTime(), PROGRAM
, buf
+ 3, length
);
189 if (!(token
= static_cast<uint8_t *>(xmalloc(length
+1)))) {
190 fprintf(stderr
, "%s| %s: Error allocating memory for token\n", LogTime(), PROGRAM
);
194 struct base64_decode_ctx ctx
;
195 base64_decode_init(&ctx
);
197 if (!base64_decode_update(&ctx
, &dstLen
, token
, strlen(buf
+3), buf
+3) ||
198 !base64_decode_final(&ctx
)) {
200 fprintf(stderr
, "%s| %s: Invalid base64 token [%s]\n", LogTime(), PROGRAM
, buf
+3);
201 fprintf(stdout
, "BH Invalid negotiate request token\n");
204 assert(dstLen
<= length
);
206 token
[dstLen
] = '\0';
208 if ((static_cast<size_t>(length
) >= sizeof(ntlmProtocol
) + 1) &&
209 (!memcmp(token
, ntlmProtocol
, sizeof ntlmProtocol
))) {
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
);
215 if (fgets(tbuff
, sizeof(tbuff
) - 1, FDNOUT
) == nullptr) {
217 if (ferror(FDNOUT
)) {
219 "fgets() failed! dying..... errno=%d (%s)\n",
220 ferror(FDNOUT
), strerror(ferror(FDNOUT
)));
223 fprintf(stderr
, "%s| %s: Error reading NTLM helper response\n",
228 if (!memchr(tbuff
, '\n', sizeof(tbuff
) - 1)) {
229 fprintf(stderr
, "%s| %s: Oversized NTLM helper response\n",
235 * Need to translate NTLM reply to Negotiate reply:
236 * AF user => AF blob user
237 * NA reason => NA blob reason
240 if (strlen(tbuff
) >= 3 && (!strncmp(tbuff
,"AF ",3) || !strncmp(tbuff
,"NA ",3))) {
241 strncpy(buff
,tbuff
,3);
243 for (unsigned int i
=2; i
<=strlen(tbuff
); ++i
)
244 buff
[i
+2] = tbuff
[i
];
250 fprintf(stderr
, "%s| %s: received Kerberos token\n",
253 fprintf(FDKIN
, "%s\n",buf
);
254 if (fgets(buff
, sizeof(buff
) - 1, FDKOUT
) == nullptr) {
256 if (ferror(FDKOUT
)) {
258 "fgets() failed! dying..... errno=%d (%s)\n",
259 ferror(FDKOUT
), strerror(ferror(FDKOUT
)));
262 fprintf(stderr
, "%s| %s: Error reading Kerberos helper response\n",
267 if (!memchr(buff
, '\n', sizeof(buff
) - 1)) {
268 fprintf(stderr
, "%s| %s: Oversized Kerberos helper response\n",
273 buff
[sizeof(buff
)-1] = '\0'; // paranoid; already terminated correctly
274 fprintf(stdout
,"%s",buff
);
276 fprintf(stderr
, "%s| %s: Return '%s'\n",
277 LogTime(), PROGRAM
, buff
);
285 main(int argc
, char *const argv
[])
287 int nstart
= 0, kstart
= 0;
288 int nend
= 0, kend
= 0;
289 char **nargs
, **kargs
;
296 setbuf(stdout
, nullptr);
297 setbuf(stdin
, nullptr);
299 if (argc
==1 || !strncasecmp(argv
[1],"-h",2)) {
305 if (!strncasecmp(argv
[1],"-d",2)) {
310 for (int i
=j
; i
<argc
; ++i
) {
311 if (!strncasecmp(argv
[i
],"--ntlm",6))
313 if (!strncasecmp(argv
[i
],"--kerberos",10))
316 if (nstart
> kstart
) {
323 if (nstart
== 0 || kstart
== 0 || kend
-kstart
<= 0 || nend
-nstart
<= 0 ) {
329 fprintf(stderr
, "%s| %s: Starting version %s\n", LogTime(), PROGRAM
,
332 if ((nargs
= (char **)xmalloc((nend
-nstart
+1)*sizeof(char *))) == nullptr) {
333 fprintf(stderr
, "%s| %s: Error allocating memory for ntlm helper\n", LogTime(), PROGRAM
);
336 memcpy(nargs
,argv
+nstart
+1,(nend
-nstart
)*sizeof(char *));
337 nargs
[nend
-nstart
]=nullptr;
339 fprintf(stderr
, "%s| %s: NTLM command: ", LogTime(), PROGRAM
);
340 for (int i
=0; i
<nend
-nstart
; ++i
)
341 fprintf(stderr
, "%s ", nargs
[i
]);
342 fprintf(stderr
, "\n");
344 if ((kargs
= (char **)xmalloc((kend
-kstart
+1)*sizeof(char *))) == nullptr) {
345 fprintf(stderr
, "%s| %s: Error allocating memory for kerberos helper\n", LogTime(), PROGRAM
);
348 memcpy(kargs
,argv
+kstart
+1,(kend
-kstart
)*sizeof(char *));
349 kargs
[kend
-kstart
]=nullptr;
351 fprintf(stderr
, "%s| %s: Kerberos command: ", LogTime(), PROGRAM
);
352 for (int i
=0; i
<kend
-kstart
; ++i
)
353 fprintf(stderr
, "%s ", kargs
[i
]);
354 fprintf(stderr
, "\n");
357 Fork Kerberos helper and NTLM helper and manage IO to send NTLM requests
358 to the right helper. squid must keep session state
361 if (pipe(pkin
) < 0) {
362 fprintf(stderr
, "%s| %s: Could not assign streams for pkin\n", LogTime(), PROGRAM
);
365 if (pipe(pkout
) < 0) {
366 fprintf(stderr
, "%s| %s: Could not assign streams for pkout\n", LogTime(), PROGRAM
);
370 if (( fpid
= fork()) < 0 ) {
371 fprintf(stderr
, "%s| %s: Failed first fork\n", LogTime(), PROGRAM
);
376 /* First Child for Kerberos helper */
379 dup2(pkin
[0],STDIN_FILENO
);
383 dup2(pkout
[1],STDOUT_FILENO
);
386 setbuf(stdin
, nullptr);
387 setbuf(stdout
, nullptr);
389 execv(kargs
[0], kargs
);
390 fprintf(stderr
, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM
, kargs
[0], strerror(errno
));
397 if (pipe(pnin
) < 0) {
398 fprintf(stderr
, "%s| %s: Could not assign streams for pnin\n", LogTime(), PROGRAM
);
401 if (pipe(pnout
) < 0) {
402 fprintf(stderr
, "%s| %s: Could not assign streams for pnout\n", LogTime(), PROGRAM
);
406 if (( fpid
= fork()) < 0 ) {
407 fprintf(stderr
, "%s| %s: Failed second fork\n", LogTime(), PROGRAM
);
412 /* Second Child for NTLM helper */
415 dup2(pnin
[0],STDIN_FILENO
);
419 dup2(pnout
[1],STDOUT_FILENO
);
422 setbuf(stdin
, nullptr);
423 setbuf(stdout
, nullptr);
425 execv(nargs
[0], nargs
);
426 fprintf(stderr
, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM
, nargs
[0], strerror(errno
));
433 FILE *FDKIN
=fdopen(pkin
[1],"w");
434 FILE *FDKOUT
=fdopen(pkout
[0],"r");
436 FILE *FDNIN
=fdopen(pnin
[1],"w");
437 FILE *FDNOUT
=fdopen(pnout
[0],"r");
439 if (!FDKIN
|| !FDKOUT
|| !FDNIN
|| !FDNOUT
) {
440 fprintf(stderr
, "%s| %s: Could not assign streams for FDKIN/FDKOUT/FDNIN/FDNOUT\n", LogTime(), PROGRAM
);
441 closeFds(FDKIN
, FDKOUT
, FDNIN
, FDNOUT
);
445 setbuf(FDKIN
, nullptr);
446 setbuf(FDKOUT
, nullptr);
447 setbuf(FDNIN
, nullptr);
448 setbuf(FDNOUT
, nullptr);
450 int result
= processingLoop(FDKIN
, FDKOUT
, FDNIN
, FDNOUT
);
451 closeFds(FDKIN
, FDKOUT
, FDNIN
, FDNOUT
);