]>
Commit | Line | Data |
---|---|---|
ca02e0ec | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 The Squid Software Foundation and contributors |
ca02e0ec AJ |
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 | ||
6e785d85 | 9 | /* |
bc25525a | 10 | * ntlm_sspi_auth: helper for NTLM Authentication for Squid Cache |
6e785d85 | 11 | * |
9af66127 | 12 | * (C)2002,2005 Guido Serassio - Acme Consulting S.r.l. |
6e785d85 | 13 | * |
14 | * Authors: | |
15 | * Guido Serassio <guido.serassio@acmeconsulting.it> | |
16 | * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it> | |
17 | * | |
18 | * With contributions from others mentioned in the change history section | |
19 | * below. | |
20 | * | |
21 | * Based on previous work of Francesco Chemolli and Robert Collins. | |
22 | * | |
23 | * Dependencies: Windows NT4 SP4 and later. | |
24 | * | |
25 | * This program is free software; you can redistribute it and/or modify | |
26 | * it under the terms of the GNU General Public License as published by | |
27 | * the Free Software Foundation; either version 2 of the License, or | |
28 | * (at your option) any later version. | |
29 | * | |
30 | * This program is distributed in the hope that it will be useful, | |
31 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
33 | * GNU General Public License for more details. | |
34 | * | |
35 | * You should have received a copy of the GNU General Public License | |
36 | * along with this program; if not, write to the Free Software | |
37 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
38 | * | |
39 | * History: | |
40 | * | |
9af66127 | 41 | * Version 1.22 |
42 | * 29-10-2005 Guido Serassio | |
43 | * Updated for Negotiate auth support. | |
6e785d85 | 44 | * Version 1.21 |
45 | * 21-02-2004 Guido Serassio | |
46 | * Removed control of use of NTLM NEGOTIATE packet from | |
47 | * command line, now the support is automatic. | |
48 | * Version 1.20 | |
49 | * 30-11-2003 Guido Serassio | |
50 | * Added support for NTLM local calls. | |
51 | * Added control of use of NTLM NEGOTIATE packet from | |
52 | * command line. | |
53 | * Updated documentation. | |
54 | * Version 1.10 | |
55 | * 07-09-2003 Guido Serassio | |
56 | * Now is true NTLM authenticator. | |
57 | * More debug info. | |
58 | * Updated documentation. | |
59 | * Version 1.0 | |
60 | * 29-06-2002 Guido Serassio | |
61 | * First release. | |
62 | * | |
63 | * | |
64 | */ | |
65 | ||
bc25525a AJ |
66 | /************* CONFIGURATION ***************/ |
67 | ||
68 | #define FAIL_DEBUG 0 | |
69 | ||
70 | /************* END CONFIGURATION ***************/ | |
71 | ||
6ad14574 | 72 | //typedef unsigned char uchar; |
bc25525a | 73 | |
f7f3304a | 74 | #include "squid.h" |
6ad14574 | 75 | #include "base64.h" |
079b1d0f | 76 | #include "helper/protocol_defines.h" |
6ad14574 AJ |
77 | #include "ntlmauth/ntlmauth.h" |
78 | #include "ntlmauth/support_bits.cci" | |
bc25525a | 79 | #include "sspwin32.h" |
6e785d85 | 80 | #include "util.h" |
bc25525a AJ |
81 | |
82 | #include <windows.h> | |
83 | #include <sspi.h> | |
84 | #include <security.h> | |
6e785d85 | 85 | #if HAVE_CTYPE_H |
86 | #include <ctype.h> | |
87 | #endif | |
bc25525a AJ |
88 | #if HAVE_GETOPT_H |
89 | #include <getopt.h> | |
90 | #endif | |
91 | #include <lm.h> | |
92 | #include <ntsecapi.h> | |
6e785d85 | 93 | |
6e785d85 | 94 | int NTLM_packet_debug_enabled = 0; |
6e785d85 | 95 | static int have_challenge; |
6e785d85 | 96 | char * NTAllowedGroup; |
97 | char * NTDisAllowedGroup; | |
98 | int UseDisallowedGroup = 0; | |
99 | int UseAllowedGroup = 0; | |
bc25525a | 100 | |
6e785d85 | 101 | #if FAIL_DEBUG |
102 | int fail_debug_enabled = 0; | |
103 | #endif | |
104 | ||
bc25525a AJ |
105 | /* returns 1 on success, 0 on failure */ |
106 | int | |
107 | Valid_Group(char *UserName, char *Group) | |
6e785d85 | 108 | { |
bc25525a | 109 | int result = FALSE; |
f53969cc SM |
110 | WCHAR wszUserName[UNLEN+1]; // Unicode user name |
111 | WCHAR wszGroup[GNLEN+1]; // Unicode Group | |
bc25525a AJ |
112 | |
113 | LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; | |
114 | LPLOCALGROUP_USERS_INFO_0 pTmpBuf; | |
115 | DWORD dwLevel = 0; | |
116 | DWORD dwFlags = LG_INCLUDE_INDIRECT; | |
117 | DWORD dwPrefMaxLen = -1; | |
118 | DWORD dwEntriesRead = 0; | |
119 | DWORD dwTotalEntries = 0; | |
120 | NET_API_STATUS nStatus; | |
121 | DWORD i; | |
122 | DWORD dwTotalCount = 0; | |
123 | ||
124 | /* Convert ANSI User Name and Group to Unicode */ | |
125 | ||
126 | MultiByteToWideChar(CP_ACP, 0, UserName, | |
127 | strlen(UserName) + 1, wszUserName, | |
128 | sizeof(wszUserName) / sizeof(wszUserName[0])); | |
129 | MultiByteToWideChar(CP_ACP, 0, Group, | |
130 | strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0])); | |
131 | ||
132 | /* | |
133 | * Call the NetUserGetLocalGroups function | |
134 | * specifying information level 0. | |
135 | * | |
136 | * The LG_INCLUDE_INDIRECT flag specifies that the | |
137 | * function should also return the names of the local | |
138 | * groups in which the user is indirectly a member. | |
139 | */ | |
140 | nStatus = NetUserGetLocalGroups(NULL, | |
141 | wszUserName, | |
142 | dwLevel, | |
143 | dwFlags, | |
144 | (LPBYTE *) & pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); | |
145 | /* | |
146 | * If the call succeeds, | |
147 | */ | |
148 | if (nStatus == NERR_Success) { | |
149 | if ((pTmpBuf = pBuf) != NULL) { | |
755494da | 150 | for (i = 0; i < dwEntriesRead; ++i) { |
bc25525a AJ |
151 | if (pTmpBuf == NULL) { |
152 | result = FALSE; | |
153 | break; | |
154 | } | |
155 | if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 0) { | |
156 | result = TRUE; | |
157 | break; | |
158 | } | |
755494da FC |
159 | ++pTmpBuf; |
160 | ++dwTotalCount; | |
bc25525a AJ |
161 | } |
162 | } | |
163 | } else | |
164 | result = FALSE; | |
165 | /* | |
166 | * Free the allocated memory. | |
167 | */ | |
168 | if (pBuf != NULL) | |
169 | NetApiBufferFree(pBuf); | |
170 | return result; | |
171 | } | |
172 | ||
bc25525a AJ |
173 | char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr) |
174 | { | |
175 | size_t len; | |
176 | static char * target; | |
177 | ||
178 | len = LsaStr.Length/sizeof(WCHAR) + 1; | |
179 | ||
180 | /* allocate buffer for str + null termination */ | |
181 | safe_free(target); | |
182 | target = (char *)xmalloc(len); | |
183 | if (target == NULL) | |
184 | return NULL; | |
185 | ||
186 | /* copy unicode buffer */ | |
187 | WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL ); | |
188 | ||
189 | /* add null termination */ | |
190 | target[len-1] = '\0'; | |
191 | return target; | |
6e785d85 | 192 | } |
193 | ||
bc25525a AJ |
194 | char * GetDomainName(void) |
195 | ||
6e785d85 | 196 | { |
bc25525a AJ |
197 | LSA_HANDLE PolicyHandle; |
198 | LSA_OBJECT_ATTRIBUTES ObjectAttributes; | |
199 | NTSTATUS status; | |
200 | PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo; | |
201 | PWKSTA_INFO_100 pwkiWorkstationInfo; | |
202 | DWORD netret; | |
203 | char * DomainName = NULL; | |
204 | ||
205 | /* | |
206 | * Always initialize the object attributes to all zeroes. | |
207 | */ | |
208 | memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes)); | |
209 | ||
210 | /* | |
211 | * You need the local workstation name. Use NetWkstaGetInfo at level | |
212 | * 100 to retrieve a WKSTA_INFO_100 structure. | |
213 | * | |
214 | * The wki100_computername field contains a pointer to a UNICODE | |
215 | * string containing the local computer name. | |
216 | */ | |
217 | netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *)&pwkiWorkstationInfo); | |
218 | if (netret == NERR_Success) { | |
219 | /* | |
220 | * We have the workstation name in: | |
221 | * pwkiWorkstationInfo->wki100_computername | |
222 | * | |
223 | * Next, open the policy object for the local system using | |
224 | * the LsaOpenPolicy function. | |
225 | */ | |
226 | status = LsaOpenPolicy( | |
227 | NULL, | |
228 | &ObjectAttributes, | |
229 | GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, | |
230 | &PolicyHandle | |
231 | ); | |
232 | ||
233 | /* | |
234 | * Error checking. | |
235 | */ | |
236 | if (status) { | |
237 | debug("OpenPolicy Error: %ld\n", status); | |
238 | } else { | |
239 | ||
240 | /* | |
241 | * You have a handle to the policy object. Now, get the | |
242 | * domain information using LsaQueryInformationPolicy. | |
243 | */ | |
244 | status = LsaQueryInformationPolicy(PolicyHandle, | |
245 | PolicyPrimaryDomainInformation, | |
246 | (void **)&ppdiDomainInfo); | |
247 | if (status) { | |
248 | debug("LsaQueryInformationPolicy Error: %ld\n", status); | |
249 | } else { | |
250 | ||
251 | /* Get name in useable format */ | |
252 | DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name); | |
253 | ||
254 | /* | |
255 | * Check the Sid pointer, if it is null, the | |
256 | * workstation is either a stand-alone computer | |
257 | * or a member of a workgroup. | |
258 | */ | |
259 | if (ppdiDomainInfo->Sid) { | |
260 | ||
261 | /* | |
262 | * Member of a domain. Display it in debug mode. | |
263 | */ | |
264 | debug("Member of Domain %s\n",DomainName); | |
265 | } else { | |
266 | DomainName = NULL; | |
267 | } | |
268 | } | |
269 | } | |
270 | ||
271 | /* | |
272 | * Clean up all the memory buffers created by the LSA and | |
273 | * Net* APIs. | |
274 | */ | |
275 | NetApiBufferFree(pwkiWorkstationInfo); | |
276 | LsaFreeMemory((LPVOID)ppdiDomainInfo); | |
277 | } else | |
278 | debug("NetWkstaGetInfo Error: %ld\n", netret); | |
279 | return DomainName; | |
280 | } | |
281 | ||
6ad14574 AJ |
282 | /* |
283 | * Fills auth with the user's credentials. | |
284 | * | |
285 | * In case of problem returns one of the | |
bc25525a AJ |
286 | * codes defined in libntlmauth/ntlmauth.h |
287 | */ | |
288 | int | |
289 | ntlm_check_auth(ntlm_authenticate * auth, char *user, char *domain, int auth_length) | |
290 | { | |
291 | int x; | |
292 | int rv; | |
f53969cc | 293 | char credentials[DNLEN+UNLEN+2]; /* we can afford to waste */ |
bc25525a AJ |
294 | |
295 | if (!NTLM_LocalCall) { | |
296 | ||
297 | user[0] = '\0'; | |
298 | domain[0] = '\0'; | |
299 | x = ntlm_unpack_auth(auth, user, domain, auth_length); | |
300 | ||
301 | if (x != NTLM_ERR_NONE) | |
302 | return x; | |
303 | ||
304 | if (domain[0] == '\0') { | |
305 | debug("No domain supplied. Returning no-auth\n"); | |
306 | return NTLM_BAD_REQUEST; | |
307 | } | |
308 | if (user[0] == '\0') { | |
309 | debug("No username supplied. Returning no-auth\n"); | |
310 | return NTLM_BAD_REQUEST; | |
311 | } | |
312 | debug("checking domain: '%s', user: '%s'\n", domain, user); | |
313 | ||
314 | } else | |
315 | debug("checking local user\n"); | |
316 | ||
317 | snprintf(credentials, DNLEN+UNLEN+2, "%s\\%s", domain, user); | |
318 | ||
319 | rv = SSP_ValidateNTLMCredentials(auth, auth_length, credentials); | |
320 | ||
321 | debug("Login attempt had result %d\n", rv); | |
322 | ||
f53969cc | 323 | if (!rv) { /* failed */ |
bc25525a AJ |
324 | return NTLM_SSPI_ERROR; |
325 | } | |
326 | ||
327 | if (UseAllowedGroup) { | |
328 | if (!Valid_Group(credentials, NTAllowedGroup)) { | |
329 | debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup); | |
330 | return NTLM_BAD_NTGROUP; | |
331 | } | |
6e785d85 | 332 | } |
bc25525a AJ |
333 | if (UseDisallowedGroup) { |
334 | if (Valid_Group(credentials, NTDisAllowedGroup)) { | |
335 | debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup); | |
336 | return NTLM_BAD_NTGROUP; | |
337 | } | |
338 | } | |
339 | ||
340 | debug("credentials: %s\n", credentials); | |
341 | return NTLM_ERR_NONE; | |
6e785d85 | 342 | } |
343 | ||
344 | void | |
345 | helperfail(const char *reason) | |
346 | { | |
347 | #if FAIL_DEBUG | |
348 | fail_debug_enabled =1; | |
349 | #endif | |
6ad14574 | 350 | SEND_BH(reason); |
6e785d85 | 351 | } |
352 | ||
353 | /* | |
354 | options: | |
355 | -d enable debugging. | |
356 | -v enable verbose NTLM packet debugging. | |
6e785d85 | 357 | -A can specify a Windows Local Group name allowed to authenticate. |
358 | -D can specify a Windows Local Group name not allowed to authenticate. | |
359 | */ | |
360 | char *my_program_name = NULL; | |
361 | ||
362 | void | |
363 | usage() | |
364 | { | |
365 | fprintf(stderr, | |
26ac0430 AJ |
366 | "Usage: %s [-d] [-v] [-A|D LocalUserGroup] [-h]\n" |
367 | " -d enable debugging.\n" | |
368 | " -v enable verbose NTLM packet debugging.\n" | |
369 | " -A specify a Windows Local Group name allowed to authenticate\n" | |
370 | " -D specify a Windows Local Group name not allowed to authenticate\n" | |
371 | " -h this message\n\n", | |
372 | my_program_name); | |
6e785d85 | 373 | } |
374 | ||
6e785d85 | 375 | void |
376 | process_options(int argc, char *argv[]) | |
377 | { | |
378 | int opt, had_error = 0; | |
379 | ||
380 | opterr =0; | |
381 | while (-1 != (opt = getopt(argc, argv, "hdvA:D:"))) { | |
26ac0430 AJ |
382 | switch (opt) { |
383 | case 'A': | |
384 | safe_free(NTAllowedGroup); | |
385 | NTAllowedGroup=xstrdup(optarg); | |
386 | UseAllowedGroup = 1; | |
387 | break; | |
388 | case 'D': | |
389 | safe_free(NTDisAllowedGroup); | |
390 | NTDisAllowedGroup=xstrdup(optarg); | |
391 | UseDisallowedGroup = 1; | |
392 | break; | |
393 | case 'd': | |
394 | debug_enabled = 1; | |
395 | break; | |
396 | case 'v': | |
397 | debug_enabled = 1; | |
398 | NTLM_packet_debug_enabled = 1; | |
399 | break; | |
400 | case 'h': | |
401 | usage(); | |
402 | exit(0); | |
403 | case '?': | |
404 | opt = optopt; | |
f53969cc | 405 | /* fall thru to default */ |
26ac0430 AJ |
406 | default: |
407 | fprintf(stderr, "unknown option: -%c. Exiting\n", opt); | |
408 | usage(); | |
409 | had_error = 1; | |
410 | } | |
6e785d85 | 411 | } |
412 | if (had_error) | |
26ac0430 | 413 | exit(1); |
6e785d85 | 414 | } |
415 | ||
836a7ffc AJ |
416 | static bool |
417 | token_decode(size_t *decodedLen, uint8_t decoded[], const char *buf) | |
418 | { | |
419 | struct base64_decode_ctx ctx; | |
420 | base64_decode_init(&ctx); | |
421 | if (!base64_decode_update(&ctx, decodedLen, decoded, strlen(buf), reinterpret_cast<const uint8_t*>(buf)) || | |
422 | !base64_decode_final(&ctx)) { | |
423 | SEND_BH("message=\"base64 decode failed\""); | |
424 | fprintf(stderr, "ERROR: base64 decoding failed for: '%s'\n", buf); | |
425 | return false; | |
426 | } | |
427 | return true; | |
428 | } | |
429 | ||
6e785d85 | 430 | int |
431 | manage_request() | |
432 | { | |
433 | ntlmhdr *fast_header; | |
6ad14574 | 434 | char buf[HELPER_INPUT_BUFFER]; |
836a7ffc AJ |
435 | uint8_t decoded[HELPER_INPUT_BUFFER]; |
436 | size_t decodedLen = 0; | |
6e785d85 | 437 | char helper_command[3]; |
6e785d85 | 438 | int oversized = 0; |
439 | char * ErrorMessage; | |
bc25525a AJ |
440 | static ntlm_negotiate local_nego; |
441 | char domain[DNLEN+1]; | |
442 | char user[UNLEN+1]; | |
443 | ||
444 | /* NP: for some reason this helper sometimes needs to accept | |
445 | * from clients that send no negotiate packet. */ | |
6ad14574 | 446 | if (memcpy(local_nego.hdr.signature, "NTLMSSP", 8) != 0) { |
f53969cc | 447 | memset(&local_nego, 0, sizeof(ntlm_negotiate)); /* reset */ |
6ad14574 AJ |
448 | memcpy(local_nego.hdr.signature, "NTLMSSP", 8); /* set the signature */ |
449 | local_nego.hdr.type = le32toh(NTLM_NEGOTIATE); /* this is a challenge */ | |
bc25525a AJ |
450 | local_nego.flags = le32toh(NTLM_NEGOTIATE_ALWAYS_SIGN | |
451 | NTLM_NEGOTIATE_USE_NTLM | | |
452 | NTLM_NEGOTIATE_USE_LM | | |
453 | NTLM_NEGOTIATE_ASCII ); | |
454 | } | |
6e785d85 | 455 | |
6ad14574 AJ |
456 | do { |
457 | if (fgets(buf, sizeof(buf), stdin) == NULL) | |
458 | return 0; | |
6e785d85 | 459 | |
6ad14574 AJ |
460 | char *c = static_cast<char*>(memchr(buf, '\n', sizeof(buf))); |
461 | if (c) { | |
462 | if (oversized) { | |
463 | helperfail("messge=\"illegal request received\""); | |
464 | fprintf(stderr, "Illegal request received: '%s'\n", buf); | |
465 | return 1; | |
466 | } | |
467 | *c = '\0'; | |
468 | } else { | |
469 | fprintf(stderr, "No newline in '%s'\n", buf); | |
470 | oversized = 1; | |
471 | continue; | |
26ac0430 | 472 | } |
6ad14574 AJ |
473 | } while (false); |
474 | ||
6e785d85 | 475 | if ((strlen(buf) > 3) && NTLM_packet_debug_enabled) { |
836a7ffc AJ |
476 | if (!token_decode(&decodedLen, decoded, buf+3)) |
477 | return 1; | |
6e785d85 | 478 | strncpy(helper_command, buf, 2); |
479 | debug("Got '%s' from Squid with data:\n", helper_command); | |
6ad14574 | 480 | hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen); |
6e785d85 | 481 | } else |
482 | debug("Got '%s' from Squid\n", buf); | |
f53969cc | 483 | if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ |
26ac0430 | 484 | /* figure out what we got */ |
836a7ffc AJ |
485 | if (strlen(buf) > 3) { |
486 | if (!decodedLen /* already decoded*/ && !token_decode(&decodedLen, decoded, buf+3)) | |
487 | return 1; | |
488 | } else { | |
bc25525a | 489 | debug("Negotiate packet not supplied - self generated\n"); |
6ad14574 AJ |
490 | memcpy(decoded, &local_nego, sizeof(local_nego)); |
491 | decodedLen = sizeof(local_nego); | |
bc25525a | 492 | } |
f53969cc | 493 | if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */ |
836a7ffc | 494 | SEND_ERR("message=\"Packet format error\""); |
26ac0430 AJ |
495 | return 1; |
496 | } | |
497 | /* fast-track-decode request type. */ | |
498 | fast_header = (struct _ntlmhdr *) decoded; | |
6e785d85 | 499 | |
26ac0430 | 500 | /* sanity-check: it IS a NTLMSSP packet, isn't it? */ |
bc25525a | 501 | if (ntlm_validate_packet(fast_header, NTLM_ANY) != NTLM_ERR_NONE) { |
6ad14574 | 502 | SEND_ERR("message=\"Broken authentication packet\""); |
26ac0430 AJ |
503 | return 1; |
504 | } | |
505 | switch (fast_header->type) { | |
6ad14574 | 506 | case NTLM_NEGOTIATE: { |
26ac0430 | 507 | /* Obtain challenge against SSPI */ |
23ad9b9e | 508 | debug("attempting SSPI challenge retrieval\n"); |
6ad14574 AJ |
509 | char *c = (char *) SSP_MakeChallenge((ntlm_negotiate *) decoded, decodedLen); |
510 | if (c) { | |
511 | SEND_TT(c); | |
23ad9b9e | 512 | if (NTLM_packet_debug_enabled) { |
836a7ffc AJ |
513 | if (!token_decode(&decodedLen, decoded, c)) |
514 | return 1; | |
6ad14574 AJ |
515 | debug("send 'TT' to squid with data:\n"); |
516 | hex_dump(reinterpret_cast<unsigned char*>(decoded), decodedLen); | |
517 | if (NTLM_LocalCall) { | |
23ad9b9e | 518 | debug("NTLM Local Call detected\n"); |
6ad14574 | 519 | } |
23ad9b9e A |
520 | } |
521 | have_challenge = 1; | |
522 | } else | |
6ad14574 | 523 | helperfail("message=\"can't obtain challenge\""); |
23ad9b9e A |
524 | |
525 | return 1; | |
26d714be A |
526 | } |
527 | /* notreached */ | |
23ad9b9e | 528 | case NTLM_CHALLENGE: |
6ad14574 | 529 | SEND_ERR("message=\"Got a challenge. We refuse to have our authority disputed\""); |
23ad9b9e | 530 | return 1; |
f53969cc | 531 | /* notreached */ |
23ad9b9e | 532 | case NTLM_AUTHENTICATE: |
6ad14574 | 533 | SEND_ERR("message=\"Got authentication request instead of negotiate request\""); |
23ad9b9e | 534 | return 1; |
f53969cc | 535 | /* notreached */ |
23ad9b9e | 536 | default: |
6ad14574 | 537 | helperfail("message=\"unknown refresh-request packet type\""); |
23ad9b9e A |
538 | return 1; |
539 | } | |
26ac0430 | 540 | return 1; |
6e785d85 | 541 | } |
f53969cc | 542 | if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */ |
6e785d85 | 543 | if (!have_challenge) { |
6ad14574 | 544 | helperfail("message=\"invalid challenge\""); |
26ac0430 | 545 | return 1; |
6e785d85 | 546 | } |
26ac0430 | 547 | /* figure out what we got */ |
836a7ffc AJ |
548 | if (!decodedLen /* already decoded*/ && !token_decode(&decodedLen, decoded, buf+3)) |
549 | return 1; | |
6e785d85 | 550 | |
f53969cc | 551 | if ((size_t)decodedLen < sizeof(ntlmhdr)) { /* decoding failure, return error */ |
836a7ffc | 552 | SEND_ERR("message=\"Packet format error\""); |
26ac0430 AJ |
553 | return 1; |
554 | } | |
555 | /* fast-track-decode request type. */ | |
556 | fast_header = (struct _ntlmhdr *) decoded; | |
6e785d85 | 557 | |
26ac0430 | 558 | /* sanity-check: it IS a NTLMSSP packet, isn't it? */ |
bc25525a | 559 | if (ntlm_validate_packet(fast_header, NTLM_ANY) != NTLM_ERR_NONE) { |
6ad14574 | 560 | SEND_ERR("message=\"Broken authentication packet\""); |
26ac0430 AJ |
561 | return 1; |
562 | } | |
563 | switch (fast_header->type) { | |
564 | case NTLM_NEGOTIATE: | |
6ad14574 | 565 | SEND_ERR("message=\"Invalid negotiation request received\""); |
26ac0430 | 566 | return 1; |
f53969cc | 567 | /* notreached */ |
26ac0430 | 568 | case NTLM_CHALLENGE: |
6ad14574 | 569 | SEND_ERR("message=\"Got a challenge. We refuse to have our authority disputed\""); |
26ac0430 | 570 | return 1; |
f53969cc | 571 | /* notreached */ |
6ad14574 | 572 | case NTLM_AUTHENTICATE: { |
26ac0430 | 573 | /* check against SSPI */ |
6ad14574 | 574 | int err = ntlm_check_auth((ntlm_authenticate *) decoded, user, domain, decodedLen); |
6e785d85 | 575 | have_challenge = 0; |
bc25525a | 576 | if (err != NTLM_ERR_NONE) { |
6e785d85 | 577 | #if FAIL_DEBUG |
578 | fail_debug_enabled =1; | |
579 | #endif | |
6ad14574 | 580 | switch (err) { |
bc25525a AJ |
581 | case NTLM_ERR_NONE: |
582 | break; | |
26ac0430 | 583 | case NTLM_BAD_NTGROUP: |
6ad14574 | 584 | SEND_ERR("message=\"Incorrect Group Membership\""); |
26ac0430 AJ |
585 | return 1; |
586 | case NTLM_BAD_REQUEST: | |
6ad14574 | 587 | SEND_ERR("message=\"Incorrect Request Format\""); |
26ac0430 AJ |
588 | return 1; |
589 | case NTLM_SSPI_ERROR: | |
590 | FormatMessage( | |
591 | FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
592 | FORMAT_MESSAGE_FROM_SYSTEM | | |
593 | FORMAT_MESSAGE_IGNORE_INSERTS, | |
594 | NULL, | |
595 | GetLastError(), | |
596 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language | |
597 | (LPTSTR) &ErrorMessage, | |
598 | 0, | |
599 | NULL); | |
6e785d85 | 600 | if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n') |
601 | ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; | |
602 | if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r') | |
603 | ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; | |
6ad14574 | 604 | SEND_ERR(ErrorMessage); // TODO update to new syntax |
6e785d85 | 605 | LocalFree(ErrorMessage); |
26ac0430 AJ |
606 | return 1; |
607 | default: | |
6ad14574 | 608 | SEND_ERR("message=\"Unknown Error\""); |
26ac0430 AJ |
609 | return 1; |
610 | } | |
611 | } | |
bc25525a | 612 | /* let's lowercase them for our convenience */ |
6ad14574 AJ |
613 | lc(domain); |
614 | lc(user); | |
615 | fprintf(stdout, "OK user=\"%s\\%s\"", domain, user); | |
26ac0430 | 616 | return 1; |
26d714be | 617 | } |
26ac0430 | 618 | default: |
6ad14574 | 619 | helperfail("message=\"unknown authentication packet type\""); |
26ac0430 AJ |
620 | return 1; |
621 | } | |
622 | return 1; | |
f53969cc | 623 | } else { /* not an auth-request */ |
6ad14574 | 624 | helperfail("message=\"illegal request received\""); |
26ac0430 AJ |
625 | fprintf(stderr, "Illegal request received: '%s'\n", buf); |
626 | return 1; | |
6e785d85 | 627 | } |
6ad14574 | 628 | helperfail("message=\"detected protocol error\""); |
6e785d85 | 629 | return 1; |
26ac0430 | 630 | /********* END ********/ |
6e785d85 | 631 | } |
632 | ||
633 | int | |
634 | main(int argc, char *argv[]) | |
635 | { | |
636 | my_program_name = argv[0]; | |
637 | ||
638 | process_options(argc, argv); | |
639 | ||
a20277e1 | 640 | debug("%s " VERSION " " SQUID_BUILD_INFO " starting up...\n", my_program_name); |
26ac0430 | 641 | |
6e785d85 | 642 | if (LoadSecurityDll(SSP_NTLM, NTLM_PACKAGE_NAME) == NULL) { |
26ac0430 AJ |
643 | fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n"); |
644 | exit(1); | |
6e785d85 | 645 | } |
646 | debug("SSPI initialized OK\n"); | |
647 | ||
648 | atexit(UnloadSecurityDll); | |
649 | ||
650 | /* initialize FDescs */ | |
651 | setbuf(stdout, NULL); | |
652 | setbuf(stderr, NULL); | |
653 | ||
654 | while (manage_request()) { | |
26ac0430 | 655 | /* everything is done within manage_request */ |
6e785d85 | 656 | } |
657 | exit(0); | |
658 | } | |
f53969cc | 659 |