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