source: squid-ssl/trunk/fuentes/helpers/negotiate_auth/wrapper/negotiate_wrapper.cc @ 5495

Last change on this file since 5495 was 5495, checked in by Juanma, 2 years ago

Initial release

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