~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to helpers/external_acl/mswin_lm_group/win32_check_group.c

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2006-11-11 10:32:06 UTC
  • Revision ID: james.westby@ubuntu.com-20061111103206-f3p0r9g0vq44rp3r
Tags: upstream-3.0.PRE5
ImportĀ upstreamĀ versionĀ 3.0.PRE5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * mswin_check_lm_group: lookup group membership in a Windows NT/2000 domain
 
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.
 
37
 *              Fixed Bugzilla #1336. 
 
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
 
60
 * 
 
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"
 
71
#ifdef _SQUID_CYGWIN_
 
72
#include <wchar.h>
 
73
int _wcsicmp(const wchar_t *, const wchar_t *);
 
74
#endif
 
75
#if HAVE_STDIO_H
 
76
#include <stdio.h>
 
77
#endif
 
78
#if HAVE_CTYPE_H
 
79
#include <ctype.h>
 
80
#endif
 
81
#ifdef HAVE_STRING_H
 
82
#include <string.h>
 
83
#endif
 
84
#if HAVE_GETOPT_H
 
85
#include <getopt.h>
 
86
#endif
 
87
#undef assert
 
88
#include <assert.h>
 
89
#include <windows.h>
 
90
#include <lm.h>
 
91
#include <ntsecapi.h>
 
92
 
 
93
#include "util.h"
 
94
 
 
95
#define BUFSIZE 8192            /* the stdin buffer size */
 
96
int use_global = 0;
 
97
int use_PDC_only = 0;
 
98
char debug_enabled = 0;
 
99
char *myname;
 
100
pid_t mypid;
 
101
char *machinedomain;
 
102
int use_case_insensitive_compare = 0;
 
103
char *DefaultDomain = NULL;
 
104
const char NTV_VALID_DOMAIN_SEPARATOR[] = "\\/";
 
105
 
 
106
#include "win32_check_group.h"
 
107
 
 
108
 
 
109
char *
 
110
AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr)
 
111
{
 
112
    size_t len;
 
113
    static char *target;
 
114
 
 
115
    len = LsaStr.Length / sizeof(WCHAR) + 1;
 
116
 
 
117
    /* allocate buffer for str + null termination */
 
118
    safe_free(target);
 
119
    target = (char *) xmalloc(len);
 
120
    if (target == NULL)
 
121
        return NULL;
 
122
 
 
123
    /* copy unicode buffer */
 
124
    WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL);
 
125
 
 
126
    /* add null termination */
 
127
    target[len - 1] = '\0';
 
128
    return target;
 
129
}
 
130
 
 
131
 
 
132
char *
 
133
GetDomainName(void)
 
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;
 
141
    char *DomainName = NULL;
 
142
 
 
143
    /* 
 
144
     * Always initialize the object attributes to all zeroes.
 
145
     */
 
146
    memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes));
 
147
 
 
148
    /* 
 
149
     * You need the local workstation name. Use NetWkstaGetInfo at level
 
150
     * 100 to retrieve a WKSTA_INFO_100 structure.
 
151
     * 
 
152
     * The wki100_computername field contains a pointer to a UNICODE
 
153
     * string containing the local computer name.
 
154
     */
 
155
    netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *) & pwkiWorkstationInfo);
 
156
    if (netret == NERR_Success) {
 
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);
 
215
    } else
 
216
        debug("NetWkstaGetInfo Error: %ld\n", netret);
 
217
    return DomainName;
 
218
}
 
219
 
 
220
/* returns 0 on match, -1 if no match */
 
221
static int 
 
222
wcstrcmparray(const wchar_t * str, const char **array)
 
223
{
 
224
    WCHAR wszGroup[GNLEN + 1];  // Unicode Group
 
225
 
 
226
    while (*array) {
 
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++;
 
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;
 
242
    char *Domain_Separator;
 
243
    WCHAR wszUserName[UNLEN + 1];       // Unicode user name
 
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)
 
257
        *Domain_Separator = '\\';
 
258
 
 
259
    debug("Valid_Local_Groups: checking group membership of '%s'.\n", UserName);
 
260
 
 
261
/* Convert ANSI User Name and Group to Unicode */
 
262
 
 
263
    MultiByteToWideChar(CP_ACP, 0, UserName,
 
264
        strlen(UserName) + 1, wszUserName, sizeof(wszUserName) / sizeof(wszUserName[0]));
 
265
 
 
266
    /*
 
267
     * Call the NetUserGetLocalGroups function 
 
268
     * specifying information level 0.
 
269
     * 
 
270
     * The LG_INCLUDE_INDIRECT flag specifies that the 
 
271
     * function should also return the names of the local 
 
272
     * groups in which the user is indirectly a member.
 
273
     */
 
274
    nStatus = NetUserGetLocalGroups(
 
275
        NULL,
 
276
        wszUserName,
 
277
        dwLevel,
 
278
        dwFlags,
 
279
        (LPBYTE *) & pBuf,
 
280
        dwPrefMaxLen,
 
281
        &dwEntriesRead,
 
282
        &dwTotalEntries);
 
283
    /*
 
284
     * If the call succeeds,
 
285
     */
 
286
    if (nStatus == NERR_Success) {
 
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
        }
 
302
    } else
 
303
        result = 0;
 
304
/*
 
305
 * Free the allocated memory.
 
306
 */
 
307
    if (pBuf != NULL)
 
308
        NetApiBufferFree(pBuf);
 
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;
 
318
    WCHAR wszUserName[UNLEN + 1];       // Unicode user name
 
319
 
 
320
    WCHAR wszLocalDomain[DNLEN + 1];    // Unicode Local Domain
 
321
 
 
322
    WCHAR wszUserDomain[DNLEN + 1];     // Unicode User Domain
 
323
 
 
324
    char NTDomain[DNLEN + UNLEN + 2];
 
325
    char *domain_qualify;
 
326
    char User[UNLEN + 1];
 
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
 
 
344
    for (j = 0; j < strlen(NTV_VALID_DOMAIN_SEPARATOR); j++) {
 
345
        if ((domain_qualify = strchr(NTDomain, NTV_VALID_DOMAIN_SEPARATOR[j])) != NULL)
 
346
            break;
 
347
    }
 
348
    if (domain_qualify == NULL) {
 
349
        strcpy(User, NTDomain);
 
350
        strcpy(NTDomain, DefaultDomain);
 
351
    } else {
 
352
        strcpy(User, domain_qualify + 1);
 
353
        domain_qualify[0] = '\0';
 
354
        strlwr(NTDomain);
 
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,
 
362
        strlen(User) + 1, wszUserName,
 
363
        sizeof(wszUserName) / sizeof(wszUserName[0]));
 
364
    MultiByteToWideChar(CP_ACP, 0, machinedomain,
 
365
        strlen(machinedomain) + 1, wszLocalDomain, sizeof(wszLocalDomain) / sizeof(wszLocalDomain[0]));
 
366
 
 
367
 
 
368
/* Call the NetServerGetInfo function for local computer, specifying level 101. */
 
369
    dwLevel = 101;
 
370
    nStatus = NetServerGetInfo(NULL, dwLevel, (LPBYTE *) & pSrvBuf);
 
371
 
 
372
    if (nStatus == NERR_Success) {
 
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));
 
380
    } else {
 
381
        fprintf(stderr, "%s NetServerGetInfo() failed.'\n", myname);
 
382
        if (pSrvBuf != NULL)
 
383
            NetApiBufferFree(pSrvBuf);
 
384
        return result;
 
385
    }
 
386
 
 
387
    if (nStatus == NERR_Success) {
 
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) {
 
395
                fprintf(stderr, "%s Can't find DC for user's domain '%s'\n", myname, NTDomain);
 
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;
 
441
            fprintf(stderr, "%s NetUserGetGroups() failed.'\n", myname);
 
442
        }
 
443
    } else {
 
444
        fprintf(stderr, "%s Can't find DC for local domain '%s'\n", myname, machinedomain);
 
445
    }
 
446
    /*
 
447
     * Free the allocated memory.
 
448
     */
 
449
    if (pSrvBuf != NULL)
 
450
        NetApiBufferFree(pSrvBuf);
 
451
    if (pUsrBuf != NULL)
 
452
        NetApiBufferFree(pUsrBuf);
 
453
    if ((UsrDCptr != NULL) && (UsrDCptr != LclDCptr))
 
454
        NetApiBufferFree((LPVOID) UsrDCptr);
 
455
    if (LclDCptr != NULL)
 
456
        NetApiBufferFree((LPVOID) LclDCptr);
 
457
    return result;
 
458
}
 
459
 
 
460
static void
 
461
usage(char *program)
 
462
{
 
463
    fprintf(stderr, "Usage: %s [-D domain][-G][-P][-c][-d][-h]\n"
 
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);
 
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"))) {
 
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:
 
504
            fprintf(stderr, "%s Unknown option: -%c. Exiting\n", myname, opt);
 
505
            usage(argv[0]);
 
506
            exit(1);
 
507
            break;              /* not reached */
 
508
        }
 
509
    }
 
510
    return;
 
511
}
 
512
 
 
513
 
 
514
int
 
515
main(int argc, char *argv[])
 
516
{
 
517
    char *p;
 
518
    char buf[BUFSIZE];
 
519
    char *username;
 
520
    char *group;
 
521
    int err = 0;
 
522
    const char *groups[512];
 
523
    int n;
 
524
 
 
525
    if (argc > 0) {             /* should always be true */
 
526
        myname = strrchr(argv[0], '/');
 
527
        if (myname == NULL)
 
528
            myname = argv[0];
 
529
    } else {
 
530
        myname = "(unknown)";
 
531
    }
 
532
    mypid = getpid();
 
533
 
 
534
    setbuf(stdout, NULL);
 
535
    setbuf(stderr, NULL);
 
536
 
 
537
    /* Check Command Line */
 
538
    process_options(argc, argv);
 
539
 
 
540
    if (use_global) {
 
541
        if ((machinedomain = GetDomainName()) == NULL) {
 
542
            fprintf(stderr, "%s Can't read machine domain\n", myname);
 
543
            exit(1);
 
544
        }
 
545
        strlwr(machinedomain);
 
546
        if (!DefaultDomain)
 
547
            DefaultDomain = xstrdup(machinedomain);
 
548
    }
 
549
    debug("External ACL win32 group helper build " __DATE__ ", " __TIME__
 
550
        " starting up...\n");
 
551
    if (use_global)
 
552
        debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain);
 
553
    if (use_case_insensitive_compare)
 
554
        debug("Warning: running in case insensitive mode !!!\n");
 
555
    if (use_PDC_only)
 
556
        debug("Warning: using only PDCs for group validation !!!\n");
 
557
 
 
558
    /* Main Loop */
 
559
    while (fgets(buf, sizeof(buf), stdin)) {
 
560
        if (NULL == strchr(buf, '\n')) {
 
561
            /* too large message received.. skip and deny */
 
562
            fprintf(stderr, "%s: ERROR: Too large: %s\n", argv[0], buf);
 
563
            while (fgets(buf, sizeof(buf), stdin)) {
 
564
                fprintf(stderr, "%s: ERROR: Too large..: %s\n", argv[0], buf);
 
565
                if (strchr(buf, '\n') != NULL)
 
566
                    break;
 
567
            }
 
568
            goto error;
 
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') {
 
578
            fprintf(stderr, "Invalid Request\n");
 
579
            goto error;
 
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) {
 
589
            fprintf(stderr, "Invalid Request\n");
 
590
            goto error;
 
591
        }
 
592
        rfc1738_unescape(username);
 
593
 
 
594
        if ((use_global ? Valid_Global_Groups(username, groups) : Valid_Local_Groups(username, groups))) {
 
595
            printf("OK\n");
 
596
        } else {
 
597
          error:
 
598
            printf("ERR\n");
 
599
        }
 
600
        err = 0;
 
601
    }
 
602
    return 0;
 
603
}