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