]>
Commit | Line | Data |
---|---|---|
6e785d85 | 1 | /* |
8eeb87e6 | 2 | * negotiate_sspi_auth: helper for Negotiate Authentication for Squid Cache |
6e785d85 | 3 | * |
4 | * (C)2005 Guido Serassio - Acme Consulting S.r.l. | |
5 | * | |
6 | * Authors: | |
7 | * Guido Serassio <guido.serassio@acmeconsulting.it> | |
8 | * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it> | |
9 | * | |
10 | * With contributions from others mentioned in the change history section | |
11 | * below. | |
12 | * | |
13 | * Based on previous work of Francesco Chemolli and Robert Collins. | |
14 | * | |
9af66127 | 15 | * Dependencies: Windows 2000 and later. |
6e785d85 | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | |
18 | * it under the terms of the GNU General Public License as published by | |
19 | * the Free Software Foundation; either version 2 of the License, or | |
20 | * (at your option) any later version. | |
21 | * | |
22 | * This program is distributed in the hope that it will be useful, | |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License | |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
30 | * | |
31 | * History: | |
32 | * | |
33 | * Version 1.0 | |
34 | * 29-10-2005 Guido Serassio | |
35 | * First release. | |
36 | * | |
37 | * | |
38 | */ | |
f7f3304a | 39 | #include "squid.h" |
8eeb87e6 AJ |
40 | #include "helpers/defines.h" |
41 | #include "libntlmauth/support_bits.cci" | |
42 | #include "sspwin32.h" | |
6e785d85 | 43 | #include "util.h" |
8eeb87e6 AJ |
44 | |
45 | #include <windows.h> | |
46 | #include <sspi.h> | |
47 | #include <security.h> | |
6e785d85 | 48 | #if HAVE_GETOPT_H |
49 | #include <getopt.h> | |
50 | #endif | |
6e785d85 | 51 | #if HAVE_CTYPE_H |
52 | #include <ctype.h> | |
53 | #endif | |
54 | ||
6e785d85 | 55 | int Negotiate_packet_debug_enabled = 0; |
6e785d85 | 56 | static int have_serverblob; |
57 | ||
8eeb87e6 AJ |
58 | /* A couple of harmless helper macros */ |
59 | #define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n"); | |
60 | #ifdef __GNUC__ | |
61 | #define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); | |
62 | #define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); | |
63 | #else | |
64 | /* no gcc, no debugging. varargs macros are a gcc extension */ | |
65 | #define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); | |
66 | #define SEND3(X,Y,Z) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z); | |
6e785d85 | 67 | #endif |
8eeb87e6 AJ |
68 | |
69 | char *negotiate_check_auth(SSP_blobP auth, int auth_length); | |
6e785d85 | 70 | |
71 | /* | |
766743af GS |
72 | * options: |
73 | * -d enable debugging. | |
74 | * -v enable verbose Negotiate packet debugging. | |
6e785d85 | 75 | */ |
76 | char *my_program_name = NULL; | |
77 | ||
78 | void | |
79 | usage() | |
80 | { | |
81 | fprintf(stderr, | |
2f7be300 AJ |
82 | "Usage: %s [-d] [-v] [-h]\n" |
83 | " -d enable debugging.\n" | |
84 | " -v enable verbose Negotiate packet debugging.\n" | |
85 | " -h this message\n\n", | |
86 | my_program_name); | |
6e785d85 | 87 | } |
88 | ||
6e785d85 | 89 | void |
90 | process_options(int argc, char *argv[]) | |
91 | { | |
92 | int opt, had_error = 0; | |
93 | ||
766743af | 94 | opterr = 0; |
6e785d85 | 95 | while (-1 != (opt = getopt(argc, argv, "hdv"))) { |
2f7be300 AJ |
96 | switch (opt) { |
97 | case 'd': | |
98 | debug_enabled = 1; | |
99 | break; | |
100 | case 'v': | |
101 | debug_enabled = 1; | |
102 | Negotiate_packet_debug_enabled = 1; | |
103 | break; | |
104 | case 'h': | |
105 | usage(); | |
106 | exit(0); | |
107 | case '?': | |
108 | opt = optopt; | |
109 | /* fall thru to default */ | |
110 | default: | |
8eeb87e6 | 111 | fprintf(stderr, "ERROR: unknown option: -%c. Exiting\n", opt); |
2f7be300 AJ |
112 | usage(); |
113 | had_error = 1; | |
114 | } | |
6e785d85 | 115 | } |
116 | if (had_error) | |
2f7be300 | 117 | exit(1); |
6e785d85 | 118 | } |
119 | ||
120 | int | |
121 | manage_request() | |
122 | { | |
8eeb87e6 | 123 | char buf[HELPER_INPUT_BUFFER]; |
8bdd0cec AJ |
124 | char decoded[HELPER_INPUT_BUFFER]; |
125 | int decodedLen; | |
6e785d85 | 126 | char helper_command[3]; |
8bdd0cec AJ |
127 | char *c; |
128 | int status; | |
6e785d85 | 129 | int oversized = 0; |
766743af GS |
130 | char *ErrorMessage; |
131 | static char cred[SSP_MAX_CRED_LEN + 1]; | |
6e785d85 | 132 | BOOL Done = FALSE; |
133 | ||
2f7be300 | 134 | try_again: |
8eeb87e6 | 135 | if (fgets(buf, HELPER_INPUT_BUFFER, stdin)) |
2f7be300 | 136 | return 0; |
6e785d85 | 137 | |
8eeb87e6 | 138 | c = memchr(buf, '\n', HELPER_INPUT_BUFFER); /* safer against overrun than strchr */ |
6e785d85 | 139 | if (c) { |
2f7be300 | 140 | if (oversized) { |
8eeb87e6 AJ |
141 | SEND("BH illegal request received"); |
142 | fprintf(stderr, "ERROR: Illegal request received: '%s'\n", buf); | |
2f7be300 AJ |
143 | return 1; |
144 | } | |
145 | *c = '\0'; | |
6e785d85 | 146 | } else { |
2f7be300 AJ |
147 | fprintf(stderr, "No newline in '%s'\n", buf); |
148 | oversized = 1; | |
149 | goto try_again; | |
6e785d85 | 150 | } |
151 | ||
152 | if ((strlen(buf) > 3) && Negotiate_packet_debug_enabled) { | |
8bdd0cec | 153 | decodedLen = base64_decode(decoded, sizeof(decoded), buf+3); |
2f7be300 AJ |
154 | strncpy(helper_command, buf, 2); |
155 | debug("Got '%s' from Squid with data:\n", helper_command); | |
8bdd0cec | 156 | hex_dump(decoded, decodedLen); |
6e785d85 | 157 | } else |
2f7be300 | 158 | debug("Got '%s' from Squid\n", buf); |
6e785d85 | 159 | |
160 | if (memcmp(buf, "YR ", 3) == 0) { /* refresh-request */ | |
2f7be300 AJ |
161 | /* figure out what we got */ |
162 | decoded = base64_decode(buf + 3); | |
8bdd0cec | 163 | if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */ |
2f7be300 AJ |
164 | SEND("NA * Packet format error, couldn't base64-decode"); |
165 | return 1; | |
166 | } | |
167 | /* Obtain server blob against SSPI */ | |
8bdd0cec | 168 | c = (char *) SSP_MakeNegotiateBlob(decoded, decodedLen, &Done, &status, cred); |
6e785d85 | 169 | |
2f7be300 AJ |
170 | if (status == SSP_OK) { |
171 | if (Done) { | |
172 | lc(cred); /* let's lowercase them for our convenience */ | |
173 | have_serverblob = 0; | |
174 | Done = FALSE; | |
175 | if (Negotiate_packet_debug_enabled) { | |
8bdd0cec | 176 | decodedLen = base64_decode(decoded, sizeof(decoded), c); |
2f7be300 AJ |
177 | debug("sending 'AF' %s to squid with data:\n", cred); |
178 | if (c != NULL) | |
8bdd0cec | 179 | hex_dump(decoded, decodedLen); |
2f7be300 AJ |
180 | else |
181 | fprintf(stderr, "No data available.\n"); | |
182 | printf("AF %s %s\n", c, cred); | |
183 | } else | |
184 | SEND3("AF %s %s", c, cred); | |
185 | } else { | |
186 | if (Negotiate_packet_debug_enabled) { | |
8bdd0cec | 187 | decodedLen = base64_decode(decoded, sizeof(decoded), c); |
2f7be300 | 188 | debug("sending 'TT' to squid with data:\n"); |
8bdd0cec | 189 | hex_dump(decoded, decodedLen); |
2f7be300 AJ |
190 | printf("TT %s\n", c); |
191 | } else { | |
192 | SEND2("TT %s", c); | |
193 | } | |
194 | have_serverblob = 1; | |
195 | } | |
196 | } else | |
8eeb87e6 | 197 | SEND("BH can't obtain server blob"); |
2f7be300 | 198 | return 1; |
6e785d85 | 199 | } |
6e785d85 | 200 | if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */ |
2f7be300 | 201 | if (!have_serverblob) { |
8eeb87e6 | 202 | SEND("BH invalid server blob"); |
2f7be300 AJ |
203 | return 1; |
204 | } | |
205 | /* figure out what we got */ | |
8bdd0cec AJ |
206 | decodedLen = base64_decode(decoded, sizeof(decoded), buf+3); |
207 | if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */ | |
2f7be300 AJ |
208 | SEND("NA * Packet format error, couldn't base64-decode"); |
209 | return 1; | |
210 | } | |
211 | /* check against SSPI */ | |
8bdd0cec | 212 | c = (char *) SSP_ValidateNegotiateCredentials(decoded, decodedLen, &Done, &status, cred); |
6e785d85 | 213 | |
2f7be300 | 214 | if (status == SSP_ERROR) { |
2f7be300 AJ |
215 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | |
216 | FORMAT_MESSAGE_IGNORE_INSERTS, | |
217 | NULL, | |
218 | GetLastError(), | |
219 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ | |
220 | (LPTSTR) & ErrorMessage, | |
221 | 0, | |
222 | NULL); | |
223 | if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n') | |
224 | ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; | |
225 | if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r') | |
226 | ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; | |
227 | SEND2("NA * %s", ErrorMessage); | |
228 | LocalFree(ErrorMessage); | |
229 | return 1; | |
230 | } | |
231 | if (Done) { | |
232 | lc(cred); /* let's lowercase them for our convenience */ | |
233 | have_serverblob = 0; | |
234 | Done = FALSE; | |
235 | if (Negotiate_packet_debug_enabled) { | |
8bdd0cec | 236 | decodedLen = base64_decode(decoded, sizeof(decoded), c); |
2f7be300 AJ |
237 | debug("sending 'AF' %s to squid with data:\n", cred); |
238 | if (c != NULL) | |
8bdd0cec | 239 | hex_dump(decoded, decodedLen); |
2f7be300 AJ |
240 | else |
241 | fprintf(stderr, "No data available.\n"); | |
242 | printf("AF %s %s\n", c, cred); | |
243 | } else { | |
244 | SEND3("AF %s %s", c, cred); | |
245 | } | |
246 | return 1; | |
247 | } else { | |
248 | if (Negotiate_packet_debug_enabled) { | |
8bdd0cec | 249 | decodedLen = base64_decode(decoded, sizeof(decoded), c); |
2f7be300 | 250 | debug("sending 'TT' to squid with data:\n"); |
8bdd0cec | 251 | hex_dump(decoded, decodedLen); |
2f7be300 AJ |
252 | printf("TT %s\n", c); |
253 | } else | |
254 | SEND2("TT %s", c); | |
255 | return 1; | |
256 | } | |
6e785d85 | 257 | |
766743af | 258 | } else { /* not an auth-request */ |
8eeb87e6 | 259 | SEND("BH illegal request received"); |
2f7be300 AJ |
260 | fprintf(stderr, "Illegal request received: '%s'\n", buf); |
261 | return 1; | |
6e785d85 | 262 | } |
8eeb87e6 | 263 | SEND("BH detected protocol error"); |
6e785d85 | 264 | return 1; |
2f7be300 | 265 | /********* END ********/ |
6e785d85 | 266 | } |
267 | ||
268 | int | |
269 | main(int argc, char *argv[]) | |
270 | { | |
271 | my_program_name = argv[0]; | |
272 | ||
273 | process_options(argc, argv); | |
274 | ||
275 | debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name); | |
26ac0430 | 276 | |
6e785d85 | 277 | if (LoadSecurityDll(SSP_NTLM, NEGOTIATE_PACKAGE_NAME) == NULL) { |
8eeb87e6 | 278 | fprintf(stderr, "FATAL: %s: can't initialize SSPI, exiting.\n", argv[0]); |
2f7be300 | 279 | exit(1); |
6e785d85 | 280 | } |
281 | debug("SSPI initialized OK\n"); | |
282 | ||
283 | atexit(UnloadSecurityDll); | |
284 | ||
285 | /* initialize FDescs */ | |
286 | setbuf(stdout, NULL); | |
287 | setbuf(stderr, NULL); | |
288 | ||
289 | while (manage_request()) { | |
2f7be300 | 290 | /* everything is done within manage_request */ |
6e785d85 | 291 | } |
292 | exit(0); | |
293 | } |