2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
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.
10 * ext_ad_group_acl: lookup group membership in a Windows
11 * Active Directory domain
13 * (C)2008-2009 Guido Serassio - Acme Consulting S.r.l.
16 * Guido Serassio <guido.serassio@acmeconsulting.it>
17 * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
19 * With contributions from others mentioned in the change history section
22 * Based on mswin_check_lm_group by Guido Serassio.
24 * Dependencies: Windows 2000 SP4 and later.
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 2 of the License, or
29 * (at your option) any later version.
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public License
37 * along with this program; if not, write to the Free Software
38 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
43 * 20-09-2009 Guido Serassio
44 * Added explicit Global Catalog query
47 * 20-07-2009 Guido Serassio
48 * Global groups support rewritten, now is based on ADSI.
50 * - support for Domain Local, Domain Global ad Universal
52 * - full group nesting support
54 * 02-05-2008 Guido Serassio
55 * First release, based on mswin_check_lm_group.
57 * This is a helper for the external ACL interface for Squid Cache
59 * It reads from the standard input the domain username and a list of
60 * groups and tries to match it against the groups membership of the
63 * Returns `OK' if the user belongs to a group or `ERR' otherwise, as
64 * described on http://devel.squid-cache.org/external_acl/config.html
69 #include "helpers/defines.h"
70 #include "include/util.h"
74 int _wcsicmp(const wchar_t *, const wchar_t *);
104 int use_case_insensitive_compare
= 0;
105 char *DefaultDomain
= NULL
;
106 const char NTV_VALID_DOMAIN_SEPARATOR
[] = "\\/";
107 int numberofgroups
= 0;
108 int WIN32_COM_initialized
= 0;
109 char *WIN32_ErrorMessage
= NULL
;
110 wchar_t **User_Groups
;
111 int User_Groups_Count
= 0;
113 wchar_t *My_NameTranslate(wchar_t *, int, int);
114 char *Get_WIN32_ErrorMessage(HRESULT
);
119 if (WIN32_COM_initialized
== 1)
124 GetLPBYTEtoOctetString(VARIANT
* pVar
, LPBYTE
* ppByte
)
128 long lLBound
, lUBound
, cElements
;
130 if ((!pVar
) || (!ppByte
))
132 if ((pVar
->n1
.n2
.vt
) != (VT_UI1
| VT_ARRAY
))
135 hr
= SafeArrayGetLBound(V_ARRAY(pVar
), 1, &lLBound
);
136 hr
= SafeArrayGetUBound(V_ARRAY(pVar
), 1, &lUBound
);
138 cElements
= lUBound
- lLBound
+ 1;
139 hr
= SafeArrayAccessData(V_ARRAY(pVar
), &pArray
);
141 LPBYTE pTemp
= (LPBYTE
) pArray
;
142 *ppByte
= (LPBYTE
) CoTaskMemAlloc(cElements
);
144 memcpy(*ppByte
, pTemp
, cElements
);
148 SafeArrayUnaccessData(V_ARRAY(pVar
));
154 Get_primaryGroup(IADs
* pUser
)
158 unsigned User_primaryGroupID
;
159 char tmpSID
[SECURITY_MAX_SID_SIZE
* 2];
160 wchar_t *wc
= NULL
, *result
= NULL
;
165 /* Get the primaryGroupID property */
166 hr
= pUser
->lpVtbl
->Get(pUser
, L
"primaryGroupID", &var
);
168 User_primaryGroupID
= var
.n1
.n2
.n3
.uintVal
;
170 debug("Get_primaryGroup: cannot get primaryGroupID, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
176 /*Get the objectSid property */
177 hr
= pUser
->lpVtbl
->Get(pUser
, L
"objectSid", &var
);
182 hr
= GetLPBYTEtoOctetString(&var
, &pByte
);
184 pObjectSID
= (PSID
) pByte
;
186 /* Convert SID to string. */
187 ConvertSidToStringSid(pObjectSID
, &szSID
);
188 CoTaskMemFree(pByte
);
190 *(strrchr(szSID
, '-') + 1) = '\0';
191 snprintf(tmpSID
, sizeof(tmpSID
)-1, "%s%u", szSID
, User_primaryGroupID
);
193 wcsize
= MultiByteToWideChar(CP_ACP
, 0, tmpSID
, -1, wc
, 0);
194 wc
= (wchar_t *) xmalloc(wcsize
* sizeof(wchar_t));
195 MultiByteToWideChar(CP_ACP
, 0, tmpSID
, -1, wc
, wcsize
);
198 result
= My_NameTranslate(wc
, ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME
, ADS_NAME_TYPE_1779
);
202 debug("Get_primaryGroup: cannot get DN for %s.\n", tmpSID
);
204 debug("Get_primaryGroup: Primary group DN: %S.\n", result
);
206 debug("Get_primaryGroup: cannot get objectSid, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
212 Get_WIN32_ErrorMessage(HRESULT hr
)
214 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
215 FORMAT_MESSAGE_IGNORE_INSERTS
,
218 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
219 (LPTSTR
) & WIN32_ErrorMessage
,
222 return WIN32_ErrorMessage
;
226 My_NameTranslate(wchar_t * name
, int in_format
, int out_format
)
228 IADsNameTranslate
*pNto
;
233 if (WIN32_COM_initialized
== 0) {
234 hr
= CoInitialize(NULL
);
236 debug("My_NameTranslate: cannot initialize COM interface, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
237 /* This is a fatal error */
240 WIN32_COM_initialized
= 1;
242 hr
= CoCreateInstance(&CLSID_NameTranslate
,
244 CLSCTX_INPROC_SERVER
,
245 &IID_IADsNameTranslate
,
248 debug("My_NameTranslate: cannot create COM instance, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
249 /* This is a fatal error */
252 hr
= pNto
->lpVtbl
->Init(pNto
, ADS_NAME_INITTYPE_GC
, L
"");
254 debug("My_NameTranslate: cannot initialise NameTranslate API, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
255 pNto
->lpVtbl
->Release(pNto
);
256 /* This is a fatal error */
259 hr
= pNto
->lpVtbl
->Set(pNto
, in_format
, name
);
261 debug("My_NameTranslate: cannot set translate of %S, ERROR: %s\n", name
, Get_WIN32_ErrorMessage(hr
));
262 pNto
->lpVtbl
->Release(pNto
);
265 hr
= pNto
->lpVtbl
->Get(pNto
, out_format
, &bstr
);
267 debug("My_NameTranslate: cannot get translate of %S, ERROR: %s\n", name
, Get_WIN32_ErrorMessage(hr
));
268 pNto
->lpVtbl
->Release(pNto
);
271 debug("My_NameTranslate: %S translated to %S\n", name
, bstr
);
273 wc
= (wchar_t *) xmalloc((wcslen(bstr
) + 1) * sizeof(wchar_t));
276 pNto
->lpVtbl
->Release(pNto
);
281 GetLDAPPath(wchar_t * Base_DN
, int query_mode
)
285 wc
= (wchar_t *) xmalloc((wcslen(Base_DN
) + 8) * sizeof(wchar_t));
287 if (query_mode
== LDAP_MODE
)
288 wcscpy(wc
, L
"LDAP://");
290 wcscpy(wc
, L
"GC://");
299 static char *DomainName
= NULL
;
300 PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDSRoleInfo
;
303 if ((netret
= DsRoleGetPrimaryDomainInformation(NULL
, DsRolePrimaryDomainInfoBasic
, (PBYTE
*) & pDSRoleInfo
) == ERROR_SUCCESS
)) {
305 * Check the machine role.
308 if ((pDSRoleInfo
->MachineRole
== DsRole_RoleMemberWorkstation
) ||
309 (pDSRoleInfo
->MachineRole
== DsRole_RoleMemberServer
) ||
310 (pDSRoleInfo
->MachineRole
== DsRole_RoleBackupDomainController
) ||
311 (pDSRoleInfo
->MachineRole
== DsRole_RolePrimaryDomainController
)) {
313 size_t len
= wcslen(pDSRoleInfo
->DomainNameFlat
);
315 /* allocate buffer for str + null termination */
316 safe_free(DomainName
);
317 DomainName
= (char *) xmalloc(len
+ 1);
319 /* copy unicode buffer */
320 WideCharToMultiByte(CP_ACP
, 0, pDSRoleInfo
->DomainNameFlat
, -1, DomainName
, len
, NULL
, NULL
);
322 /* add null termination */
323 DomainName
[len
] = '\0';
326 * Member of a domain. Display it in debug mode.
328 debug("Member of Domain %s\n", DomainName
);
329 debug("Into forest %S\n", pDSRoleInfo
->DomainForestName
);
332 debug("Not a Domain member\n");
335 debug("GetDomainName: ERROR DsRoleGetPrimaryDomainInformation returned: %s\n", Get_WIN32_ErrorMessage(netret
));
338 * Free the allocated memory.
340 if (pDSRoleInfo
!= NULL
)
341 DsRoleFreeMemory(pDSRoleInfo
);
347 add_User_Group(wchar_t * Group
)
351 if (User_Groups_Count
== 0) {
352 User_Groups
= (wchar_t **) xmalloc(sizeof(wchar_t *));
358 if (wcscmp(Group
, *array
) == 0)
362 User_Groups
= (wchar_t **) xrealloc(User_Groups
, sizeof(wchar_t *) * (User_Groups_Count
+ 1));
363 User_Groups
[User_Groups_Count
] = NULL
;
364 User_Groups
[User_Groups_Count
- 1] = (wchar_t *) xmalloc((wcslen(Group
) + 1) * sizeof(wchar_t));
365 wcscpy(User_Groups
[User_Groups_Count
- 1], Group
);
371 /* returns 0 on match, -1 if no match */
373 wccmparray(const wchar_t * str
, const wchar_t ** array
)
376 debug("Windows group: %S, Squid group: %S\n", str
, *array
);
377 if (wcscmp(str
, *array
) == 0)
384 /* returns 0 on match, -1 if no match */
386 wcstrcmparray(const wchar_t * str
, const char **array
)
388 WCHAR wszGroup
[GNLEN
+ 1]; // Unicode Group
391 MultiByteToWideChar(CP_ACP
, 0, *array
,
392 strlen(*array
) + 1, wszGroup
, sizeof(wszGroup
) / sizeof(wszGroup
[0]));
393 debug("Windows group: %S, Squid group: %S\n", str
, wszGroup
);
394 if ((use_case_insensitive_compare
? _wcsicmp(str
, wszGroup
) : wcscmp(str
, wszGroup
)) == 0)
402 Recursive_Memberof(IADs
* pObj
)
409 hr
= pObj
->lpVtbl
->Get(pObj
, L
"memberOf", &var
);
411 if (VT_BSTR
== var
.n1
.n2
.vt
) {
412 if (add_User_Group(var
.n1
.n2
.n3
.bstrVal
)) {
416 Group_Path
= GetLDAPPath(var
.n1
.n2
.n3
.bstrVal
, GC_MODE
);
417 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
419 hr
= Recursive_Memberof(pGrp
);
420 pGrp
->lpVtbl
->Release(pGrp
);
421 safe_free(Group_Path
);
422 Group_Path
= GetLDAPPath(var
.n1
.n2
.n3
.bstrVal
, LDAP_MODE
);
423 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
425 hr
= Recursive_Memberof(pGrp
);
426 pGrp
->lpVtbl
->Release(pGrp
);
428 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
430 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
431 safe_free(Group_Path
);
434 if (SUCCEEDED(SafeArrayGetLBound(V_ARRAY(&var
), 1, &lBound
)) &&
435 SUCCEEDED(SafeArrayGetUBound(V_ARRAY(&var
), 1, &uBound
))) {
437 while (lBound
<= uBound
) {
438 hr
= SafeArrayGetElement(V_ARRAY(&var
), &lBound
, &elem
);
440 if (add_User_Group(elem
.n1
.n2
.n3
.bstrVal
)) {
444 Group_Path
= GetLDAPPath(elem
.n1
.n2
.n3
.bstrVal
, GC_MODE
);
445 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
447 hr
= Recursive_Memberof(pGrp
);
448 pGrp
->lpVtbl
->Release(pGrp
);
449 safe_free(Group_Path
);
450 Group_Path
= GetLDAPPath(elem
.n1
.n2
.n3
.bstrVal
, LDAP_MODE
);
451 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
453 hr
= Recursive_Memberof(pGrp
);
454 pGrp
->lpVtbl
->Release(pGrp
);
455 safe_free(Group_Path
);
457 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
459 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
460 safe_free(Group_Path
);
464 debug("Recursive_Memberof: ERROR SafeArrayGetElement failed: %s\n", Get_WIN32_ErrorMessage(hr
));
470 debug("Recursive_Memberof: ERROR SafeArrayGetxBound failed: %s\n", Get_WIN32_ErrorMessage(hr
));
474 if (hr
!= E_ADS_PROPERTY_NOT_FOUND
)
475 debug("Recursive_Memberof: ERROR getting memberof attribute: %s\n", Get_WIN32_ErrorMessage(hr
));
481 build_groups_DN_array(const char **array
, char *userdomain
)
485 int source_group_format
;
486 char Group
[GNLEN
+ 1];
488 wchar_t **wc_array
, **entry
;
490 entry
= wc_array
= (wchar_t **) xmalloc((numberofgroups
+ 1) * sizeof(wchar_t *));
493 if (strchr(*array
, '/') != NULL
) {
494 strncpy(Group
, *array
, GNLEN
);
495 source_group_format
= ADS_NAME_TYPE_CANONICAL
;
497 source_group_format
= ADS_NAME_TYPE_NT4
;
498 if (strchr(*array
, '\\') == NULL
) {
499 strcpy(Group
, userdomain
);
501 strncat(Group
, *array
, GNLEN
- sizeof(userdomain
) - 1);
503 strncpy(Group
, *array
, GNLEN
);
506 wcsize
= MultiByteToWideChar(CP_ACP
, 0, Group
, -1, wc
, 0);
507 wc
= (wchar_t *) xmalloc(wcsize
* sizeof(wchar_t));
508 MultiByteToWideChar(CP_ACP
, 0, Group
, -1, wc
, wcsize
);
509 *entry
= My_NameTranslate(wc
, source_group_format
, ADS_NAME_TYPE_1779
);
512 if (*entry
== NULL
) {
513 debug("build_groups_DN_array: cannot get DN for '%s'.\n", Group
);
522 /* returns 1 on success, 0 on failure */
524 Valid_Local_Groups(char *UserName
, const char **Groups
)
527 char *Domain_Separator
;
528 WCHAR wszUserName
[UNLEN
+ 1]; /* Unicode user name */
530 LPLOCALGROUP_USERS_INFO_0 pBuf
;
531 LPLOCALGROUP_USERS_INFO_0 pTmpBuf
;
533 DWORD dwFlags
= LG_INCLUDE_INDIRECT
;
534 DWORD dwPrefMaxLen
= -1;
535 DWORD dwEntriesRead
= 0;
536 DWORD dwTotalEntries
= 0;
537 NET_API_STATUS nStatus
;
539 DWORD dwTotalCount
= 0;
540 LPBYTE pBufTmp
= NULL
;
542 if ((Domain_Separator
= strchr(UserName
, '/')) != NULL
)
543 *Domain_Separator
= '\\';
545 debug("Valid_Local_Groups: checking group membership of '%s'.\n", UserName
);
547 /* Convert ANSI User Name and Group to Unicode */
549 MultiByteToWideChar(CP_ACP
, 0, UserName
,
550 strlen(UserName
) + 1, wszUserName
, sizeof(wszUserName
) / sizeof(wszUserName
[0]));
553 * Call the NetUserGetLocalGroups function
554 * specifying information level 0.
556 * The LG_INCLUDE_INDIRECT flag specifies that the
557 * function should also return the names of the local
558 * groups in which the user is indirectly a member.
560 nStatus
= NetUserGetLocalGroups(NULL
,
568 pBuf
= (LPLOCALGROUP_USERS_INFO_0
) pBufTmp
;
570 * If the call succeeds,
572 if (nStatus
== NERR_Success
) {
573 if ((pTmpBuf
= pBuf
) != NULL
) {
574 for (i
= 0; i
< dwEntriesRead
; ++i
) {
575 assert(pTmpBuf
!= NULL
);
576 if (pTmpBuf
== NULL
) {
580 if (wcstrcmparray(pTmpBuf
->lgrui0_name
, Groups
) == 0) {
589 debug("Valid_Local_Groups: ERROR NetUserGetLocalGroups returned: %s\n", Get_WIN32_ErrorMessage(nStatus
));
593 * Free the allocated memory.
596 NetApiBufferFree(pBuf
);
600 /* returns 1 on success, 0 on failure */
602 Valid_Global_Groups(char *UserName
, const char **Groups
)
605 WCHAR wszUser
[DNLEN
+ UNLEN
+ 2]; /* Unicode user name */
606 char NTDomain
[DNLEN
+ UNLEN
+ 2];
608 char *domain_qualify
= NULL
;
609 char User
[DNLEN
+ UNLEN
+ 2];
612 wchar_t *User_DN
, *User_LDAP_path
, *User_PrimaryGroup
;
613 wchar_t **wszGroups
, **tmp
;
617 strncpy(NTDomain
, UserName
, sizeof(NTDomain
));
619 for (j
= 0; j
< strlen(NTV_VALID_DOMAIN_SEPARATOR
); ++j
) {
620 if ((domain_qualify
= strchr(NTDomain
, NTV_VALID_DOMAIN_SEPARATOR
[j
])) != NULL
)
623 if (domain_qualify
== NULL
) {
624 strncpy(User
, DefaultDomain
, DNLEN
);
626 strncat(User
, UserName
, UNLEN
);
627 strncpy(NTDomain
, DefaultDomain
, DNLEN
);
629 domain_qualify
[0] = '\\';
630 strncpy(User
, NTDomain
, DNLEN
+ UNLEN
+ 2);
631 domain_qualify
[0] = '\0';
634 debug("Valid_Global_Groups: checking group membership of '%s'.\n", User
);
636 /* Convert ANSI User Name to Unicode */
638 MultiByteToWideChar(CP_ACP
, 0, User
,
639 strlen(User
) + 1, wszUser
,
640 sizeof(wszUser
) / sizeof(wszUser
[0]));
643 if ((User_DN
= My_NameTranslate(wszUser
, ADS_NAME_TYPE_NT4
, ADS_NAME_TYPE_1779
)) == NULL
) {
644 debug("Valid_Global_Groups: cannot get DN for '%s'.\n", User
);
647 wszGroups
= build_groups_DN_array(Groups
, NTDomain
);
649 User_LDAP_path
= GetLDAPPath(User_DN
, GC_MODE
);
651 hr
= ADsGetObject(User_LDAP_path
, &IID_IADs
, (void **) &pUser
);
653 wchar_t *User_PrimaryGroup_Path
;
656 User_PrimaryGroup
= Get_primaryGroup(pUser
);
657 if (User_PrimaryGroup
== NULL
)
658 debug("Valid_Global_Groups: cannot get Primary Group for '%s'.\n", User
);
660 add_User_Group(User_PrimaryGroup
);
661 User_PrimaryGroup_Path
= GetLDAPPath(User_PrimaryGroup
, GC_MODE
);
662 hr
= ADsGetObject(User_PrimaryGroup_Path
, &IID_IADs
, (void **) &pGrp
);
664 hr
= Recursive_Memberof(pGrp
);
665 pGrp
->lpVtbl
->Release(pGrp
);
666 safe_free(User_PrimaryGroup_Path
);
667 User_PrimaryGroup_Path
= GetLDAPPath(User_PrimaryGroup
, LDAP_MODE
);
668 hr
= ADsGetObject(User_PrimaryGroup_Path
, &IID_IADs
, (void **) &pGrp
);
670 hr
= Recursive_Memberof(pGrp
);
671 pGrp
->lpVtbl
->Release(pGrp
);
673 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_PrimaryGroup_Path
, Get_WIN32_ErrorMessage(hr
));
675 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_PrimaryGroup_Path
, Get_WIN32_ErrorMessage(hr
));
676 safe_free(User_PrimaryGroup_Path
);
678 hr
= Recursive_Memberof(pUser
);
679 pUser
->lpVtbl
->Release(pUser
);
680 safe_free(User_LDAP_path
);
681 User_LDAP_path
= GetLDAPPath(User_DN
, LDAP_MODE
);
682 hr
= ADsGetObject(User_LDAP_path
, &IID_IADs
, (void **) &pUser
);
684 hr
= Recursive_Memberof(pUser
);
685 pUser
->lpVtbl
->Release(pUser
);
687 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_LDAP_path
, Get_WIN32_ErrorMessage(hr
));
691 if (wccmparray(*tmp
, wszGroups
) == 0) {
698 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_LDAP_path
, Get_WIN32_ErrorMessage(hr
));
701 safe_free(User_LDAP_path
);
702 safe_free(User_PrimaryGroup
);
708 safe_free(wszGroups
);
715 safe_free(User_Groups
);
716 User_Groups_Count
= 0;
722 usage(const char *program
)
724 fprintf(stderr
, "Usage: %s [-D domain][-G][-c][-d][-h]\n"
725 " -D default user Domain\n"
726 " -G enable Active Directory Global group mode\n"
727 " -c use case insensitive compare (local mode only)\n"
728 " -d enable debugging\n"
729 " -h this message\n",
734 process_options(int argc
, char *argv
[])
739 while (-1 != (opt
= getopt(argc
, argv
, "D:Gcdh"))) {
742 DefaultDomain
= xstrndup(optarg
, DNLEN
+ 1);
743 strlwr(DefaultDomain
);
749 use_case_insensitive_compare
= 1;
759 /* fall thru to default */
761 fprintf(stderr
, "%s: FATAL: Unknown option: -%c. Exiting\n", program_name
, opt
);
764 break; /* not reached */
771 main(int argc
, char *argv
[])
774 char buf
[HELPER_INPUT_BUFFER
];
777 const char *groups
[512];
780 if (argc
> 0) { /* should always be true */
781 program_name
= strrchr(argv
[0], '/');
782 if (program_name
== NULL
)
783 program_name
= argv
[0];
785 program_name
= "(unknown)";
789 setbuf(stdout
, NULL
);
790 setbuf(stderr
, NULL
);
792 /* Check Command Line */
793 process_options(argc
, argv
);
796 if ((machinedomain
= GetDomainName()) == NULL
) {
797 fprintf(stderr
, "%s: FATAL: Can't read machine domain\n", program_name
);
800 strlwr(machinedomain
);
802 DefaultDomain
= xstrdup(machinedomain
);
804 debug("External ACL win32 group helper build " __DATE__
", " __TIME__
805 " starting up...\n");
807 debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain
);
808 if (use_case_insensitive_compare
)
809 debug("Warning: running in case insensitive mode !!!\n");
814 while (fgets(buf
, HELPER_INPUT_BUFFER
, stdin
)) {
815 if (NULL
== strchr(buf
, '\n')) {
816 /* too large message received.. skip and deny */
817 fprintf(stderr
, "%s: ERROR: Too large: %s\n", argv
[0], buf
);
818 while (fgets(buf
, HELPER_INPUT_BUFFER
, stdin
)) {
819 fprintf(stderr
, "%s: ERROR: Too large..: %s\n", argv
[0], buf
);
820 if (strchr(buf
, '\n') != NULL
)
823 SEND_ERR("Invalid Request. Too Long.");
826 if ((p
= strchr(buf
, '\n')) != NULL
)
827 *p
= '\0'; /* strip \n */
828 if ((p
= strchr(buf
, '\r')) != NULL
)
829 *p
= '\0'; /* strip \r */
831 debug("Got '%s' from Squid (length: %d).\n", buf
, strlen(buf
));
833 if (buf
[0] == '\0') {
834 SEND_ERR("Invalid Request. No Input.");
837 username
= strtok(buf
, " ");
838 for (n
= 0; (group
= strtok(NULL
, " ")) != NULL
; ++n
) {
839 rfc1738_unescape(group
);
845 if (NULL
== username
) {
846 SEND_ERR("Invalid Request. No Username.");
849 rfc1738_unescape(username
);
851 if ((use_global
? Valid_Global_Groups(username
, groups
) : Valid_Local_Groups(username
, groups
))) {