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