]>
Commit | Line | Data |
---|---|---|
75aa769b AJ |
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 | ||
f7f3304a | 56 | #include "squid.h" |
25f98340 | 57 | #include "base64.h" |
dcb9c96c | 58 | #include "helpers/defines.h" |
7c16470c AJ |
59 | #include "ntlmauth/ntlmauth.h" |
60 | #include "ntlmauth/support_bits.cci" | |
25f98340 | 61 | //#include "util.h" |
75aa769b | 62 | |
75aa769b AJ |
63 | #if HAVE_STRING_H |
64 | #include <string.h> | |
65 | #endif | |
5dc2526c FC |
66 | #if HAVE_CTYPE_H |
67 | #include <ctype.h> | |
68 | #endif | |
75aa769b AJ |
69 | #if HAVE_CRYPT_H |
70 | #include <crypt.h> | |
71 | #endif | |
72 | #if HAVE_PWD_H | |
73 | #include <pwd.h> | |
74 | #endif | |
75 | #if HAVE_GETOPT_H | |
76 | #include <getopt.h> | |
77 | #endif | |
5dc2526c FC |
78 | #if HAVE_STDIO_H |
79 | #include <stdio.h> | |
80 | #endif | |
81 | #if HAVE_STDINT_H | |
82 | #include <stdint.h> | |
83 | #endif | |
84 | #if HAVE_INTTYPES_H | |
85 | #include <inttypes.h> | |
86 | #endif | |
75aa769b | 87 | |
75aa769b AJ |
88 | /* A couple of harmless helper macros */ |
89 | #define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n"); | |
90 | #ifdef __GNUC__ | |
91 | #define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); | |
59a09b98 | 92 | #define SEND4(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); |
75aa769b AJ |
93 | #else |
94 | /* no gcc, no debugging. varargs macros are a gcc extension */ | |
95 | #define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); | |
079c2dd4 | 96 | #define SEND4(X,Y,Z,W) debug("sending '" X "' to squid\n",Y,Z,W); printf(X "\n",Y,Z,W); |
75aa769b AJ |
97 | #endif |
98 | ||
75aa769b AJ |
99 | const char *authenticate_ntlm_domain = "WORKGROUP"; |
100 | int strip_domain_enabled = 0; | |
101 | int NTLM_packet_debug_enabled = 0; | |
102 | ||
75aa769b AJ |
103 | /* |
104 | * options: | |
105 | * -d enable debugging. | |
106 | * -v enable verbose NTLM packet debugging. | |
107 | * -l if specified, changes behavior on failures to last-ditch. | |
108 | */ | |
109 | char *my_program_name = NULL; | |
110 | ||
111 | static void | |
112 | usage(void) | |
113 | { | |
114 | fprintf(stderr, | |
115 | "Usage: %s [-d] [-v] [-h]\n" | |
116 | " -d enable debugging.\n" | |
117 | " -S strip domain from username.\n" | |
118 | " -v enable verbose NTLM packet debugging.\n" | |
119 | " -h this message\n\n", | |
120 | my_program_name); | |
121 | } | |
122 | ||
123 | static void | |
124 | process_options(int argc, char *argv[]) | |
125 | { | |
126 | int opt, had_error = 0; | |
127 | ||
128 | opterr = 0; | |
129 | while (-1 != (opt = getopt(argc, argv, "hdvS"))) { | |
130 | switch (opt) { | |
131 | case 'd': | |
132 | debug_enabled = 1; | |
133 | break; | |
134 | case 'v': | |
135 | debug_enabled = 1; | |
136 | NTLM_packet_debug_enabled = 1; | |
137 | break; | |
138 | case 'S': | |
139 | strip_domain_enabled = 1; | |
140 | break; | |
141 | case 'h': | |
142 | usage(); | |
143 | exit(0); | |
144 | case '?': | |
145 | opt = optopt; | |
146 | /* fall thru to default */ | |
147 | default: | |
148 | fprintf(stderr, "unknown option: -%c. Exiting\n", opt); | |
149 | usage(); | |
150 | had_error = 1; | |
151 | } | |
152 | } | |
153 | if (had_error) | |
154 | exit(1); | |
155 | } | |
156 | ||
157 | int | |
158 | main(int argc, char *argv[]) | |
159 | { | |
4c4ca9c2 | 160 | char buf[HELPER_INPUT_BUFFER]; |
75aa769b | 161 | int buflen = 0; |
8bdd0cec AJ |
162 | char decodedBuf[HELPER_INPUT_BUFFER]; |
163 | int decodedLen; | |
75aa769b | 164 | char user[NTLM_MAX_FIELD_LENGTH], domain[NTLM_MAX_FIELD_LENGTH]; |
350f6838 | 165 | char *p; |
75aa769b AJ |
166 | ntlmhdr *packet = NULL; |
167 | char helper_command[3]; | |
168 | int len; | |
169 | char *data = NULL; | |
170 | ||
171 | setbuf(stdout, NULL); | |
172 | setbuf(stderr, NULL); | |
173 | ||
174 | my_program_name = argv[0]; | |
175 | ||
176 | process_options(argc, argv); | |
177 | ||
178 | debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name); | |
179 | ||
dcb9c96c | 180 | while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) { |
75aa769b AJ |
181 | user[0] = '\0'; /*no user code */ |
182 | domain[0] = '\0'; /*no domain code */ | |
183 | ||
184 | if ((p = strchr(buf, '\n')) != NULL) | |
185 | *p = '\0'; /* strip \n */ | |
186 | buflen = strlen(buf); /* keep this so we only scan the buffer for \0 once per loop */ | |
8bdd0cec AJ |
187 | if (buflen > 3) { |
188 | decodedLen = base64_decode(decodedBuf, sizeof(decodedBuf), buf+3); | |
189 | packet = (ntlmhdr*)decodedBuf; | |
190 | } else { | |
191 | packet = NULL; | |
fb599974 | 192 | decodedLen = 0; |
8bdd0cec | 193 | } |
75aa769b AJ |
194 | if (buflen > 3 && NTLM_packet_debug_enabled) { |
195 | strncpy(helper_command, buf, 2); | |
196 | helper_command[2] = '\0'; | |
197 | debug("Got '%s' from Squid with data:\n", helper_command); | |
8bdd0cec | 198 | hex_dump((unsigned char *)decodedBuf, decodedLen); |
75aa769b AJ |
199 | } else |
200 | debug("Got '%s' from Squid\n", buf); | |
201 | ||
5dc2526c | 202 | if (strncmp(buf, "YR", 2) == 0) { |
75aa769b AJ |
203 | char nonce[NTLM_NONCE_LEN]; |
204 | ntlm_challenge chal; | |
205 | ntlm_make_nonce(nonce); | |
206 | if (buflen > 3) { | |
207 | ntlm_negotiate *nego = (ntlm_negotiate *)packet; | |
208 | ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, nego->flags); | |
209 | } else { | |
1dcf61eb | 210 | ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, NTLM_NEGOTIATE_ASCII); |
75aa769b AJ |
211 | } |
212 | // TODO: find out what this context means, and why only the fake auth helper contains it. | |
213 | chal.context_high = htole32(0x003a<<16); | |
214 | ||
215 | len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen); | |
216 | data = (char *) base64_encode_bin((char *) &chal, len); | |
217 | if (NTLM_packet_debug_enabled) { | |
218 | printf("TT %s\n", data); | |
219 | debug("sending 'TT' to squid with data:\n"); | |
220 | hex_dump((unsigned char *)&chal, len); | |
221 | } else | |
222 | SEND2("TT %s", data); | |
5dc2526c | 223 | } else if (strncmp(buf, "KK ", 3) == 0) { |
75aa769b AJ |
224 | if (!packet) { |
225 | SEND("BH received KK with no data! user="); | |
1dcf61eb | 226 | } else if (ntlm_validate_packet(packet, NTLM_AUTHENTICATE) == NTLM_ERR_NONE) { |
8bdd0cec | 227 | if (ntlm_unpack_auth((ntlm_authenticate *)packet, user, domain, decodedLen) == NTLM_ERR_NONE) { |
75aa769b AJ |
228 | lc(user); |
229 | lc(domain); | |
230 | if (strip_domain_enabled) { | |
231 | SEND2("AF %s", user); | |
232 | } else { | |
59a09b98 | 233 | SEND4("AF %s%s%s", domain, (*domain?"\\":""), user); |
75aa769b AJ |
234 | } |
235 | } else { | |
236 | lc(user); | |
237 | lc(domain); | |
59a09b98 | 238 | SEND4("NA invalid credentials, user=%s%s%s", domain, (*domain?"\\":""), user); |
75aa769b AJ |
239 | } |
240 | } else { | |
241 | SEND("BH wrong packet type! user="); | |
242 | } | |
243 | } | |
244 | } | |
245 | exit(0); | |
246 | } |