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