2 * AUTHOR: Andrew Doran <ad@interlude.eu.org>
3 * AUTHOR: Robert Collins <rbtcollins@hotmail.com>
4 * AUTHOR: Guido Serassio: <guido.serassio@acmeconsulting.it>
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 * Example ntlm authentication program for Squid, based on the
35 * original proxy_auth code from client_side.c, written by
36 * Jon Thackray <jrmt@uk.gdscorp.com>. Initial ntlm code by
37 * Andrew Doran <ad@interlude.eu.org>.
39 * This code gets the username and returns it. No validation is done.
40 * and by the way: it is a complete patch-up. Use the "real thing" NTLMSSP
43 * Revised by Guido Serassio: <guido.serassio@acmeconsulting.it>
45 * - Added negotiation of UNICODE char support
46 * - More detailed debugging info
50 /* undefine this to have strict protocol adherence. You don't really need
52 #define IGNORANCE_IS_BLISS
56 #include "helpers/defines.h"
57 #include "ntlmauth/ntlmauth.h"
58 #include "ntlmauth/support_bits.cci"
78 /* A couple of harmless helper macros */
79 #define SEND(X) {debug("sending '%s' to squid\n",X); printf(X "\n");}
81 #define SEND2(X,Y...) {debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);}
82 #define SEND4(X,Y...) {debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);}
84 /* no gcc, no debugging. varargs macros are a gcc extension */
85 #define SEND2(X,Y) {debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);}
86 #define SEND4(X,Y,Z,W) {debug("sending '" X "' to squid\n",Y,Z,W); printf(X "\n",Y,Z,W);}
89 const char *authenticate_ntlm_domain
= "WORKGROUP";
90 int strip_domain_enabled
= 0;
91 int NTLM_packet_debug_enabled
= 0;
95 * -d enable debugging.
96 * -v enable verbose NTLM packet debugging.
97 * -l if specified, changes behavior on failures to last-ditch.
99 char *my_program_name
= NULL
;
105 "Usage: %s [-d] [-v] [-h]\n"
106 " -d enable debugging.\n"
107 " -S strip domain from username.\n"
108 " -v enable verbose NTLM packet debugging.\n"
109 " -h this message\n\n",
114 process_options(int argc
, char *argv
[])
116 int opt
, had_error
= 0;
119 while (-1 != (opt
= getopt(argc
, argv
, "hdvS"))) {
126 NTLM_packet_debug_enabled
= 1;
129 strip_domain_enabled
= 1;
136 /* fall thru to default */
138 fprintf(stderr
, "unknown option: -%c. Exiting\n", opt
);
148 main(int argc
, char *argv
[])
150 char buf
[HELPER_INPUT_BUFFER
];
152 char decodedBuf
[HELPER_INPUT_BUFFER
];
154 char user
[NTLM_MAX_FIELD_LENGTH
], domain
[NTLM_MAX_FIELD_LENGTH
];
156 ntlmhdr
*packet
= NULL
;
157 char helper_command
[3];
161 setbuf(stdout
, NULL
);
162 setbuf(stderr
, NULL
);
164 my_program_name
= argv
[0];
166 process_options(argc
, argv
);
168 debug("%s build " __DATE__
", " __TIME__
" starting up...\n", my_program_name
);
170 while (fgets(buf
, HELPER_INPUT_BUFFER
, stdin
) != NULL
) {
171 user
[0] = '\0'; /*no user code */
172 domain
[0] = '\0'; /*no domain code */
174 if ((p
= strchr(buf
, '\n')) != NULL
)
175 *p
= '\0'; /* strip \n */
176 buflen
= strlen(buf
); /* keep this so we only scan the buffer for \0 once per loop */
178 decodedLen
= base64_decode(decodedBuf
, sizeof(decodedBuf
), buf
+3);
179 packet
= (ntlmhdr
*)decodedBuf
;
184 if (buflen
> 3 && NTLM_packet_debug_enabled
) {
185 strncpy(helper_command
, buf
, 2);
186 helper_command
[2] = '\0';
187 debug("Got '%s' from Squid with data:\n", helper_command
);
188 hex_dump((unsigned char *)decodedBuf
, decodedLen
);
190 debug("Got '%s' from Squid\n", buf
);
192 if (strncmp(buf
, "YR", 2) == 0) {
193 char nonce
[NTLM_NONCE_LEN
];
195 ntlm_make_nonce(nonce
);
197 ntlm_negotiate
*nego
= (ntlm_negotiate
*)packet
;
198 ntlm_make_challenge(&chal
, authenticate_ntlm_domain
, NULL
, nonce
, NTLM_NONCE_LEN
, nego
->flags
);
200 ntlm_make_challenge(&chal
, authenticate_ntlm_domain
, NULL
, nonce
, NTLM_NONCE_LEN
, NTLM_NEGOTIATE_ASCII
);
202 // TODO: find out what this context means, and why only the fake auth helper contains it.
203 chal
.context_high
= htole32(0x003a<<16);
205 len
= sizeof(chal
) - sizeof(chal
.payload
) + le16toh(chal
.target
.maxlen
);
206 data
= (char *) base64_encode_bin((char *) &chal
, len
);
207 if (NTLM_packet_debug_enabled
) {
208 printf("TT %s\n", data
);
209 debug("sending 'TT' to squid with data:\n");
210 hex_dump((unsigned char *)&chal
, len
);
212 SEND2("TT %s", data
);
213 } else if (strncmp(buf
, "KK ", 3) == 0) {
215 SEND("BH received KK with no data! user=");
216 } else if (ntlm_validate_packet(packet
, NTLM_AUTHENTICATE
) == NTLM_ERR_NONE
) {
217 if (ntlm_unpack_auth((ntlm_authenticate
*)packet
, user
, domain
, decodedLen
) == NTLM_ERR_NONE
) {
219 if (strip_domain_enabled
) {
220 SEND2("AF %s", user
);
222 SEND4("AF %s%s%s", domain
, (*domain
?"\\":""), user
);
226 SEND4("NA invalid credentials, user=%s%s%s", domain
, (*domain
?"\\":""), user
);
229 SEND("BH wrong packet type! user=");