]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/ntlm_auth/fake/ntlm_fake_auth.cc
Merged from trunk
[thirdparty/squid.git] / helpers / ntlm_auth / fake / ntlm_fake_auth.cc
1 /*
2 * $Id$
3 *
4 * AUTHOR: Andrew Doran <ad@interlude.eu.org>
5 * AUTHOR: Robert Collins <rbtcollins@hotmail.com>
6 * AUTHOR: Guido Serassio: <guido.serassio@acmeconsulting.it>
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35 /*
36 * Example ntlm authentication program for Squid, based on the
37 * original proxy_auth code from client_side.c, written by
38 * Jon Thackray <jrmt@uk.gdscorp.com>. Initial ntlm code by
39 * Andrew Doran <ad@interlude.eu.org>.
40 *
41 * This code gets the username and returns it. No validation is done.
42 * and by the way: it is a complete patch-up. Use the "real thing" NTLMSSP
43 * if you can.
44 *
45 * Revised by Guido Serassio: <guido.serassio@acmeconsulting.it>
46 *
47 * - Added negotiation of UNICODE char support
48 * - More detailed debugging info
49 *
50 */
51
52 /* undefine this to have strict protocol adherence. You don't really need
53 * that though */
54 #define IGNORANCE_IS_BLISS
55
56 #include "config.h"
57 #include "ntlmauth.h"
58 #include "util.h"
59
60 #if HAVE_CTYPE_H
61 #include <ctype.h>
62 #endif
63 #if HAVE_STRING_H
64 #include <string.h>
65 #endif
66 #if HAVE_CRYPT_H
67 #include <crypt.h>
68 #endif
69 #if HAVE_PWD_H
70 #include <pwd.h>
71 #endif
72 #if HAVE_GETOPT_H
73 #include <getopt.h>
74 #endif
75
76
77 #define safe_free(x) if (x) { free(x); x = NULL; }
78
79 /* A couple of harmless helper macros */
80 #define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
81 #ifdef __GNUC__
82 #define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
83 #define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
84 #else
85 /* no gcc, no debugging. varargs macros are a gcc extension */
86 #define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
87 #define SEND3(X,Y,Z) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z);
88 #endif
89
90 #define ERR "ERR\n"
91 #define OK "OK\n"
92
93 #define BUFFER_SIZE 10240
94
95 const char *authenticate_ntlm_domain = "WORKGROUP";
96 int strip_domain_enabled = 0;
97 int NTLM_packet_debug_enabled = 0;
98
99 static void
100 hex_dump(unsigned char *data, int size)
101 {
102 /* dumps size bytes of *data to stdout. Looks like:
103 * [0000] 75 6E 6B 6E 6F 77 6E 20
104 * 30 FF 00 00 00 00 39 00 unknown 0.....9.
105 * (in a single line of course)
106 */
107
108 if (!data)
109 return;
110
111 if (debug_enabled) {
112 unsigned char *p = data;
113 unsigned char c;
114 int n;
115 char bytestr[4] = {0};
116 char addrstr[10] = {0};
117 char hexstr[16 * 3 + 5] = {0};
118 char charstr[16 * 1 + 5] = {0};
119 for (n = 1; n <= size; n++) {
120 if (n % 16 == 1) {
121 /* store address for this line */
122 snprintf(addrstr, sizeof(addrstr), "%.4x",
123 (int) (p - data));
124 }
125 c = *p;
126 if (xisalnum(c) == 0) {
127 c = '.';
128 }
129 /* store hex str (for left side) */
130 snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
131 strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);
132
133 /* store char str (for right side) */
134 snprintf(bytestr, sizeof(bytestr), "%c", c);
135 strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1);
136
137 if (n % 16 == 0) {
138 /* line completed */
139 fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
140 hexstr[0] = 0;
141 charstr[0] = 0;
142 } else if (n % 8 == 0) {
143 /* half line: add whitespaces */
144 strncat(hexstr, " ", sizeof(hexstr) - strlen(hexstr) - 1);
145 strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1);
146 }
147 p++; /* next byte */
148 }
149
150 if (strlen(hexstr) > 0) {
151 /* print rest of buffer if not empty */
152 fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
153 }
154 }
155 }
156
157
158 /* makes a null-terminated string lower-case. Changes CONTENTS! */
159 static void
160 lc(char *string)
161 {
162 char *p = string, c;
163 while ((c = *p)) {
164 *p = xtolower(c);
165 p++;
166 }
167 }
168
169 /*
170 * options:
171 * -d enable debugging.
172 * -v enable verbose NTLM packet debugging.
173 * -l if specified, changes behavior on failures to last-ditch.
174 */
175 char *my_program_name = NULL;
176
177 static void
178 usage(void)
179 {
180 fprintf(stderr,
181 "Usage: %s [-d] [-v] [-h]\n"
182 " -d enable debugging.\n"
183 " -S strip domain from username.\n"
184 " -v enable verbose NTLM packet debugging.\n"
185 " -h this message\n\n",
186 my_program_name);
187 }
188
189 static void
190 process_options(int argc, char *argv[])
191 {
192 int opt, had_error = 0;
193
194 opterr = 0;
195 while (-1 != (opt = getopt(argc, argv, "hdvS"))) {
196 switch (opt) {
197 case 'd':
198 debug_enabled = 1;
199 break;
200 case 'v':
201 debug_enabled = 1;
202 NTLM_packet_debug_enabled = 1;
203 break;
204 case 'S':
205 strip_domain_enabled = 1;
206 break;
207 case 'h':
208 usage();
209 exit(0);
210 case '?':
211 opt = optopt;
212 /* fall thru to default */
213 default:
214 fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
215 usage();
216 had_error = 1;
217 }
218 }
219 if (had_error)
220 exit(1);
221 }
222
223 int
224 main(int argc, char *argv[])
225 {
226 char buf[BUFFER_SIZE];
227 int buflen = 0;
228 char user[NTLM_MAX_FIELD_LENGTH], domain[NTLM_MAX_FIELD_LENGTH];
229 char *p, *decoded = NULL;
230 ntlmhdr *packet = NULL;
231 char helper_command[3];
232 int len;
233 char *data = NULL;
234
235 setbuf(stdout, NULL);
236 setbuf(stderr, NULL);
237
238 my_program_name = argv[0];
239
240 process_options(argc, argv);
241
242 debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name);
243
244 while (fgets(buf, BUFFER_SIZE, stdin) != NULL) {
245 user[0] = '\0'; /*no user code */
246 domain[0] = '\0'; /*no domain code */
247
248 if ((p = strchr(buf, '\n')) != NULL)
249 *p = '\0'; /* strip \n */
250 buflen = strlen(buf); /* keep this so we only scan the buffer for \0 once per loop */
251 if (buflen > 3)
252 packet = (ntlmhdr*)base64_decode(buf + 3);
253 if (buflen > 3 && NTLM_packet_debug_enabled) {
254 strncpy(helper_command, buf, 2);
255 helper_command[2] = '\0';
256 debug("Got '%s' from Squid with data:\n", helper_command);
257 hex_dump((unsigned char*)packet, ((buflen - 3) * 3) / 4);
258 } else
259 debug("Got '%s' from Squid\n", buf);
260
261 if (strncasecmp(buf, "YR", 2) == 0) {
262 char nonce[NTLM_NONCE_LEN];
263 ntlm_challenge chal;
264 ntlm_make_nonce(nonce);
265 if (buflen > 3) {
266 ntlm_negotiate *nego = (ntlm_negotiate *)packet;
267 ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, nego->flags);
268 } else {
269 ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, NEGOTIATE_ASCII);
270 }
271 // TODO: find out what this context means, and why only the fake auth helper contains it.
272 chal.context_high = htole32(0x003a<<16);
273
274 len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
275 data = (char *) base64_encode_bin((char *) &chal, len);
276 if (NTLM_packet_debug_enabled) {
277 printf("TT %s\n", data);
278 debug("sending 'TT' to squid with data:\n");
279 hex_dump((unsigned char *)&chal, len);
280 } else
281 SEND2("TT %s", data);
282 } else if (strncasecmp(buf, "KK ", 3) == 0) {
283 if (!packet) {
284 SEND("BH received KK with no data! user=");
285 } else if (!ntlm_validate_packet(packet, NTLM_AUTHENTICATE)) {
286 if (ntlm_unpack_auth((ntlm_authenticate *)packet, user, domain, (buflen-3)) == 0) {
287 lc(user);
288 lc(domain);
289 if (strip_domain_enabled) {
290 SEND2("AF %s", user);
291 } else {
292 SEND3("AF %s%s%s", domain, (*domain?"\\":""), user);
293 }
294 } else {
295 lc(user);
296 lc(domain);
297 SEND3("NA invalid credentials, user=%s%s%s", domain, (*domain?"\\":""), user);
298 }
299 } else {
300 SEND("BH wrong packet type! user=");
301 }
302 }
303 }
304 exit(0);
305 }