]>
Commit | Line | Data |
---|---|---|
736a9a4d | 1 | /* |
9af66127 | 2 | * mswin_check_lm_group: lookup group membership in a Windows NT/2000 domain |
736a9a4d | 3 | * |
4 | * (C)2002,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 | * In part based on check_group by Rodrigo Albani de Campos. | |
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 | * | |
33 | * Version 1.22 | |
34 | * 08-07-2005 Guido Serassio | |
35 | * Added -P option for force usage of PDCs for group validation. | |
36 | * Added support for '/' char as domain separator. | |
26ac0430 | 37 | * Fixed Bugzilla #1336. |
736a9a4d | 38 | * Version 1.21 |
39 | * 23-04-2005 Guido Serassio | |
40 | * Added -D option for specify default user's domain. | |
41 | * Version 1.20.1 | |
42 | * 15-08-2004 Guido Serassio | |
43 | * Helper protocol changed to use URL escaped strings in Squid-3.0 | |
44 | * (Original work of Henrik Nordstrom) | |
45 | * Version 1.20 | |
46 | * 13-06-2004 Guido Serassio | |
47 | * Added support for running on a Domain Controller. | |
48 | * Version 1.10 | |
49 | * 01-05-2003 Guido Serassio | |
50 | * Added option for case insensitive group name comparation. | |
51 | * More debug info. | |
52 | * Updated documentation. | |
53 | * Segfault bug fix (Bugzilla #574) | |
54 | * Version 1.0 | |
55 | * 24-06-2002 Guido Serassio | |
56 | * Using the main function from check_group and sections | |
57 | * from wbinfo wrote win32_group | |
58 | * | |
59 | * This is a helper for the external ACL interface for Squid Cache | |
26ac0430 | 60 | * |
736a9a4d | 61 | * It reads from the standard input the domain username and a list of |
62 | * groups and tries to match it against the groups membership of the | |
63 | * specified username. | |
64 | * | |
65 | * Returns `OK' if the user belongs to a group or `ERR' otherwise, as | |
66 | * described on http://devel.squid-cache.org/external_acl/config.html | |
67 | * | |
68 | */ | |
69 | ||
f7f3304a | 70 | #include "squid.h" |
c152a447 | 71 | #include "helpers/defines.h" |
16cca888 AJ |
72 | #include "rfc1738.h" |
73 | #include "util.h" | |
c152a447 | 74 | |
be266cb2 | 75 | #if _SQUID_CYGWIN_ |
736a9a4d | 76 | #include <wchar.h> |
45648be2 | 77 | int _wcsicmp(const wchar_t *, const wchar_t *); |
736a9a4d | 78 | #endif |
c152a447 | 79 | |
074d6a40 AJ |
80 | #undef assert |
81 | #include <cassert> | |
82 | #include <cctype> | |
83 | #include <cstring> | |
736a9a4d | 84 | #if HAVE_GETOPT_H |
85 | #include <getopt.h> | |
86 | #endif | |
736a9a4d | 87 | #include <windows.h> |
88 | #include <lm.h> | |
89 | #include <ntsecapi.h> | |
90 | ||
736a9a4d | 91 | int use_global = 0; |
92 | int use_PDC_only = 0; | |
385df818 | 93 | const char *program_name; |
736a9a4d | 94 | pid_t mypid; |
45648be2 | 95 | char *machinedomain; |
736a9a4d | 96 | int use_case_insensitive_compare = 0; |
45648be2 | 97 | char *DefaultDomain = NULL; |
736a9a4d | 98 | const char NTV_VALID_DOMAIN_SEPARATOR[] = "\\/"; |
99 | ||
45648be2 | 100 | char * |
101 | AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr) | |
736a9a4d | 102 | { |
103 | size_t len; | |
45648be2 | 104 | static char *target; |
736a9a4d | 105 | |
45648be2 | 106 | len = LsaStr.Length / sizeof(WCHAR) + 1; |
736a9a4d | 107 | |
108 | /* allocate buffer for str + null termination */ | |
109 | safe_free(target); | |
45648be2 | 110 | target = (char *) xmalloc(len); |
736a9a4d | 111 | if (target == NULL) |
26ac0430 | 112 | return NULL; |
736a9a4d | 113 | |
114 | /* copy unicode buffer */ | |
45648be2 | 115 | WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL); |
736a9a4d | 116 | |
117 | /* add null termination */ | |
45648be2 | 118 | target[len - 1] = '\0'; |
736a9a4d | 119 | return target; |
120 | } | |
121 | ||
45648be2 | 122 | char * |
123 | GetDomainName(void) | |
736a9a4d | 124 | { |
125 | LSA_HANDLE PolicyHandle; | |
126 | LSA_OBJECT_ATTRIBUTES ObjectAttributes; | |
127 | NTSTATUS status; | |
128 | PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo; | |
129 | PWKSTA_INFO_100 pwkiWorkstationInfo; | |
130 | DWORD netret; | |
45648be2 | 131 | char *DomainName = NULL; |
736a9a4d | 132 | |
26ac0430 | 133 | /* |
736a9a4d | 134 | * Always initialize the object attributes to all zeroes. |
45648be2 | 135 | */ |
736a9a4d | 136 | memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes)); |
137 | ||
26ac0430 | 138 | /* |
736a9a4d | 139 | * You need the local workstation name. Use NetWkstaGetInfo at level |
140 | * 100 to retrieve a WKSTA_INFO_100 structure. | |
26ac0430 | 141 | * |
736a9a4d | 142 | * The wki100_computername field contains a pointer to a UNICODE |
143 | * string containing the local computer name. | |
45648be2 | 144 | */ |
145 | netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *) & pwkiWorkstationInfo); | |
736a9a4d | 146 | if (netret == NERR_Success) { |
26ac0430 AJ |
147 | /* |
148 | * We have the workstation name in: | |
149 | * pwkiWorkstationInfo->wki100_computername | |
150 | * | |
151 | * Next, open the policy object for the local system using | |
152 | * the LsaOpenPolicy function. | |
153 | */ | |
154 | status = LsaOpenPolicy( | |
155 | NULL, | |
156 | &ObjectAttributes, | |
157 | GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, | |
158 | &PolicyHandle | |
159 | ); | |
160 | ||
161 | /* | |
162 | * Error checking. | |
163 | */ | |
164 | if (status) { | |
165 | debug("OpenPolicy Error: %ld\n", status); | |
166 | } else { | |
167 | ||
168 | /* | |
169 | * You have a handle to the policy object. Now, get the | |
170 | * domain information using LsaQueryInformationPolicy. | |
171 | */ | |
172 | status = LsaQueryInformationPolicy(PolicyHandle, | |
173 | PolicyPrimaryDomainInformation, | |
174 | (PVOID *) & ppdiDomainInfo); | |
175 | if (status) { | |
176 | debug("LsaQueryInformationPolicy Error: %ld\n", status); | |
177 | } else { | |
178 | ||
179 | /* Get name in useable format */ | |
180 | DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name); | |
181 | ||
182 | /* | |
183 | * Check the Sid pointer, if it is null, the | |
184 | * workstation is either a stand-alone computer | |
185 | * or a member of a workgroup. | |
186 | */ | |
187 | if (ppdiDomainInfo->Sid) { | |
188 | ||
189 | /* | |
190 | * Member of a domain. Display it in debug mode. | |
191 | */ | |
192 | debug("Member of Domain %s\n", DomainName); | |
193 | } else { | |
194 | DomainName = NULL; | |
195 | } | |
196 | } | |
197 | } | |
198 | ||
199 | /* | |
200 | * Clean up all the memory buffers created by the LSA and | |
201 | * Net* APIs. | |
202 | */ | |
203 | NetApiBufferFree(pwkiWorkstationInfo); | |
204 | LsaFreeMemory((LPVOID) ppdiDomainInfo); | |
45648be2 | 205 | } else |
26ac0430 | 206 | debug("NetWkstaGetInfo Error: %ld\n", netret); |
736a9a4d | 207 | return DomainName; |
208 | } | |
209 | ||
210 | /* returns 0 on match, -1 if no match */ | |
26ac0430 | 211 | static int |
45648be2 | 212 | wcstrcmparray(const wchar_t * str, const char **array) |
736a9a4d | 213 | { |
45648be2 | 214 | WCHAR wszGroup[GNLEN + 1]; // Unicode Group |
736a9a4d | 215 | |
216 | while (*array) { | |
26ac0430 AJ |
217 | MultiByteToWideChar(CP_ACP, 0, *array, |
218 | strlen(*array) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0])); | |
219 | debug("Windows group: %S, Squid group: %S\n", str, wszGroup); | |
220 | if ((use_case_insensitive_compare ? _wcsicmp(str, wszGroup) : wcscmp(str, wszGroup)) == 0) | |
221 | return 0; | |
755494da | 222 | ++array; |
736a9a4d | 223 | } |
224 | return -1; | |
225 | } | |
226 | ||
227 | /* returns 1 on success, 0 on failure */ | |
228 | int | |
229 | Valid_Local_Groups(char *UserName, const char **Groups) | |
230 | { | |
231 | int result = 0; | |
45648be2 | 232 | char *Domain_Separator; |
233 | WCHAR wszUserName[UNLEN + 1]; // Unicode user name | |
736a9a4d | 234 | |
235 | LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; | |
236 | LPLOCALGROUP_USERS_INFO_0 pTmpBuf; | |
237 | DWORD dwLevel = 0; | |
238 | DWORD dwFlags = LG_INCLUDE_INDIRECT; | |
239 | DWORD dwPrefMaxLen = -1; | |
240 | DWORD dwEntriesRead = 0; | |
241 | DWORD dwTotalEntries = 0; | |
242 | NET_API_STATUS nStatus; | |
243 | DWORD i; | |
244 | DWORD dwTotalCount = 0; | |
245 | ||
246 | if ((Domain_Separator = strchr(UserName, '/')) != NULL) | |
26ac0430 | 247 | *Domain_Separator = '\\'; |
45648be2 | 248 | |
736a9a4d | 249 | debug("Valid_Local_Groups: checking group membership of '%s'.\n", UserName); |
45648be2 | 250 | |
26ac0430 | 251 | /* Convert ANSI User Name and Group to Unicode */ |
736a9a4d | 252 | |
253 | MultiByteToWideChar(CP_ACP, 0, UserName, | |
26ac0430 | 254 | strlen(UserName) + 1, wszUserName, sizeof(wszUserName) / sizeof(wszUserName[0])); |
736a9a4d | 255 | |
256 | /* | |
26ac0430 | 257 | * Call the NetUserGetLocalGroups function |
45648be2 | 258 | * specifying information level 0. |
26ac0430 AJ |
259 | * |
260 | * The LG_INCLUDE_INDIRECT flag specifies that the | |
261 | * function should also return the names of the local | |
45648be2 | 262 | * groups in which the user is indirectly a member. |
263 | */ | |
736a9a4d | 264 | nStatus = NetUserGetLocalGroups( |
26ac0430 AJ |
265 | NULL, |
266 | wszUserName, | |
267 | dwLevel, | |
268 | dwFlags, | |
269 | (LPBYTE *) & pBuf, | |
270 | dwPrefMaxLen, | |
271 | &dwEntriesRead, | |
272 | &dwTotalEntries); | |
45648be2 | 273 | /* |
274 | * If the call succeeds, | |
275 | */ | |
736a9a4d | 276 | if (nStatus == NERR_Success) { |
26ac0430 | 277 | if ((pTmpBuf = pBuf) != NULL) { |
a2f5277a | 278 | for (i = 0; i < dwEntriesRead; ++i) { |
26ac0430 AJ |
279 | assert(pTmpBuf != NULL); |
280 | if (pTmpBuf == NULL) { | |
281 | result = 0; | |
282 | break; | |
283 | } | |
284 | if (wcstrcmparray(pTmpBuf->lgrui0_name, Groups) == 0) { | |
285 | result = 1; | |
286 | break; | |
287 | } | |
755494da FC |
288 | ++pTmpBuf; |
289 | ++dwTotalCount; | |
26ac0430 AJ |
290 | } |
291 | } | |
736a9a4d | 292 | } else |
26ac0430 AJ |
293 | result = 0; |
294 | /* | |
295 | * Free the allocated memory. | |
296 | */ | |
736a9a4d | 297 | if (pBuf != NULL) |
26ac0430 | 298 | NetApiBufferFree(pBuf); |
736a9a4d | 299 | return result; |
300 | } | |
301 | ||
736a9a4d | 302 | /* returns 1 on success, 0 on failure */ |
303 | int | |
304 | Valid_Global_Groups(char *UserName, const char **Groups) | |
305 | { | |
306 | int result = 0; | |
45648be2 | 307 | WCHAR wszUserName[UNLEN + 1]; // Unicode user name |
736a9a4d | 308 | |
45648be2 | 309 | WCHAR wszLocalDomain[DNLEN + 1]; // Unicode Local Domain |
310 | ||
311 | WCHAR wszUserDomain[DNLEN + 1]; // Unicode User Domain | |
312 | ||
313 | char NTDomain[DNLEN + UNLEN + 2]; | |
736a9a4d | 314 | char *domain_qualify; |
45648be2 | 315 | char User[UNLEN + 1]; |
736a9a4d | 316 | size_t j; |
317 | ||
318 | LPWSTR LclDCptr = NULL; | |
319 | LPWSTR UsrDCptr = NULL; | |
320 | LPGROUP_USERS_INFO_0 pUsrBuf = NULL; | |
321 | LPGROUP_USERS_INFO_0 pTmpBuf; | |
322 | LPSERVER_INFO_101 pSrvBuf = NULL; | |
323 | DWORD dwLevel = 0; | |
324 | DWORD dwPrefMaxLen = -1; | |
325 | DWORD dwEntriesRead = 0; | |
326 | DWORD dwTotalEntries = 0; | |
327 | NET_API_STATUS nStatus; | |
328 | DWORD i; | |
329 | DWORD dwTotalCount = 0; | |
330 | ||
331 | strncpy(NTDomain, UserName, sizeof(NTDomain)); | |
332 | ||
a2f5277a | 333 | for (j = 0; j < strlen(NTV_VALID_DOMAIN_SEPARATOR); ++j) { |
26ac0430 AJ |
334 | if ((domain_qualify = strchr(NTDomain, NTV_VALID_DOMAIN_SEPARATOR[j])) != NULL) |
335 | break; | |
736a9a4d | 336 | } |
337 | if (domain_qualify == NULL) { | |
26ac0430 AJ |
338 | strcpy(User, NTDomain); |
339 | strcpy(NTDomain, DefaultDomain); | |
736a9a4d | 340 | } else { |
26ac0430 AJ |
341 | strcpy(User, domain_qualify + 1); |
342 | domain_qualify[0] = '\0'; | |
343 | strlwr(NTDomain); | |
736a9a4d | 344 | } |
345 | ||
346 | debug("Valid_Global_Groups: checking group membership of '%s\\%s'.\n", NTDomain, User); | |
347 | ||
348 | /* Convert ANSI User Name and Group to Unicode */ | |
349 | ||
350 | MultiByteToWideChar(CP_ACP, 0, User, | |
26ac0430 AJ |
351 | strlen(User) + 1, wszUserName, |
352 | sizeof(wszUserName) / sizeof(wszUserName[0])); | |
736a9a4d | 353 | MultiByteToWideChar(CP_ACP, 0, machinedomain, |
26ac0430 | 354 | strlen(machinedomain) + 1, wszLocalDomain, sizeof(wszLocalDomain) / sizeof(wszLocalDomain[0])); |
736a9a4d | 355 | |
26ac0430 | 356 | /* Call the NetServerGetInfo function for local computer, specifying level 101. */ |
736a9a4d | 357 | dwLevel = 101; |
45648be2 | 358 | nStatus = NetServerGetInfo(NULL, dwLevel, (LPBYTE *) & pSrvBuf); |
359 | ||
360 | if (nStatus == NERR_Success) { | |
26ac0430 AJ |
361 | /* Check if we are running on a Domain Controller */ |
362 | if ((pSrvBuf->sv101_type & SV_TYPE_DOMAIN_CTRL) || | |
363 | (pSrvBuf->sv101_type & SV_TYPE_DOMAIN_BAKCTRL)) { | |
364 | LclDCptr = NULL; | |
365 | debug("Running on a DC.\n"); | |
366 | } else | |
367 | nStatus = (use_PDC_only ? NetGetDCName(NULL, wszLocalDomain, (LPBYTE *) & LclDCptr) : NetGetAnyDCName(NULL, wszLocalDomain, (LPBYTE *) & LclDCptr)); | |
736a9a4d | 368 | } else { |
c152a447 | 369 | fprintf(stderr, "%s: ERROR: NetServerGetInfo() failed.'\n", program_name); |
26ac0430 AJ |
370 | if (pSrvBuf != NULL) |
371 | NetApiBufferFree(pSrvBuf); | |
372 | return result; | |
736a9a4d | 373 | } |
374 | ||
375 | if (nStatus == NERR_Success) { | |
26ac0430 AJ |
376 | debug("Using '%S' as DC for '%S' local domain.\n", LclDCptr, wszLocalDomain); |
377 | ||
378 | if (strcmp(NTDomain, machinedomain) != 0) { | |
379 | MultiByteToWideChar(CP_ACP, 0, NTDomain, | |
380 | strlen(NTDomain) + 1, wszUserDomain, sizeof(wszUserDomain) / sizeof(wszUserDomain[0])); | |
381 | nStatus = (use_PDC_only ? NetGetDCName(LclDCptr, wszUserDomain, (LPBYTE *) & UsrDCptr) : NetGetAnyDCName(LclDCptr, wszUserDomain, (LPBYTE *) & UsrDCptr)); | |
382 | if (nStatus != NERR_Success) { | |
c152a447 | 383 | fprintf(stderr, "%s: ERROR: Can't find DC for user's domain '%s'\n", program_name, NTDomain); |
26ac0430 AJ |
384 | if (pSrvBuf != NULL) |
385 | NetApiBufferFree(pSrvBuf); | |
386 | if (LclDCptr != NULL) | |
387 | NetApiBufferFree((LPVOID) LclDCptr); | |
388 | if (UsrDCptr != NULL) | |
389 | NetApiBufferFree((LPVOID) UsrDCptr); | |
390 | return result; | |
391 | } | |
392 | } else | |
393 | UsrDCptr = LclDCptr; | |
394 | ||
395 | debug("Using '%S' as DC for '%s' user's domain.\n", UsrDCptr, NTDomain); | |
396 | /* | |
397 | * Call the NetUserGetGroups function | |
398 | * specifying information level 0. | |
399 | */ | |
400 | dwLevel = 0; | |
401 | nStatus = NetUserGetGroups(UsrDCptr, | |
402 | wszUserName, | |
403 | dwLevel, | |
404 | (LPBYTE *) & pUsrBuf, | |
405 | dwPrefMaxLen, | |
406 | &dwEntriesRead, | |
407 | &dwTotalEntries); | |
408 | /* | |
409 | * If the call succeeds, | |
410 | */ | |
411 | if (nStatus == NERR_Success) { | |
412 | if ((pTmpBuf = pUsrBuf) != NULL) { | |
a2f5277a | 413 | for (i = 0; i < dwEntriesRead; ++i) { |
26ac0430 AJ |
414 | assert(pTmpBuf != NULL); |
415 | if (pTmpBuf == NULL) { | |
416 | result = 0; | |
417 | break; | |
418 | } | |
419 | if (wcstrcmparray(pTmpBuf->grui0_name, Groups) == 0) { | |
420 | result = 1; | |
421 | break; | |
422 | } | |
755494da FC |
423 | ++pTmpBuf; |
424 | ++dwTotalCount; | |
26ac0430 AJ |
425 | } |
426 | } | |
427 | } else { | |
428 | result = 0; | |
c152a447 | 429 | fprintf(stderr, "%s: ERROR: NetUserGetGroups() failed.'\n", program_name); |
26ac0430 | 430 | } |
736a9a4d | 431 | } else { |
c152a447 | 432 | fprintf(stderr, "%s: ERROR: Can't find DC for local domain '%s'\n", program_name, machinedomain); |
736a9a4d | 433 | } |
434 | /* | |
435 | * Free the allocated memory. | |
436 | */ | |
437 | if (pSrvBuf != NULL) | |
26ac0430 | 438 | NetApiBufferFree(pSrvBuf); |
736a9a4d | 439 | if (pUsrBuf != NULL) |
26ac0430 | 440 | NetApiBufferFree(pUsrBuf); |
736a9a4d | 441 | if ((UsrDCptr != NULL) && (UsrDCptr != LclDCptr)) |
26ac0430 | 442 | NetApiBufferFree((LPVOID) UsrDCptr); |
736a9a4d | 443 | if (LclDCptr != NULL) |
26ac0430 | 444 | NetApiBufferFree((LPVOID) LclDCptr); |
736a9a4d | 445 | return result; |
446 | } | |
447 | ||
448 | static void | |
c152a447 | 449 | usage(const char *program) |
736a9a4d | 450 | { |
45648be2 | 451 | fprintf(stderr, "Usage: %s [-D domain][-G][-P][-c][-d][-h]\n" |
26ac0430 AJ |
452 | " -D default user Domain\n" |
453 | " -G enable Domain Global group mode\n" | |
454 | " -P use ONLY PDCs for group validation\n" | |
455 | " -c use case insensitive compare\n" | |
456 | " -d enable debugging\n" | |
457 | " -h this message\n", | |
458 | program); | |
736a9a4d | 459 | } |
460 | ||
461 | void | |
462 | process_options(int argc, char *argv[]) | |
463 | { | |
464 | int opt; | |
465 | ||
466 | opterr = 0; | |
467 | while (-1 != (opt = getopt(argc, argv, "D:GPcdh"))) { | |
26ac0430 AJ |
468 | switch (opt) { |
469 | case 'D': | |
470 | DefaultDomain = xstrndup(optarg, DNLEN + 1); | |
471 | strlwr(DefaultDomain); | |
472 | break; | |
473 | case 'G': | |
474 | use_global = 1; | |
475 | break; | |
476 | case 'P': | |
477 | use_PDC_only = 1; | |
478 | break; | |
479 | case 'c': | |
480 | use_case_insensitive_compare = 1; | |
481 | break; | |
482 | case 'd': | |
483 | debug_enabled = 1; | |
484 | break; | |
485 | case 'h': | |
486 | usage(argv[0]); | |
487 | exit(0); | |
488 | case '?': | |
489 | opt = optopt; | |
490 | /* fall thru to default */ | |
491 | default: | |
c152a447 | 492 | fprintf(stderr, "%s: FATAL: Unknown option: -%c. Exiting\n", program_name, opt); |
26ac0430 AJ |
493 | usage(argv[0]); |
494 | exit(1); | |
495 | break; /* not reached */ | |
496 | } | |
736a9a4d | 497 | } |
498 | return; | |
499 | } | |
500 | ||
736a9a4d | 501 | int |
45648be2 | 502 | main(int argc, char *argv[]) |
736a9a4d | 503 | { |
504 | char *p; | |
c152a447 | 505 | char buf[HELPER_INPUT_BUFFER]; |
736a9a4d | 506 | char *username; |
507 | char *group; | |
736a9a4d | 508 | const char *groups[512]; |
509 | int n; | |
510 | ||
45648be2 | 511 | if (argc > 0) { /* should always be true */ |
c152a447 AJ |
512 | program_name = strrchr(argv[0], '/'); |
513 | if (program_name == NULL) | |
514 | program_name = argv[0]; | |
736a9a4d | 515 | } else { |
c152a447 | 516 | program_name = "(unknown)"; |
736a9a4d | 517 | } |
45648be2 | 518 | mypid = getpid(); |
736a9a4d | 519 | |
520 | setbuf(stdout, NULL); | |
521 | setbuf(stderr, NULL); | |
522 | ||
523 | /* Check Command Line */ | |
524 | process_options(argc, argv); | |
525 | ||
526 | if (use_global) { | |
26ac0430 | 527 | if ((machinedomain = GetDomainName()) == NULL) { |
c152a447 | 528 | fprintf(stderr, "%s: FATAL: Can't read machine domain\n", program_name); |
26ac0430 AJ |
529 | exit(1); |
530 | } | |
531 | strlwr(machinedomain); | |
532 | if (!DefaultDomain) | |
533 | DefaultDomain = xstrdup(machinedomain); | |
736a9a4d | 534 | } |
736a9a4d | 535 | debug("External ACL win32 group helper build " __DATE__ ", " __TIME__ |
26ac0430 | 536 | " starting up...\n"); |
385df818 | 537 | if (use_global) { |
26ac0430 | 538 | debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain); |
385df818 AJ |
539 | } |
540 | if (use_case_insensitive_compare) { | |
26ac0430 | 541 | debug("Warning: running in case insensitive mode !!!\n"); |
385df818 AJ |
542 | } |
543 | if (use_PDC_only) { | |
26ac0430 | 544 | debug("Warning: using only PDCs for group validation !!!\n"); |
385df818 | 545 | } |
736a9a4d | 546 | |
547 | /* Main Loop */ | |
c152a447 | 548 | while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) { |
26ac0430 AJ |
549 | if (NULL == strchr(buf, '\n')) { |
550 | /* too large message received.. skip and deny */ | |
c152a447 AJ |
551 | debug("%s: ERROR: Too large: %s\n", argv[0], buf); |
552 | while (fgets(buf, HELPER_INPUT_BUFFER, stdin)) { | |
553 | debug("%s: ERROR: Too large..: %s\n", argv[0], buf); | |
26ac0430 AJ |
554 | if (strchr(buf, '\n') != NULL) |
555 | break; | |
556 | } | |
c152a447 AJ |
557 | SEND_ERR("Input Too Long."); |
558 | continue; | |
26ac0430 AJ |
559 | } |
560 | if ((p = strchr(buf, '\n')) != NULL) | |
561 | *p = '\0'; /* strip \n */ | |
562 | if ((p = strchr(buf, '\r')) != NULL) | |
563 | *p = '\0'; /* strip \r */ | |
564 | ||
565 | debug("Got '%s' from Squid (length: %d).\n", buf, strlen(buf)); | |
566 | ||
567 | if (buf[0] == '\0') { | |
c152a447 AJ |
568 | SEND_ERR("Invalid Request."); |
569 | continue; | |
26ac0430 AJ |
570 | } |
571 | username = strtok(buf, " "); | |
a2f5277a | 572 | for (n = 0; (group = strtok(NULL, " ")) != NULL; ++n) { |
26ac0430 AJ |
573 | rfc1738_unescape(group); |
574 | groups[n] = group; | |
575 | } | |
576 | groups[n] = NULL; | |
577 | ||
578 | if (NULL == username) { | |
c152a447 AJ |
579 | SEND_ERR("Invalid Request. No Username."); |
580 | continue; | |
26ac0430 AJ |
581 | } |
582 | rfc1738_unescape(username); | |
583 | ||
584 | if ((use_global ? Valid_Global_Groups(username, groups) : Valid_Local_Groups(username, groups))) { | |
c152a447 | 585 | SEND_OK(""); |
26ac0430 | 586 | } else { |
c152a447 | 587 | SEND_ERR(""); |
26ac0430 | 588 | } |
736a9a4d | 589 | } |
590 | return 0; | |
591 | } |