]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/negotiate_auth/wrapper/negotiate_wrapper.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / helpers / negotiate_auth / wrapper / negotiate_wrapper.cc
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 "squid.h"
29 #include "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
75 static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
76
77 static const char *
78 LogTime()
79 {
80 struct timeval now;
81 static time_t last_t = 0;
82 static char buf[128];
83
84 gettimeofday(&now, NULL);
85 if (now.tv_sec != last_t) {
86 time_t *tmp = (time_t *) & now.tv_sec;
87 struct tm *tm = localtime(tmp);
88 strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
89 last_t = now.tv_sec;
90 }
91 return buf;
92 }
93
94 void 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
104 int
105 main(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;
111 int debug = 0;
112 int length;
113 int nstart = 0, kstart = 0;
114 int nend = 0, kend = 0;
115 char *token;
116 char **nargs, **kargs;
117 int i,j;
118 int fpid;
119 FILE *FDKIN,*FDKOUT;
120 FILE *FDNIN,*FDNOUT;
121 int pkin[2];
122 int pkout[2];
123 int pnin[2];
124 int pnout[2];
125
126 setbuf(stdout, NULL);
127 setbuf(stdin, NULL);
128
129 if (argc ==1 || !strncasecmp(argv[1],"-h",2)) {
130 usage();
131 return 0;
132 }
133
134 j = 1;
135 if (!strncasecmp(argv[1],"-d",2)) {
136 debug = 1;
137 j = 2;
138 }
139
140 for (i=j; i<argc; i++) {
141 if (!strncasecmp(argv[i],"--ntlm",6))
142 nstart = i;
143 if (!strncasecmp(argv[i],"--kerberos",10))
144 kstart = i;
145 }
146 if (nstart > kstart) {
147 kend = nstart-1;
148 nend = argc-1;
149 } else {
150 kend = argc-1;
151 nend = kstart-1;
152 }
153 if (nstart == 0 || kstart == 0 || kend-kstart <= 0 || nend-nstart <= 0 ) {
154 usage();
155 return 0;
156 }
157
158 if (debug)
159 fprintf(stderr, "%s| %s: Starting version %s\n", LogTime(), PROGRAM,
160 VERSION);
161
162 if ((nargs = (char **)xmalloc((nend-nstart+1)*sizeof(char *))) == NULL) {
163 fprintf(stderr, "%s| %s: Error allocating memory for ntlm helper\n", LogTime(), PROGRAM);
164 return 1;
165 }
166 memcpy(nargs,argv+nstart+1,(nend-nstart)*sizeof(char *));
167 nargs[nend-nstart]=NULL;
168 if (debug) {
169 fprintf(stderr, "%s| %s: NTLM command: ", LogTime(), PROGRAM);
170 for (i=0; i<nend-nstart; i++)
171 fprintf(stderr, "%s ", nargs[i]);
172 fprintf(stderr, "\n");
173 }
174 if ((kargs = (char **)xmalloc((kend-kstart+1)*sizeof(char *))) == NULL) {
175 fprintf(stderr, "%s| %s: Error allocating memory for kerberos helper\n", LogTime(), PROGRAM);
176 return 1;
177 }
178 memcpy(kargs,argv+kstart+1,(kend-kstart)*sizeof(char *));
179 kargs[kend-kstart]=NULL;
180 if (debug) {
181 fprintf(stderr, "%s| %s: Kerberos command: ", LogTime(), PROGRAM);
182 for (i=0; i<kend-kstart; i++)
183 fprintf(stderr, "%s ", kargs[i]);
184 fprintf(stderr, "\n");
185 }
186 /*
187 Fork Kerberos helper and NTLM helper and manage IO to send NTLM requests
188 to the right helper. squid must keep session state
189 */
190
191 if (pipe(pkin) < 0) {
192 fprintf(stderr, "%s| %s: Could not assign streams for pkin\n", LogTime(), PROGRAM);
193 return 1;
194 }
195 if (pipe(pkout) < 0) {
196 fprintf(stderr, "%s| %s: Could not assign streams for pkout\n", LogTime(), PROGRAM);
197 return 1;
198 }
199
200
201 if (( fpid = vfork()) < 0 ) {
202 fprintf(stderr, "%s| %s: Failed first fork\n", LogTime(), PROGRAM);
203 return 1;
204 }
205
206 if ( fpid == 0 ) {
207 /* First Child for Kerberos helper */
208
209 close(pkin[1]);
210 dup2(pkin[0],STDIN_FILENO);
211 close(pkin[0]);
212
213 close(pkout[0]);
214 dup2(pkout[1],STDOUT_FILENO);
215 close(pkout[1]);
216
217 setbuf(stdin, NULL);
218 setbuf(stdout, NULL);
219
220 execv(kargs[0], kargs);
221 fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, kargs[0], strerror(errno));
222 return 1;
223
224 }
225
226 close(pkin[0]);
227 close(pkout[1]);
228
229 if (pipe(pnin) < 0) {
230 fprintf(stderr, "%s| %s: Could not assign streams for pnin\n", LogTime(), PROGRAM);
231 return 1;
232 }
233 if (pipe(pnout) < 0) {
234 fprintf(stderr, "%s| %s: Could not assign streams for pnout\n", LogTime(), PROGRAM);
235 return 1;
236 }
237
238 if (( fpid = vfork()) < 0 ) {
239 fprintf(stderr, "%s| %s: Failed second fork\n", LogTime(), PROGRAM);
240 return 1;
241 }
242
243 if ( fpid == 0 ) {
244 /* Second Child for NTLM helper */
245
246 close(pnin[1]);
247 dup2(pnin[0],STDIN_FILENO);
248 close(pnin[0]);
249
250 close(pnout[0]);
251 dup2(pnout[1],STDOUT_FILENO);
252 close(pnout[1]);
253
254 setbuf(stdin, NULL);
255 setbuf(stdout, NULL);
256
257 execv(nargs[0], nargs);
258 fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, nargs[0], strerror(errno));
259 return 1;
260 }
261
262 close(pnin[0]);
263 close(pnout[1]);
264
265 FDKIN=fdopen(pkin[1],"w");
266 FDKOUT=fdopen(pkout[0],"r");
267
268 FDNIN=fdopen(pnin[1],"w");
269 FDNOUT=fdopen(pnout[0],"r");
270
271 if (!FDKIN || !FDKOUT || !FDNIN || !FDNOUT) {
272 fprintf(stderr, "%s| %s: Could not assign streams for FDKIN/FDKOUT/FDNIN/FDNOUT\n", LogTime(), PROGRAM);
273 return 1;
274 }
275
276 setbuf(FDKIN, NULL);
277 setbuf(FDKOUT, NULL);
278 setbuf(FDNIN, NULL);
279 setbuf(FDNOUT, NULL);
280
281
282 while (1) {
283 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
284 if (ferror(stdin)) {
285 if (debug)
286 fprintf(stderr,
287 "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
288 LogTime(), PROGRAM, ferror(stdin),
289 strerror(ferror(stdin)));
290
291 fprintf(stdout, "BH input error\n");
292 return 1; /* BIIG buffer */
293 }
294 fprintf(stdout, "BH input error\n");
295 return 0;
296 }
297 c = static_cast<char*>(memchr(buf, '\n', sizeof(buf) - 1));
298 if (c) {
299 *c = '\0';
300 length = c - buf;
301 if (debug)
302 fprintf(stderr, "%s| %s: Got '%s' from squid (length: %d).\n",
303 LogTime(), PROGRAM, buf, length);
304 } else {
305 if (debug)
306 fprintf(stderr, "%s| %s: Oversized message\n", LogTime(),
307 PROGRAM);
308 fprintf(stdout, "BH Oversized message\n");
309 continue;
310 }
311
312 if (buf[0] == '\0') {
313 if (debug)
314 fprintf(stderr, "%s| %s: Invalid request\n", LogTime(),
315 PROGRAM);
316 fprintf(stdout, "BH Invalid request\n");
317 continue;
318 }
319 if (strlen(buf) < 2) {
320 if (debug)
321 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
322 PROGRAM, buf);
323 fprintf(stdout, "BH Invalid request\n");
324 continue;
325 }
326 if (!strncmp(buf, "QQ", 2)) {
327 fprintf(stdout, "BH quit command\n");
328 return 0;
329 }
330 if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
331 if (debug)
332 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
333 PROGRAM, buf);
334 fprintf(stdout, "BH Invalid request\n");
335 continue;
336 }
337 if (strlen(buf) <= 3) {
338 if (debug)
339 fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
340 LogTime(), PROGRAM, buf);
341 fprintf(stdout, "BH Invalid negotiate request\n");
342 continue;
343 }
344 length = base64_decode_len(buf+3);
345 if (debug)
346 fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %d).\n",
347 LogTime(), PROGRAM, buf + 3, (int) length);
348
349 if ((token = (char *)xmalloc(length)) == NULL) {
350 fprintf(stderr, "%s| %s: Error allocating memory for token\n", LogTime(), PROGRAM);
351 return 1;
352 }
353
354 length = base64_decode(token, length, buf+3);
355
356 if ((static_cast<size_t>(length) >= sizeof(ntlmProtocol) + 1) &&
357 (!memcmp(token, ntlmProtocol, sizeof ntlmProtocol))) {
358 free(token);
359 if (debug)
360 fprintf(stderr, "%s| %s: received type %d NTLM token\n",
361 LogTime(), PROGRAM, (int) *((unsigned char *) token +
362 sizeof ntlmProtocol));
363 fprintf(FDNIN, "%s\n",buf);
364 if (fgets(tbuff, sizeof(tbuff) - 1, FDNOUT) == NULL) {
365 if (ferror(FDNOUT)) {
366 fprintf(stderr,
367 "fgets() failed! dying..... errno=%d (%s)\n",
368 ferror(FDNOUT), strerror(ferror(FDNOUT)));
369 return 1;
370 }
371 fprintf(stderr, "%s| %s: Error reading NTLM helper response\n",
372 LogTime(), PROGRAM);
373 return 0;
374 }
375 /*
376 Need to translate NTLM reply to Negotiate reply
377 AF user => AF blob user
378 NA reason => NA blob reason
379 Set blob to '='
380 */
381 if (strlen(tbuff) >= 3 && (!strncmp(tbuff,"AF ",3) || !strncmp(tbuff,"NA ",3))) {
382 strncpy(buff,tbuff,3);
383 buff[3]='=';
384 for (unsigned int i=2; i<=strlen(tbuff); i++)
385 buff[i+2] = tbuff[i];
386 } else {
387 strcpy(buff,tbuff);
388 }
389 } else {
390 free(token);
391 if (debug)
392 fprintf(stderr, "%s| %s: received Kerberos token\n",
393 LogTime(), PROGRAM);
394
395 fprintf(FDKIN, "%s\n",buf);
396 if (fgets(buff, sizeof(buff) - 1, FDKOUT) == NULL) {
397 if (ferror(FDKOUT)) {
398 fprintf(stderr,
399 "fgets() failed! dying..... errno=%d (%s)\n",
400 ferror(FDKOUT), strerror(ferror(FDKOUT)));
401 return 1;
402 }
403 fprintf(stderr, "%s| %s: Error reading Kerberos helper response\n",
404 LogTime(), PROGRAM);
405 return 0;
406 }
407 }
408 fprintf(stdout,"%s",buff);
409 if (debug)
410 fprintf(stderr, "%s| %s: Return '%s'\n",
411 LogTime(), PROGRAM, buff);
412 }
413
414 return 1;
415 }