2 * ext_ad_group_acl: lookup group membership in a Windows
3 * Active Directory domain
5 * (C)2008-2009 Guido Serassio - Acme Consulting S.r.l.
8 * Guido Serassio <guido.serassio@acmeconsulting.it>
9 * Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
11 * With contributions from others mentioned in the change history section
14 * Based on mswin_check_lm_group by Guido Serassio.
16 * Dependencies: Windows 2000 SP4 and later.
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
35 * 20-09-2009 Guido Serassio
36 * Added explicit Global Catalog query
39 * 20-07-2009 Guido Serassio
40 * Global groups support rewritten, now is based on ADSI.
42 * - support for Domain Local, Domain Global ad Universal
44 * - full group nesting support
46 * 02-05-2008 Guido Serassio
47 * First release, based on mswin_check_lm_group.
49 * This is a helper for the external ACL interface for Squid Cache
51 * It reads from the standard input the domain username and a list of
52 * groups and tries to match it against the groups membership of the
55 * Returns `OK' if the user belongs to a group or `ERR' otherwise, as
56 * described on http://devel.squid-cache.org/external_acl/config.html
61 #include "helpers/defines.h"
62 #include "include/util.h"
66 int _wcsicmp(const wchar_t *, const wchar_t *);
103 int use_case_insensitive_compare
= 0;
104 char *DefaultDomain
= NULL
;
105 const char NTV_VALID_DOMAIN_SEPARATOR
[] = "\\/";
106 int numberofgroups
= 0;
107 int WIN32_COM_initialized
= 0;
108 char *WIN32_ErrorMessage
= NULL
;
109 wchar_t **User_Groups
;
110 int User_Groups_Count
= 0;
112 wchar_t *My_NameTranslate(wchar_t *, int, int);
113 char *Get_WIN32_ErrorMessage(HRESULT
);
118 if (WIN32_COM_initialized
== 1)
123 GetLPBYTEtoOctetString(VARIANT
* pVar
, LPBYTE
* ppByte
)
127 long lLBound
, lUBound
, cElements
;
129 if ((!pVar
) || (!ppByte
))
131 if ((pVar
->n1
.n2
.vt
) != (VT_UI1
| VT_ARRAY
))
134 hr
= SafeArrayGetLBound(V_ARRAY(pVar
), 1, &lLBound
);
135 hr
= SafeArrayGetUBound(V_ARRAY(pVar
), 1, &lUBound
);
137 cElements
= lUBound
- lLBound
+ 1;
138 hr
= SafeArrayAccessData(V_ARRAY(pVar
), &pArray
);
140 LPBYTE pTemp
= (LPBYTE
) pArray
;
141 *ppByte
= (LPBYTE
) CoTaskMemAlloc(cElements
);
143 memcpy(*ppByte
, pTemp
, cElements
);
147 SafeArrayUnaccessData(V_ARRAY(pVar
));
153 Get_primaryGroup(IADs
* pUser
)
157 unsigned User_primaryGroupID
;
158 char tmpSID
[SECURITY_MAX_SID_SIZE
* 2];
159 wchar_t *wc
= NULL
, *result
= NULL
;
164 /* Get the primaryGroupID property */
165 hr
= pUser
->lpVtbl
->Get(pUser
, L
"primaryGroupID", &var
);
167 User_primaryGroupID
= var
.n1
.n2
.n3
.uintVal
;
169 debug("Get_primaryGroup: cannot get primaryGroupID, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
175 /*Get the objectSid property */
176 hr
= pUser
->lpVtbl
->Get(pUser
, L
"objectSid", &var
);
181 hr
= GetLPBYTEtoOctetString(&var
, &pByte
);
183 pObjectSID
= (PSID
) pByte
;
185 /* Convert SID to string. */
186 ConvertSidToStringSid(pObjectSID
, &szSID
);
187 CoTaskMemFree(pByte
);
189 *(strrchr(szSID
, '-') + 1) = '\0';
190 sprintf(tmpSID
, "%s%u", szSID
, User_primaryGroupID
);
192 wcsize
= MultiByteToWideChar(CP_ACP
, 0, tmpSID
, -1, wc
, 0);
193 wc
= (wchar_t *) xmalloc(wcsize
* sizeof(wchar_t));
194 MultiByteToWideChar(CP_ACP
, 0, tmpSID
, -1, wc
, wcsize
);
197 result
= My_NameTranslate(wc
, ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME
, ADS_NAME_TYPE_1779
);
201 debug("Get_primaryGroup: cannot get DN for %s.\n", tmpSID
);
203 debug("Get_primaryGroup: Primary group DN: %S.\n", result
);
205 debug("Get_primaryGroup: cannot get objectSid, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
211 Get_WIN32_ErrorMessage(HRESULT hr
)
213 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
|
214 FORMAT_MESSAGE_IGNORE_INSERTS
,
217 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
218 (LPTSTR
) & WIN32_ErrorMessage
,
221 return WIN32_ErrorMessage
;
225 My_NameTranslate(wchar_t * name
, int in_format
, int out_format
)
227 IADsNameTranslate
*pNto
;
232 if (WIN32_COM_initialized
== 0) {
233 hr
= CoInitialize(NULL
);
235 debug("My_NameTranslate: cannot initialize COM interface, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
236 /* This is a fatal error */
239 WIN32_COM_initialized
= 1;
241 hr
= CoCreateInstance(&CLSID_NameTranslate
,
243 CLSCTX_INPROC_SERVER
,
244 &IID_IADsNameTranslate
,
247 debug("My_NameTranslate: cannot create COM instance, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
248 /* This is a fatal error */
251 hr
= pNto
->lpVtbl
->Init(pNto
, ADS_NAME_INITTYPE_GC
, L
"");
253 debug("My_NameTranslate: cannot initialise NameTranslate API, ERROR: %s\n", Get_WIN32_ErrorMessage(hr
));
254 pNto
->lpVtbl
->Release(pNto
);
255 /* This is a fatal error */
258 hr
= pNto
->lpVtbl
->Set(pNto
, in_format
, name
);
260 debug("My_NameTranslate: cannot set translate of %S, ERROR: %s\n", name
, Get_WIN32_ErrorMessage(hr
));
261 pNto
->lpVtbl
->Release(pNto
);
264 hr
= pNto
->lpVtbl
->Get(pNto
, out_format
, &bstr
);
266 debug("My_NameTranslate: cannot get translate of %S, ERROR: %s\n", name
, Get_WIN32_ErrorMessage(hr
));
267 pNto
->lpVtbl
->Release(pNto
);
270 debug("My_NameTranslate: %S translated to %S\n", name
, bstr
);
272 wc
= (wchar_t *) xmalloc((wcslen(bstr
) + 1) * sizeof(wchar_t));
275 pNto
->lpVtbl
->Release(pNto
);
280 GetLDAPPath(wchar_t * Base_DN
, int query_mode
)
284 wc
= (wchar_t *) xmalloc((wcslen(Base_DN
) + 8) * sizeof(wchar_t));
286 if (query_mode
== LDAP_MODE
)
287 wcscpy(wc
, L
"LDAP://");
289 wcscpy(wc
, L
"GC://");
298 static char *DomainName
= NULL
;
299 PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDSRoleInfo
;
302 if ((netret
= DsRoleGetPrimaryDomainInformation(NULL
, DsRolePrimaryDomainInfoBasic
, (PBYTE
*) & pDSRoleInfo
) == ERROR_SUCCESS
)) {
304 * Check the machine role.
307 if ((pDSRoleInfo
->MachineRole
== DsRole_RoleMemberWorkstation
) ||
308 (pDSRoleInfo
->MachineRole
== DsRole_RoleMemberServer
) ||
309 (pDSRoleInfo
->MachineRole
== DsRole_RoleBackupDomainController
) ||
310 (pDSRoleInfo
->MachineRole
== DsRole_RolePrimaryDomainController
)) {
312 size_t len
= wcslen(pDSRoleInfo
->DomainNameFlat
);
314 /* allocate buffer for str + null termination */
315 safe_free(DomainName
);
316 DomainName
= (char *) xmalloc(len
+ 1);
318 /* copy unicode buffer */
319 WideCharToMultiByte(CP_ACP
, 0, pDSRoleInfo
->DomainNameFlat
, -1, DomainName
, len
, NULL
, NULL
);
321 /* add null termination */
322 DomainName
[len
] = '\0';
325 * Member of a domain. Display it in debug mode.
327 debug("Member of Domain %s\n", DomainName
);
328 debug("Into forest %S\n", pDSRoleInfo
->DomainForestName
);
331 debug("Not a Domain member\n");
334 debug("GetDomainName: ERROR DsRoleGetPrimaryDomainInformation returned: %s\n", Get_WIN32_ErrorMessage(netret
));
337 * Free the allocated memory.
339 if (pDSRoleInfo
!= NULL
)
340 DsRoleFreeMemory(pDSRoleInfo
);
346 add_User_Group(wchar_t * Group
)
350 if (User_Groups_Count
== 0) {
351 User_Groups
= (wchar_t **) xmalloc(sizeof(wchar_t *));
357 if (wcscmp(Group
, *array
) == 0)
361 User_Groups
= (wchar_t **) xrealloc(User_Groups
, sizeof(wchar_t *) * (User_Groups_Count
+ 1));
362 User_Groups
[User_Groups_Count
] = NULL
;
363 User_Groups
[User_Groups_Count
- 1] = (wchar_t *) xmalloc((wcslen(Group
) + 1) * sizeof(wchar_t));
364 wcscpy(User_Groups
[User_Groups_Count
- 1], Group
);
370 /* returns 0 on match, -1 if no match */
372 wccmparray(const wchar_t * str
, const wchar_t ** array
)
375 debug("Windows group: %S, Squid group: %S\n", str
, *array
);
376 if (wcscmp(str
, *array
) == 0)
383 /* returns 0 on match, -1 if no match */
385 wcstrcmparray(const wchar_t * str
, const char **array
)
387 WCHAR wszGroup
[GNLEN
+ 1]; // Unicode Group
390 MultiByteToWideChar(CP_ACP
, 0, *array
,
391 strlen(*array
) + 1, wszGroup
, sizeof(wszGroup
) / sizeof(wszGroup
[0]));
392 debug("Windows group: %S, Squid group: %S\n", str
, wszGroup
);
393 if ((use_case_insensitive_compare
? _wcsicmp(str
, wszGroup
) : wcscmp(str
, wszGroup
)) == 0)
401 Recursive_Memberof(IADs
* pObj
)
408 hr
= pObj
->lpVtbl
->Get(pObj
, L
"memberOf", &var
);
410 if (VT_BSTR
== var
.n1
.n2
.vt
) {
411 if (add_User_Group(var
.n1
.n2
.n3
.bstrVal
)) {
415 Group_Path
= GetLDAPPath(var
.n1
.n2
.n3
.bstrVal
, GC_MODE
);
416 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
418 hr
= Recursive_Memberof(pGrp
);
419 pGrp
->lpVtbl
->Release(pGrp
);
420 safe_free(Group_Path
);
421 Group_Path
= GetLDAPPath(var
.n1
.n2
.n3
.bstrVal
, LDAP_MODE
);
422 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
424 hr
= Recursive_Memberof(pGrp
);
425 pGrp
->lpVtbl
->Release(pGrp
);
427 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
429 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
430 safe_free(Group_Path
);
433 if (SUCCEEDED(SafeArrayGetLBound(V_ARRAY(&var
), 1, &lBound
)) &&
434 SUCCEEDED(SafeArrayGetUBound(V_ARRAY(&var
), 1, &uBound
))) {
436 while (lBound
<= uBound
) {
437 hr
= SafeArrayGetElement(V_ARRAY(&var
), &lBound
, &elem
);
439 if (add_User_Group(elem
.n1
.n2
.n3
.bstrVal
)) {
443 Group_Path
= GetLDAPPath(elem
.n1
.n2
.n3
.bstrVal
, GC_MODE
);
444 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
446 hr
= Recursive_Memberof(pGrp
);
447 pGrp
->lpVtbl
->Release(pGrp
);
448 safe_free(Group_Path
);
449 Group_Path
= GetLDAPPath(elem
.n1
.n2
.n3
.bstrVal
, LDAP_MODE
);
450 hr
= ADsGetObject(Group_Path
, &IID_IADs
, (void **) &pGrp
);
452 hr
= Recursive_Memberof(pGrp
);
453 pGrp
->lpVtbl
->Release(pGrp
);
454 safe_free(Group_Path
);
456 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
458 debug("Recursive_Memberof: ERROR ADsGetObject for %S failed: %s\n", Group_Path
, Get_WIN32_ErrorMessage(hr
));
459 safe_free(Group_Path
);
463 debug("Recursive_Memberof: ERROR SafeArrayGetElement failed: %s\n", Get_WIN32_ErrorMessage(hr
));
469 debug("Recursive_Memberof: ERROR SafeArrayGetxBound failed: %s\n", Get_WIN32_ErrorMessage(hr
));
473 if (hr
!= E_ADS_PROPERTY_NOT_FOUND
)
474 debug("Recursive_Memberof: ERROR getting memberof attribute: %s\n", Get_WIN32_ErrorMessage(hr
));
480 build_groups_DN_array(const char **array
, char *userdomain
)
484 int source_group_format
;
485 char Group
[GNLEN
+ 1];
487 wchar_t **wc_array
, **entry
;
489 entry
= wc_array
= (wchar_t **) xmalloc((numberofgroups
+ 1) * sizeof(wchar_t *));
492 if (strchr(*array
, '/') != NULL
) {
493 strncpy(Group
, *array
, GNLEN
);
494 source_group_format
= ADS_NAME_TYPE_CANONICAL
;
496 source_group_format
= ADS_NAME_TYPE_NT4
;
497 if (strchr(*array
, '\\') == NULL
) {
498 strcpy(Group
, userdomain
);
500 strncat(Group
, *array
, GNLEN
- sizeof(userdomain
) - 1);
502 strncpy(Group
, *array
, GNLEN
);
505 wcsize
= MultiByteToWideChar(CP_ACP
, 0, Group
, -1, wc
, 0);
506 wc
= (wchar_t *) xmalloc(wcsize
* sizeof(wchar_t));
507 MultiByteToWideChar(CP_ACP
, 0, Group
, -1, wc
, wcsize
);
508 *entry
= My_NameTranslate(wc
, source_group_format
, ADS_NAME_TYPE_1779
);
511 if (*entry
== NULL
) {
512 debug("build_groups_DN_array: cannot get DN for '%s'.\n", Group
);
521 /* returns 1 on success, 0 on failure */
523 Valid_Local_Groups(char *UserName
, const char **Groups
)
526 char *Domain_Separator
;
527 WCHAR wszUserName
[UNLEN
+ 1]; /* Unicode user name */
529 LPLOCALGROUP_USERS_INFO_0 pBuf
;
530 LPLOCALGROUP_USERS_INFO_0 pTmpBuf
;
532 DWORD dwFlags
= LG_INCLUDE_INDIRECT
;
533 DWORD dwPrefMaxLen
= -1;
534 DWORD dwEntriesRead
= 0;
535 DWORD dwTotalEntries
= 0;
536 NET_API_STATUS nStatus
;
538 DWORD dwTotalCount
= 0;
539 LPBYTE pBufTmp
= NULL
;
541 if ((Domain_Separator
= strchr(UserName
, '/')) != NULL
)
542 *Domain_Separator
= '\\';
544 debug("Valid_Local_Groups: checking group membership of '%s'.\n", UserName
);
546 /* Convert ANSI User Name and Group to Unicode */
548 MultiByteToWideChar(CP_ACP
, 0, UserName
,
549 strlen(UserName
) + 1, wszUserName
, sizeof(wszUserName
) / sizeof(wszUserName
[0]));
552 * Call the NetUserGetLocalGroups function
553 * specifying information level 0.
555 * The LG_INCLUDE_INDIRECT flag specifies that the
556 * function should also return the names of the local
557 * groups in which the user is indirectly a member.
559 nStatus
= NetUserGetLocalGroups(NULL
,
567 pBuf
= (LPLOCALGROUP_USERS_INFO_0
) pBufTmp
;
569 * If the call succeeds,
571 if (nStatus
== NERR_Success
) {
572 if ((pTmpBuf
= pBuf
) != NULL
) {
573 for (i
= 0; i
< dwEntriesRead
; ++i
) {
574 assert(pTmpBuf
!= NULL
);
575 if (pTmpBuf
== NULL
) {
579 if (wcstrcmparray(pTmpBuf
->lgrui0_name
, Groups
) == 0) {
588 debug("Valid_Local_Groups: ERROR NetUserGetLocalGroups returned: %s\n", Get_WIN32_ErrorMessage(nStatus
));
592 * Free the allocated memory.
595 NetApiBufferFree(pBuf
);
599 /* returns 1 on success, 0 on failure */
601 Valid_Global_Groups(char *UserName
, const char **Groups
)
604 WCHAR wszUser
[DNLEN
+ UNLEN
+ 2]; /* Unicode user name */
605 char NTDomain
[DNLEN
+ UNLEN
+ 2];
607 char *domain_qualify
= NULL
;
608 char User
[DNLEN
+ UNLEN
+ 2];
611 wchar_t *User_DN
, *User_LDAP_path
, *User_PrimaryGroup
;
612 wchar_t **wszGroups
, **tmp
;
616 strncpy(NTDomain
, UserName
, sizeof(NTDomain
));
618 for (j
= 0; j
< strlen(NTV_VALID_DOMAIN_SEPARATOR
); ++j
) {
619 if ((domain_qualify
= strchr(NTDomain
, NTV_VALID_DOMAIN_SEPARATOR
[j
])) != NULL
)
622 if (domain_qualify
== NULL
) {
623 strncpy(User
, DefaultDomain
, DNLEN
);
625 strncat(User
, UserName
, UNLEN
);
626 strncpy(NTDomain
, DefaultDomain
, DNLEN
);
628 domain_qualify
[0] = '\\';
629 strncpy(User
, NTDomain
, DNLEN
+ UNLEN
+ 2);
630 domain_qualify
[0] = '\0';
633 debug("Valid_Global_Groups: checking group membership of '%s'.\n", User
);
635 /* Convert ANSI User Name to Unicode */
637 MultiByteToWideChar(CP_ACP
, 0, User
,
638 strlen(User
) + 1, wszUser
,
639 sizeof(wszUser
) / sizeof(wszUser
[0]));
642 if ((User_DN
= My_NameTranslate(wszUser
, ADS_NAME_TYPE_NT4
, ADS_NAME_TYPE_1779
)) == NULL
) {
643 debug("Valid_Global_Groups: cannot get DN for '%s'.\n", User
);
646 wszGroups
= build_groups_DN_array(Groups
, NTDomain
);
648 User_LDAP_path
= GetLDAPPath(User_DN
, GC_MODE
);
650 hr
= ADsGetObject(User_LDAP_path
, &IID_IADs
, (void **) &pUser
);
652 wchar_t *User_PrimaryGroup_Path
;
655 User_PrimaryGroup
= Get_primaryGroup(pUser
);
656 if (User_PrimaryGroup
== NULL
)
657 debug("Valid_Global_Groups: cannot get Primary Group for '%s'.\n", User
);
659 add_User_Group(User_PrimaryGroup
);
660 User_PrimaryGroup_Path
= GetLDAPPath(User_PrimaryGroup
, GC_MODE
);
661 hr
= ADsGetObject(User_PrimaryGroup_Path
, &IID_IADs
, (void **) &pGrp
);
663 hr
= Recursive_Memberof(pGrp
);
664 pGrp
->lpVtbl
->Release(pGrp
);
665 safe_free(User_PrimaryGroup_Path
);
666 User_PrimaryGroup_Path
= GetLDAPPath(User_PrimaryGroup
, LDAP_MODE
);
667 hr
= ADsGetObject(User_PrimaryGroup_Path
, &IID_IADs
, (void **) &pGrp
);
669 hr
= Recursive_Memberof(pGrp
);
670 pGrp
->lpVtbl
->Release(pGrp
);
672 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_PrimaryGroup_Path
, Get_WIN32_ErrorMessage(hr
));
674 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_PrimaryGroup_Path
, Get_WIN32_ErrorMessage(hr
));
675 safe_free(User_PrimaryGroup_Path
);
677 hr
= Recursive_Memberof(pUser
);
678 pUser
->lpVtbl
->Release(pUser
);
679 safe_free(User_LDAP_path
);
680 User_LDAP_path
= GetLDAPPath(User_DN
, LDAP_MODE
);
681 hr
= ADsGetObject(User_LDAP_path
, &IID_IADs
, (void **) &pUser
);
683 hr
= Recursive_Memberof(pUser
);
684 pUser
->lpVtbl
->Release(pUser
);
686 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_LDAP_path
, Get_WIN32_ErrorMessage(hr
));
690 if (wccmparray(*tmp
, wszGroups
) == 0) {
697 debug("Valid_Global_Groups: ADsGetObject for %S failed, ERROR: %s\n", User_LDAP_path
, Get_WIN32_ErrorMessage(hr
));
700 safe_free(User_LDAP_path
);
701 safe_free(User_PrimaryGroup
);
707 safe_free(wszGroups
);
714 safe_free(User_Groups
);
715 User_Groups_Count
= 0;
721 usage(const char *program
)
723 fprintf(stderr
, "Usage: %s [-D domain][-G][-c][-d][-h]\n"
724 " -D default user Domain\n"
725 " -G enable Active Directory Global group mode\n"
726 " -c use case insensitive compare (local mode only)\n"
727 " -d enable debugging\n"
728 " -h this message\n",
733 process_options(int argc
, char *argv
[])
738 while (-1 != (opt
= getopt(argc
, argv
, "D:Gcdh"))) {
741 DefaultDomain
= xstrndup(optarg
, DNLEN
+ 1);
742 strlwr(DefaultDomain
);
748 use_case_insensitive_compare
= 1;
758 /* fall thru to default */
760 fprintf(stderr
, "%s: FATAL: Unknown option: -%c. Exiting\n", program_name
, opt
);
763 break; /* not reached */
770 main(int argc
, char *argv
[])
773 char buf
[HELPER_INPUT_BUFFER
];
776 const char *groups
[512];
779 if (argc
> 0) { /* should always be true */
780 program_name
= strrchr(argv
[0], '/');
781 if (program_name
== NULL
)
782 program_name
= argv
[0];
784 program_name
= "(unknown)";
788 setbuf(stdout
, NULL
);
789 setbuf(stderr
, NULL
);
791 /* Check Command Line */
792 process_options(argc
, argv
);
795 if ((machinedomain
= GetDomainName()) == NULL
) {
796 fprintf(stderr
, "%s: FATAL: Can't read machine domain\n", program_name
);
799 strlwr(machinedomain
);
801 DefaultDomain
= xstrdup(machinedomain
);
803 debug("External ACL win32 group helper build " __DATE__
", " __TIME__
804 " starting up...\n");
806 debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain
);
807 if (use_case_insensitive_compare
)
808 debug("Warning: running in case insensitive mode !!!\n");
813 while (fgets(buf
, HELPER_INPUT_BUFFER
, stdin
)) {
814 if (NULL
== strchr(buf
, '\n')) {
815 /* too large message received.. skip and deny */
816 fprintf(stderr
, "%s: ERROR: Too large: %s\n", argv
[0], buf
);
817 while (fgets(buf
, HELPER_INPUT_BUFFER
, stdin
)) {
818 fprintf(stderr
, "%s: ERROR: Too large..: %s\n", argv
[0], buf
);
819 if (strchr(buf
, '\n') != NULL
)
822 SEND_ERR("Invalid Request. Too Long.");
825 if ((p
= strchr(buf
, '\n')) != NULL
)
826 *p
= '\0'; /* strip \n */
827 if ((p
= strchr(buf
, '\r')) != NULL
)
828 *p
= '\0'; /* strip \r */
830 debug("Got '%s' from Squid (length: %d).\n", buf
, strlen(buf
));
832 if (buf
[0] == '\0') {
833 SEND_ERR("Invalid Request. No Input.");
836 username
= strtok(buf
, " ");
837 for (n
= 0; (group
= strtok(NULL
, " ")) != NULL
; ++n
) {
838 rfc1738_unescape(group
);
844 if (NULL
== username
) {
845 SEND_ERR("Invalid Request. No Username.");
848 rfc1738_unescape(username
);
850 if ((use_global
? Valid_Global_Groups(username
, groups
) : Valid_Local_Groups(username
, groups
))) {