negotiate_wrapper.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
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 
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  */
32 
33 #include "squid.h"
34 #include "base64.h"
35 
36 #include <cerrno>
37 #include <cstring>
38 #include <cstdlib>
39 #include <ctime>
40 #if HAVE_NETDB_H
41 #include <netdb.h>
42 #endif
43 #if HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
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 
66 static const unsigned char ntlmProtocol[] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0};
67 
68 static const char *
70 {
71  struct timeval now;
72  static time_t last_t = 0;
73  static char buf[128];
74 
75  gettimeofday(&now, NULL);
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);
80  last_t = now.tv_sec;
81  }
82  return buf;
83 }
84 
85 void usage(void)
86 {
87  fprintf(stderr, "Usage: \n");
88  fprintf(stderr, "negotiate_wrapper [-h] [-d] --ntlm ntlm helper + arguments --kerberos kerberos helper + arguments\n");
89  fprintf(stderr, "-h help\n");
90  fprintf(stderr, "-d full debug\n");
91  fprintf(stderr, "--ntlm full ntlm helper path with arguments\n");
92  fprintf(stderr, "--kerberos full kerberos helper path with arguments\n");
93 }
94 
95 static void
96 closeFds(FILE *a, FILE *b, FILE *c, FILE *d)
97 {
98  if (a)
99  fclose(a);
100  if (b)
101  fclose(b);
102  if (c)
103  fclose(c);
104  if (d)
105  fclose(d);
106 }
107 
108 static int
109 processingLoop(FILE *FDKIN, FILE *FDKOUT, FILE *FDNIN, FILE *FDNOUT)
110 {
111  char buf[MAX_AUTHTOKEN_LEN];
112  char tbuff[MAX_AUTHTOKEN_LEN];
113  char buff[MAX_AUTHTOKEN_LEN+2];
114  char *c;
115  size_t length;
116  uint8_t *token = NULL;
117 
118  while (1) {
119  if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
120  xfree(token);
121  if (ferror(stdin)) {
122  if (debug_enabled)
123  fprintf(stderr,
124  "%s| %s: fgets() failed! dying..... errno=%d (%s)\n",
125  LogTime(), PROGRAM, ferror(stdin),
126  strerror(ferror(stdin)));
127 
128  fprintf(stdout, "BH input error\n");
129  return 1; /* BIIG buffer */
130  }
131  fprintf(stdout, "BH input error\n");
132  return 0;
133  }
134  c = static_cast<char*>(memchr(buf, '\n', sizeof(buf) - 1));
135  if (c) {
136  *c = '\0';
137  length = c - buf;
138  if (debug_enabled)
139  fprintf(stderr, "%s| %s: Got '%s' from squid (length: %" PRIuSIZE ").\n",
140  LogTime(), PROGRAM, buf, length);
141  } else {
142  if (debug_enabled)
143  fprintf(stderr, "%s| %s: Oversized message\n", LogTime(),
144  PROGRAM);
145  fprintf(stdout, "BH Oversized message\n");
146  continue;
147  }
148 
149  if (buf[0] == '\0') {
150  if (debug_enabled)
151  fprintf(stderr, "%s| %s: Invalid request\n", LogTime(),
152  PROGRAM);
153  fprintf(stdout, "BH Invalid request\n");
154  continue;
155  }
156  if (strlen(buf) < 2) {
157  if (debug_enabled)
158  fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
159  PROGRAM, buf);
160  fprintf(stdout, "BH Invalid request\n");
161  continue;
162  }
163  if (!strncmp(buf, "QQ", 2)) {
164  fprintf(stdout, "BH quit command\n");
165  xfree(token);
166  return 0;
167  }
168  if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
169  if (debug_enabled)
170  fprintf(stderr, "%s| %s: Invalid request [%s]\n", LogTime(),
171  PROGRAM, buf);
172  fprintf(stdout, "BH Invalid request\n");
173  continue;
174  }
175  if (strlen(buf) <= 3) {
176  if (debug_enabled)
177  fprintf(stderr, "%s| %s: Invalid negotiate request [%s]\n",
178  LogTime(), PROGRAM, buf);
179  fprintf(stdout, "BH Invalid negotiate request\n");
180  continue;
181  }
182  length = BASE64_DECODE_LENGTH(strlen(buf+3));
183  if (debug_enabled)
184  fprintf(stderr, "%s| %s: Decode '%s' (decoded length: %" PRIuSIZE ").\n",
185  LogTime(), PROGRAM, buf + 3, length);
186 
187  safe_free(token);
188  if (!(token = static_cast<uint8_t *>(xmalloc(length+1)))) {
189  fprintf(stderr, "%s| %s: Error allocating memory for token\n", LogTime(), PROGRAM);
190  return 1;
191  }
192 
193  struct base64_decode_ctx ctx;
194  base64_decode_init(&ctx);
195  size_t dstLen = 0;
196  if (!base64_decode_update(&ctx, &dstLen, token, strlen(buf+3), buf+3) ||
197  !base64_decode_final(&ctx)) {
198  if (debug_enabled)
199  fprintf(stderr, "%s| %s: Invalid base64 token [%s]\n", LogTime(), PROGRAM, buf+3);
200  fprintf(stdout, "BH Invalid negotiate request token\n");
201  continue;
202  }
203  assert(dstLen <= length);
204  length = dstLen;
205  token[dstLen] = '\0';
206 
207  if ((static_cast<size_t>(length) >= sizeof(ntlmProtocol) + 1) &&
208  (!memcmp(token, ntlmProtocol, sizeof ntlmProtocol))) {
209  if (debug_enabled)
210  fprintf(stderr, "%s| %s: received type %d NTLM token\n",
211  LogTime(), PROGRAM, (int) *((unsigned char *) token +
212  sizeof ntlmProtocol));
213  fprintf(FDNIN, "%s\n",buf);
214  if (fgets(tbuff, sizeof(tbuff) - 1, FDNOUT) == NULL) {
215  xfree(token);
216  if (ferror(FDNOUT)) {
217  fprintf(stderr,
218  "fgets() failed! dying..... errno=%d (%s)\n",
219  ferror(FDNOUT), strerror(ferror(FDNOUT)));
220  return 1;
221  }
222  fprintf(stderr, "%s| %s: Error reading NTLM helper response\n",
223  LogTime(), PROGRAM);
224  return 0;
225  }
226  /*
227  * Need to translate NTLM reply to Negotiate reply:
228  * AF user => AF blob user
229  * NA reason => NA blob reason
230  * Set blob to '='
231  */
232  if (strlen(tbuff) >= 3 && (!strncmp(tbuff,"AF ",3) || !strncmp(tbuff,"NA ",3))) {
233  strncpy(buff,tbuff,3);
234  buff[3]='=';
235  for (unsigned int i=2; i<=strlen(tbuff); ++i)
236  buff[i+2] = tbuff[i];
237  } else {
238  strcpy(buff,tbuff);
239  }
240  } else {
241  if (debug_enabled)
242  fprintf(stderr, "%s| %s: received Kerberos token\n",
243  LogTime(), PROGRAM);
244 
245  fprintf(FDKIN, "%s\n",buf);
246  if (fgets(buff, sizeof(buff) - 1, FDKOUT) == NULL) {
247  xfree(token);
248  if (ferror(FDKOUT)) {
249  fprintf(stderr,
250  "fgets() failed! dying..... errno=%d (%s)\n",
251  ferror(FDKOUT), strerror(ferror(FDKOUT)));
252  return 1;
253  }
254  fprintf(stderr, "%s| %s: Error reading Kerberos helper response\n",
255  LogTime(), PROGRAM);
256  return 0;
257  }
258  }
259  fprintf(stdout,"%s",buff);
260  if (debug_enabled)
261  fprintf(stderr, "%s| %s: Return '%s'\n",
262  LogTime(), PROGRAM, buff);
263  }
264 
265  xfree(token);
266  return 1;
267 }
268 
269 int
270 main(int argc, char *const argv[])
271 {
272  int nstart = 0, kstart = 0;
273  int nend = 0, kend = 0;
274  char **nargs, **kargs;
275  int fpid;
276  int pkin[2];
277  int pkout[2];
278  int pnin[2];
279  int pnout[2];
280 
281  setbuf(stdout, NULL);
282  setbuf(stdin, NULL);
283 
284  if (argc ==1 || !strncasecmp(argv[1],"-h",2)) {
285  usage();
286  exit(EXIT_SUCCESS);
287  }
288 
289  int j = 1;
290  if (!strncasecmp(argv[1],"-d",2)) {
291  debug_enabled = 1;
292  j = 2;
293  }
294 
295  for (int i=j; i<argc; ++i) {
296  if (!strncasecmp(argv[i],"--ntlm",6))
297  nstart = i;
298  if (!strncasecmp(argv[i],"--kerberos",10))
299  kstart = i;
300  }
301  if (nstart > kstart) {
302  kend = nstart-1;
303  nend = argc-1;
304  } else {
305  kend = argc-1;
306  nend = kstart-1;
307  }
308  if (nstart == 0 || kstart == 0 || kend-kstart <= 0 || nend-nstart <= 0 ) {
309  usage();
310  exit(EXIT_SUCCESS);
311  }
312 
313  if (debug_enabled)
314  fprintf(stderr, "%s| %s: Starting version %s\n", LogTime(), PROGRAM,
315  VERSION);
316 
317  if ((nargs = (char **)xmalloc((nend-nstart+1)*sizeof(char *))) == NULL) {
318  fprintf(stderr, "%s| %s: Error allocating memory for ntlm helper\n", LogTime(), PROGRAM);
319  exit(EXIT_FAILURE);
320  }
321  memcpy(nargs,argv+nstart+1,(nend-nstart)*sizeof(char *));
322  nargs[nend-nstart]=NULL;
323  if (debug_enabled) {
324  fprintf(stderr, "%s| %s: NTLM command: ", LogTime(), PROGRAM);
325  for (int i=0; i<nend-nstart; ++i)
326  fprintf(stderr, "%s ", nargs[i]);
327  fprintf(stderr, "\n");
328  }
329  if ((kargs = (char **)xmalloc((kend-kstart+1)*sizeof(char *))) == NULL) {
330  fprintf(stderr, "%s| %s: Error allocating memory for kerberos helper\n", LogTime(), PROGRAM);
331  exit(EXIT_FAILURE);
332  }
333  memcpy(kargs,argv+kstart+1,(kend-kstart)*sizeof(char *));
334  kargs[kend-kstart]=NULL;
335  if (debug_enabled) {
336  fprintf(stderr, "%s| %s: Kerberos command: ", LogTime(), PROGRAM);
337  for (int i=0; i<kend-kstart; ++i)
338  fprintf(stderr, "%s ", kargs[i]);
339  fprintf(stderr, "\n");
340  }
341  /*
342  Fork Kerberos helper and NTLM helper and manage IO to send NTLM requests
343  to the right helper. squid must keep session state
344  */
345 
346  if (pipe(pkin) < 0) {
347  fprintf(stderr, "%s| %s: Could not assign streams for pkin\n", LogTime(), PROGRAM);
348  exit(EXIT_FAILURE);
349  }
350  if (pipe(pkout) < 0) {
351  fprintf(stderr, "%s| %s: Could not assign streams for pkout\n", LogTime(), PROGRAM);
352  exit(EXIT_FAILURE);
353  }
354 
355  if (( fpid = vfork()) < 0 ) {
356  fprintf(stderr, "%s| %s: Failed first fork\n", LogTime(), PROGRAM);
357  exit(EXIT_FAILURE);
358  }
359 
360  if ( fpid == 0 ) {
361  /* First Child for Kerberos helper */
362 
363  close(pkin[1]);
364  dup2(pkin[0],STDIN_FILENO);
365  close(pkin[0]);
366 
367  close(pkout[0]);
368  dup2(pkout[1],STDOUT_FILENO);
369  close(pkout[1]);
370 
371  setbuf(stdin, NULL);
372  setbuf(stdout, NULL);
373 
374  execv(kargs[0], kargs);
375  fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, kargs[0], strerror(errno));
376  exit(EXIT_FAILURE);
377  }
378 
379  close(pkin[0]);
380  close(pkout[1]);
381 
382  if (pipe(pnin) < 0) {
383  fprintf(stderr, "%s| %s: Could not assign streams for pnin\n", LogTime(), PROGRAM);
384  exit(EXIT_FAILURE);
385  }
386  if (pipe(pnout) < 0) {
387  fprintf(stderr, "%s| %s: Could not assign streams for pnout\n", LogTime(), PROGRAM);
388  exit(EXIT_FAILURE);
389  }
390 
391  if (( fpid = vfork()) < 0 ) {
392  fprintf(stderr, "%s| %s: Failed second fork\n", LogTime(), PROGRAM);
393  exit(EXIT_FAILURE);
394  }
395 
396  if ( fpid == 0 ) {
397  /* Second Child for NTLM helper */
398 
399  close(pnin[1]);
400  dup2(pnin[0],STDIN_FILENO);
401  close(pnin[0]);
402 
403  close(pnout[0]);
404  dup2(pnout[1],STDOUT_FILENO);
405  close(pnout[1]);
406 
407  setbuf(stdin, NULL);
408  setbuf(stdout, NULL);
409 
410  execv(nargs[0], nargs);
411  fprintf(stderr, "%s| %s: Failed execv for %s: %s\n", LogTime(), PROGRAM, nargs[0], strerror(errno));
412  exit(EXIT_FAILURE);
413  }
414 
415  close(pnin[0]);
416  close(pnout[1]);
417 
418  FILE *FDKIN=fdopen(pkin[1],"w");
419  FILE *FDKOUT=fdopen(pkout[0],"r");
420 
421  FILE *FDNIN=fdopen(pnin[1],"w");
422  FILE *FDNOUT=fdopen(pnout[0],"r");
423 
424  if (!FDKIN || !FDKOUT || !FDNIN || !FDNOUT) {
425  fprintf(stderr, "%s| %s: Could not assign streams for FDKIN/FDKOUT/FDNIN/FDNOUT\n", LogTime(), PROGRAM);
426  closeFds(FDKIN, FDKOUT, FDNIN, FDNOUT);
427  exit(EXIT_FAILURE);
428  }
429 
430  setbuf(FDKIN, NULL);
431  setbuf(FDKOUT, NULL);
432  setbuf(FDNIN, NULL);
433  setbuf(FDNOUT, NULL);
434 
435  int result = processingLoop(FDKIN, FDKOUT, FDNIN, FDNOUT);
436  closeFds(FDKIN, FDKOUT, FDNIN, FDNOUT);
437  return result;
438 }
439 
#define MAX_AUTHTOKEN_LEN
#define assert(EX)
Definition: assert.h:17
char * strerror(int ern)
Definition: strerror.c:22
int debug_enabled
Definition: debug.cc:13
#define PROGRAM
int i
Definition: membanger.c:49
#define safe_free(x)
Definition: xalloc.h:73
void base64_decode_init(struct base64_decode_ctx *ctx)
Definition: base64.c:54
#define BASE64_DECODE_LENGTH(length)
Definition: base64.h:120
static void closeFds(FILE *a, FILE *b, FILE *c, FILE *d)
void usage(void)
int main(int argc, char *const argv[])
void const char * buf
Definition: stub_helper.cc:16
#define xmalloc
#define VERSION
static int processingLoop(FILE *FDKIN, FILE *FDKOUT, FILE *FDNIN, FILE *FDNOUT)
int a
Definition: membanger.c:50
static const unsigned char ntlmProtocol[]
static const char * LogTime()
int base64_decode_update(struct base64_decode_ctx *ctx, size_t *dst_length, uint8_t *dst, size_t src_length, const char *src)
Definition: base64.c:129
#define xfree
int base64_decode_final(struct base64_decode_ctx *ctx)
Definition: base64.c:159
#define NULL
Definition: types.h:166

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors