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