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