]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/negotiate_auth/wrapper/negotiate_wrapper.cc
Merged from parent (trunk r11446, v3.2.0.7+).
[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 "config.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 static int err = 0;
112 int 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 if (pipe(pkin) < 0) {
193 fprintf(stderr, "%s| %s: Could not assign streams for pkin\n", LogTime(), PROGRAM);
194 return 1;
195 }
196 if (pipe(pkout) < 0) {
197 fprintf(stderr, "%s| %s: Could not assign streams for pkout\n", LogTime(), PROGRAM);
198 return 1;
199 }
200
201
202 if (( fpid = vfork()) < 0 ) {
203 fprintf(stderr, "%s| %s: Failed first fork\n", LogTime(), PROGRAM);
204 return 1;
205 }
206
207 if ( fpid == 0 ) {
208 /* First Child for Kerberos helper */
209
210 close(pkin[1]);
211 dup2(pkin[0],STDIN_FILENO);
212 close(pkin[0]);
213
214 close(pkout[0]);
215 dup2(pkout[1],STDOUT_FILENO);
216 close(pkout[1]);
217
218 setbuf(stdin, NULL);
219 setbuf(stdout, NULL);
220
221 execv(kargs[0], kargs);
222 fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, kargs[0], strerror(errno));
223 return 1;
224
225 }
226
227 close(pkin[0]);
228 close(pkout[1]);
229
230 if (pipe(pnin) < 0) {
231 fprintf(stderr, "%s| %s: Could not assign streams for pnin\n", LogTime(), PROGRAM);
232 return 1;
233 }
234 if (pipe(pnout) < 0) {
235 fprintf(stderr, "%s| %s: Could not assign streams for pnout\n", LogTime(), PROGRAM);
236 return 1;
237 }
238
239 if (( fpid = vfork()) < 0 ) {
240 fprintf(stderr, "%s| %s: Failed second fork\n", LogTime(), PROGRAM);
241 return 1;
242 }
243
244 if ( fpid == 0 ) {
245 /* Second Child for NTLM helper */
246
247 close(pnin[1]);
248 dup2(pnin[0],STDIN_FILENO);
249 close(pnin[0]);
250
251 close(pnout[0]);
252 dup2(pnout[1],STDOUT_FILENO);
253 close(pnout[1]);
254
255 setbuf(stdin, NULL);
256 setbuf(stdout, NULL);
257
258 execv(nargs[0], nargs);
259 fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, nargs[0], strerror(errno));
260 return 1;
261 }
262
263 close(pnin[0]);
264 close(pnout[1]);
265
266 FDKIN=fdopen(pkin[1],"w");
267 FDKOUT=fdopen(pkout[0],"r");
268
269 FDNIN=fdopen(pnin[1],"w");
270 FDNOUT=fdopen(pnout[0],"r");
271
272 if (!FDKIN || !FDKOUT || !FDNIN || !FDNOUT) {
273 fprintf(stderr, "%s| %s: Could not assign streams for FDKIN/FDKOUT/FDNIN/FDNOUT\n", LogTime(), PROGRAM);
274 return 1;
275 }
276
277 setbuf(FDKIN, NULL);
278 setbuf(FDKOUT, NULL);
279 setbuf(FDNIN, NULL);
280 setbuf(FDNOUT, NULL);
281
282
283 while (1) {
284 if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
285 if (ferror(stdin)) {
286 if (debug)
287 fprintf(stderr,
288 "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
289 LogTime(), PROGRAM, ferror(stdin),
290 strerror(ferror(stdin)));
291
292 fprintf(stdout, "BH input error\n");
293 return 1; /* BIIG buffer */
294 }
295 fprintf(stdout, "BH input error\n");
296 return 0;
297 }
298 c = static_cast<char*>(memchr(buf, '\n', sizeof(buf) - 1));
299 if (c) {
300 *c = '\0';
301 length = c - buf;
302 } else {
303 err = 1;
304 }
305 if (err) {
306 if (debug)
307 fprintf(stderr, "%s| %s: Oversized message\n", LogTime(),
308 PROGRAM);
309 fprintf(stdout, "BH Oversized message\n");
310 err = 0;
311 continue;
312 }
313 if (debug)
314 fprintf(stderr, "%s| %s: Got '%s' from squid (length: %d).\n",
315 LogTime(), PROGRAM, buf, length);
316
317 if (buf[0] == '\0') {
318 if (debug)
319 fprintf(stderr, "%s| %s: Invalid request\n", LogTime(),
320 PROGRAM);
321 fprintf(stdout, "BH Invalid request\n");
322 continue;
323 }
324 if (strlen(buf) < 2) {
325 if (debug)
326 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
327 PROGRAM, buf);
328 fprintf(stdout, "BH Invalid request\n");
329 continue;
330 }
331 if (!strncmp(buf, "QQ", 2)) {
332 fprintf(stdout, "BH quit command\n");
333 return 0;
334 }
335 if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
336 if (debug)
337 fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
338 PROGRAM, buf);
339 fprintf(stdout, "BH Invalid request\n");
340 continue;
341 }
342 if (strlen(buf) <= 3) {
343 if (debug)
344 fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
345 LogTime(), PROGRAM, buf);
346 fprintf(stdout, "BH Invalid negotiate request\n");
347 continue;
348 }
349 length = base64_decode_len(buf+3);
350 if (debug)
351 fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %d).\n",
352 LogTime(), PROGRAM, buf + 3, (int) length);
353
354 if ((token = (char *)xmalloc(length)) == NULL) {
355 fprintf(stderr, "%s| %s: Error allocating memory for token\n", LogTime(), PROGRAM);
356 return 1;
357 }
358
359 length = base64_decode(token, length, buf+3);
360
361 if ((static_cast<size_t>(length) >= sizeof(ntlmProtocol) + 1) &&
362 (!memcmp(token, ntlmProtocol, sizeof ntlmProtocol))) {
363 free(token);
364 if (debug)
365 fprintf(stderr, "%s| %s: received type %d NTLM token\n",
366 LogTime(), PROGRAM, (int) *((unsigned char *) token +
367 sizeof ntlmProtocol));
368 fprintf(FDNIN, "%s\n",buf);
369 if (fgets(tbuff, sizeof(tbuff) - 1, FDNOUT) == NULL) {
370 if (ferror(FDNOUT)) {
371 fprintf(stderr,
372 "fgets() failed! dying..... errno=%d (%s)\n",
373 ferror(FDNOUT), strerror(ferror(FDNOUT)));
374 return 1;
375 }
376 fprintf(stderr, "%s| %s: Error reading NTLM helper response\n",
377 LogTime(), PROGRAM);
378 return 0;
379 }
380 /*
381 Need to translate NTLM reply to Negotiate reply
382 AF user => AF blob user
383 NA reason => NA blob reason
384 Set blob to '='
385 */
386 if (strlen(tbuff) >= 3 && (!strncmp(tbuff,"AF ",3) || !strncmp(tbuff,"NA ",3))) {
387 strncpy(buff,tbuff,3);
388 buff[3]='=';
389 for (unsigned int i=2; i<=strlen(tbuff); i++)
390 buff[i+2] = tbuff[i];
391 } else {
392 strcpy(buff,tbuff);
393 }
394 } else {
395 free(token);
396 if (debug)
397 fprintf(stderr, "%s| %s: received Kerberos token\n",
398 LogTime(), PROGRAM);
399
400 fprintf(FDKIN, "%s\n",buf);
401 if (fgets(buff, sizeof(buff) - 1, FDKOUT) == NULL) {
402 if (ferror(FDKOUT)) {
403 fprintf(stderr,
404 "fgets() failed! dying..... errno=%d (%s)\n",
405 ferror(FDKOUT), strerror(ferror(FDKOUT)));
406 return 1;
407 }
408 fprintf(stderr, "%s| %s: Error reading Kerberos helper response\n",
409 LogTime(), PROGRAM);
410 return 0;
411 }
412 }
413 fprintf(stdout,"%s",buff);
414 if (debug)
415 fprintf(stderr, "%s| %s: Return '%s'\n",
416 LogTime(), PROGRAM, buff);
417 }
418
419 return 1;
420 }