22167f0785821356d638be93acd6b1313ca044ce
[openafs.git] / src / afs / afs_osi_pag.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  * genpag
13  * getpag
14  * afs_setpag
15  * AddPag
16  * afs_InitReq
17  * afs_get_pag_from_groups
18  * afs_get_groups_from_pag
19  * PagInCred
20  */
21
22 #include <afsconfig.h>
23 #include "afs/param.h"
24
25
26 #include "afs/sysincludes.h"    /* Standard vendor system headers */
27 #include "afsincludes.h"        /* Afs-based standard headers */
28 #include "afs/afs_stats.h"      /* statistics */
29 #include "afs/afs_cbqueue.h"
30 #include "afs/nfsclient.h"
31 #include "afs/afs_osidnlc.h"
32
33
34 /* Imported variables */
35 extern enum afs_shutdown_state afs_shuttingdown;
36
37 /* Exported variables */
38 afs_uint32 pag_epoch;
39 #if defined(UKERNEL)
40 afs_uint32 pagCounter = 1;
41 #else
42 afs_uint32 pagCounter = 0;
43 #endif /* UKERNEL */
44
45 /*
46  * Pags are implemented as follows: the set of groups whose long
47  * representation is '41XXXXXX' hex are used to represent the pags.
48  * Being a member of such a group means you are authenticated as pag
49  * XXXXXX (0x41 == 'A', for Andrew).  You are never authenticated as
50  * multiple pags at once.
51  *
52  * The function afs_InitReq takes a credential field and formats the
53  * corresponding venus request structure.  The uid field in the
54  * vrequest structure is set to the *pag* you are authenticated as, or
55  * the uid, if you aren't authenticated with a pag.
56  *
57  * The basic motivation behind pags is this: just because your unix
58  * uid is N doesn't mean that you should have the same privileges as
59  * anyone logged in on the machine as user N, since this would enable
60  * the superuser on the machine to sneak in and make use of anyone's
61  * authentication info, even that which is only accidentally left
62  * behind when someone leaves a public workstation.
63  *
64  * AFS doesn't use the unix uid for anything except
65  * a handle with which to find the actual authentication tokens
66  * anyway, so the pag is an alternative handle which is somewhat more
67  * secure (although of course not absolutely secure).
68 */
69 #if !defined(UKERNEL)
70 afs_uint32
71 genpag(void)
72 {
73     AFS_STATCNT(genpag);
74 #ifdef AFS_LINUX20_ENV
75     /* Ensure unique PAG's (mod 200 days) when reloading the client. */
76     return (('A' << 24) + ((pag_epoch + pagCounter++) & 0xffffff));
77 #else /* AFS_LINUX20_ENV */
78     return (('A' << 24) + (pagCounter++ & 0xffffff));
79 #endif /* AFS_LINUX20_ENV */
80 }
81
82 afs_uint32
83 getpag(void)
84 {
85     AFS_STATCNT(getpag);
86 #ifdef AFS_LINUX20_ENV
87     /* Ensure unique PAG's (mod 200 days) when reloading the client. */
88     return (('A' << 24) + ((pag_epoch + pagCounter) & 0xffffff));
89 #else
90     return (('A' << 24) + (pagCounter & 0xffffff));
91 #endif
92 }
93
94 #else
95
96 /* Web enhancement: we don't need to restrict pags to 41XXXXXX since
97  * we are not sharing the space with anyone.  So we use the full 32 bits. */
98
99 afs_uint32
100 genpag(void)
101 {
102     AFS_STATCNT(genpag);
103 #ifdef AFS_LINUX20_ENV
104     return (pag_epoch + pagCounter++);
105 #else
106     return (pagCounter++);
107 #endif /* AFS_LINUX20_ENV */
108 }
109
110 afs_uint32
111 getpag(void)
112 {
113     AFS_STATCNT(getpag);
114 #ifdef AFS_LINUX20_ENV
115     /* Ensure unique PAG's (mod 200 days) when reloading the client. */
116     return (pag_epoch + pagCounter);
117 #else
118     return (pagCounter);
119 #endif
120 }
121 #endif /* UKERNEL */
122
123 /* used to require 10 seconds between each setpag to guarantee that
124  * PAGs never wrap - which would be a security hole.  If we presume
125  * that in ordinary operation, the average rate of PAG allocation
126  * will not exceed one per second, the 24 bits provided will be
127  * sufficient for ~200 days.  Unfortunately, if we merely assume that,
128  * there will be an opportunity for attack.  So we must enforce it.
129  * If we need to increase the average rate of PAG allocation, we
130  * should increase the number of bits in a PAG, and/or reduce our
131  * window in which we guarantee that the PAG counter won't wrap.
132  * By permitting an average of one new PAG per second, new PAGs can
133  * be allocated VERY frequently over a short period relative to total uptime.
134  * Of course, there's only an issue here if one user stays logged (and re-
135  * activates tokens repeatedly) for that entire period.
136  */
137
138 static int afs_pag_sleepcnt = 0;
139 static int afs_pag_timewarn = 0;
140
141 static int
142 afs_pag_sleep(afs_ucred_t **acred)
143 {
144     int rv = 0;
145
146     if (!afs_suser(acred)) {
147         if(osi_Time() - pag_epoch < pagCounter) {
148             rv = 1;
149         }
150         if (rv && (osi_Time() < pag_epoch)) {
151             if (!afs_pag_timewarn) {
152                 afs_pag_timewarn = 1;
153                 afs_warn("clock went backwards, not PAG throttling");
154             }
155             rv = 0;
156         }
157     }
158
159     return rv;
160 }
161
162 static int
163 afs_pag_wait(afs_ucred_t **acred)
164 {
165     int code = 0;
166
167     if (afs_pag_sleep(acred)) {
168         if (!afs_pag_sleepcnt) {
169             afs_warn("%s() PAG throttling triggered, pid %d... sleeping.  sleepcnt %d\n",
170                      "afs_pag_wait", osi_getpid(), afs_pag_sleepcnt);
171         }
172
173         afs_pag_sleepcnt++;
174
175         do {
176             code = afs_osi_Wait(1000, (struct afs_osi_WaitHandle *)0, 0);
177         } while (!code && afs_pag_sleep(acred));
178
179         afs_pag_sleepcnt--;
180     }
181
182     return code;
183 }
184
185 int
186 #if     defined(AFS_SUN5_ENV)
187 afs_setpag(afs_ucred_t **credpp)
188 #elif   defined(AFS_FBSD_ENV)
189 afs_setpag(struct thread *td, void *args)
190 #elif   defined(AFS_NBSD_ENV)
191 afs_setpag(afs_proc_t *p, const void *args, register_t *retval)
192 #elif  defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
193 afs_setpag(afs_proc_t *p, void *args, int *retval)
194 #else
195 afs_setpag(void)
196 #endif
197 {
198
199 #if     defined(AFS_SUN5_ENV)
200     afs_ucred_t **acred = *credpp;
201 #elif  defined(AFS_OBSD_ENV)
202     afs_ucred_t **acred = &p->p_ucred;
203 #else
204     afs_ucred_t **acred = NULL;
205 #endif
206
207     int code = 0;
208
209 #if defined(AFS_SGI53_ENV) && defined(MP)
210     /* This is our first chance to get the global lock. */
211     AFS_GLOCK();
212 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
213
214     AFS_STATCNT(afs_setpag);
215
216     code = afs_pag_wait(acred);
217     if (code) {
218         goto done;
219     }
220
221
222 #if     defined(AFS_SUN5_ENV)
223     code = AddPag(genpag(), credpp);
224 #elif   defined(AFS_FBSD_ENV)
225     code = AddPag(td, genpag(), &td->td_ucred);
226 #elif   defined(AFS_NBSD40_ENV)
227     code = AddPag(p, genpag(), &p->l_proc->p_cred);
228 #elif   defined(AFS_XBSD_ENV)
229     code = AddPag(p, genpag(), &p->p_rcred);
230 #elif   defined(AFS_AIX41_ENV)
231     {
232         struct ucred *credp;
233         struct ucred *credp0;
234
235         credp = crref();
236         credp0 = credp;
237         code = AddPag(genpag(), &credp);
238         /* If AddPag() didn't make a new cred, then free our cred ref */
239         if (credp == credp0) {
240             crfree(credp);
241         }
242     }
243 #elif   defined(AFS_HPUX110_ENV)
244     {
245         struct ucred *credp = p_cred(u.u_procp);
246         code = AddPag(genpag(), &credp);
247     }
248 #elif   defined(AFS_SGI_ENV)
249     {
250         cred_t *credp;
251         credp = OSI_GET_CURRENT_CRED();
252         code = AddPag(genpag(), &credp);
253     }
254 #elif   defined(AFS_LINUX20_ENV)
255     {
256         afs_ucred_t *credp = crref();
257         code = AddPag(genpag(), &credp);
258         crfree(credp);
259     }
260 #elif defined(AFS_DARWIN80_ENV)
261     {
262         afs_ucred_t *credp = kauth_cred_proc_ref(p);
263         code = AddPag(p, genpag(), &credp);
264         crfree(credp);
265     }
266 #elif defined(AFS_DARWIN_ENV)
267     {
268         afs_ucred_t *credp = crdup(p->p_cred->pc_ucred);
269         code = AddPag(p, genpag(), &credp);
270         crfree(credp);
271     }
272 #elif defined(UKERNEL)
273     code = AddPag(genpag(), &(get_user_struct()->u_cred));
274 #else
275     code = AddPag(genpag(), &u.u_cred);
276 #endif
277
278   done:
279     afs_Trace1(afs_iclSetp, CM_TRACE_SETPAG, ICL_TYPE_INT32, code);
280
281 #if defined(KERNEL_HAVE_UERROR)
282     if (!getuerror())
283         setuerror(code);
284 #endif
285
286 #if defined(AFS_SGI53_ENV) && defined(MP)
287     AFS_GUNLOCK();
288 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
289
290     return (code);
291 }
292
293 #if defined(UKERNEL)
294 /*
295  * afs_setpag_val
296  * This function is like setpag but sets the current thread's pag id to a
297  * caller-provided value instead of calling genpag().  This implements a
298  * form of token caching since the caller can recall a particular pag value
299  * for the thread to restore tokens, rather than reauthenticating.
300  */
301 int
302 #if     defined(AFS_SUN5_ENV)
303 afs_setpag_val(afs_ucred_t **credpp, int pagval)
304 #elif   defined(AFS_FBSD_ENV)
305 afs_setpag_val(struct thread *td, void *args, int pagval)
306 #elif  defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
307 afs_setpag_val(afs_proc_t *p, void *args, int *retval, int pagval)
308 #else
309 afs_setpag_val(int pagval)
310 #endif
311 {
312
313 #if     defined(AFS_SUN5_ENV)
314     afs_ucred_t **acred = *credp;
315 #elif  defined(AFS_OBSD_ENV)
316     afs_ucred_t **acred = &p->p_ucred;
317 #else
318     afs_ucred_t **acred = NULL;
319 #endif
320
321     int code = 0;
322
323 #if defined(AFS_SGI53_ENV) && defined(MP)
324     /* This is our first chance to get the global lock. */
325     AFS_GLOCK();
326 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
327
328     AFS_STATCNT(afs_setpag);
329
330     code = afs_pag_wait(acred);
331     if (code) {
332         goto done;
333     }
334
335 #if     defined(AFS_SUN5_ENV)
336     code = AddPag(pagval, credpp);
337 #elif   defined(AFS_FBSD_ENV)
338     code = AddPag(td, pagval, &td->td_ucred);
339 #elif   defined(AFS_XBSD_ENV)
340     code = AddPag(p, pagval, &p->p_rcred);
341 #elif   defined(AFS_AIX41_ENV)
342     {
343         struct ucred *credp;
344         struct ucred *credp0;
345
346         credp = crref();
347         credp0 = credp;
348         code = AddPag(pagval, &credp);
349         /* If AddPag() didn't make a new cred, then free our cred ref */
350         if (credp == credp0) {
351             crfree(credp);
352         }
353     }
354 #elif   defined(AFS_HPUX110_ENV)
355     {
356         struct ucred *credp = p_cred(u.u_procp);
357         code = AddPag(pagval, &credp);
358     }
359 #elif   defined(AFS_SGI_ENV)
360     {
361         cred_t *credp;
362         credp = OSI_GET_CURRENT_CRED();
363         code = AddPag(pagval, &credp);
364     }
365 #elif   defined(AFS_LINUX20_ENV)
366     {
367         afs_ucred_t *credp = crref();
368         code = AddPag(pagval, &credp);
369         crfree(credp);
370     }
371 #elif defined(AFS_DARWIN_ENV)
372     {
373         struct ucred *credp = crdup(p->p_cred->pc_ucred);
374         code = AddPag(p, pagval, &credp);
375         crfree(credp);
376     }
377 #elif defined(UKERNEL)
378     code = AddPag(pagval, &(get_user_struct()->u_cred));
379 #else
380     code = AddPag(pagval, &u.u_cred);
381 #endif
382
383   done:
384     afs_Trace1(afs_iclSetp, CM_TRACE_SETPAG, ICL_TYPE_INT32, code);
385 #if defined(KERNEL_HAVE_UERROR)
386     if (!getuerror())
387         setuerror(code);
388 #endif
389 #if defined(AFS_SGI53_ENV) && defined(MP)
390     AFS_GUNLOCK();
391 #endif /* defined(AFS_SGI53_ENV) && defined(MP) */
392     return (code);
393 }
394
395 #ifndef AFS_PAG_ONEGROUP_ENV
396 int
397 afs_getpag_val(void)
398 {
399     int pagvalue;
400 #ifdef UKERNEL
401     afs_ucred_t *credp = get_user_struct()->u_cred;
402 #else
403     afs_ucred_t *credp = u.u_cred;
404 #endif
405     gid_t gidset0, gidset1;
406 #ifdef AFS_SUN510_ENV
407     const gid_t *gids;
408
409     gids = crgetgroups(*credp);
410     gidset0 = gids[0];
411     gidset1 = gids[1];
412 #else
413     gidset0 = credp->cr_groups[0];
414     gidset1 = credp->cr_groups[1];
415 #endif
416     pagvalue = afs_get_pag_from_groups(gidset0, gidset1);
417     return pagvalue;
418 }
419 #endif
420 #endif /* UKERNEL */
421
422
423 /* Note - needs to be available on AIX, others can be static - rework this */
424 int
425 #if defined(AFS_FBSD_ENV)
426 AddPag(struct thread *p, afs_int32 aval, afs_ucred_t **credpp)
427 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
428 AddPag(afs_proc_t *p, afs_int32 aval, afs_ucred_t **credpp)
429 #else
430 AddPag(afs_int32 aval, afs_ucred_t **credpp)
431 #endif
432 {
433     afs_int32 code;
434     afs_uint32 newpag;
435
436     AFS_STATCNT(AddPag);
437 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
438     if ((code = setpag(p, credpp, aval, &newpag, 0)))
439 #else
440     if ((code = setpag(credpp, aval, &newpag, 0)))
441 #endif
442 #if defined(KERNEL_HAVE_UERROR)
443         return (setuerror(code), code);
444 #else
445         return (code);
446 #endif
447     return 0;
448 }
449
450
451 int
452 afs_InitReq(struct vrequest *av, afs_ucred_t *acred)
453 {
454 #if defined(AFS_LINUX26_ENV) && !defined(AFS_NONFSTRANS)
455     int code;
456 #endif
457
458     AFS_STATCNT(afs_InitReq);
459     memset(av, 0, sizeof(*av));
460     if (afs_shuttingdown == AFS_SHUTDOWN)
461         return EIO;
462
463 #ifdef AFS_LINUX26_ENV
464 #if !defined(AFS_NONFSTRANS)
465     if (osi_linux_nfs_initreq(av, acred, &code))
466         return code;
467 #endif
468 #endif
469
470     av->uid = PagInCred(acred);
471     if (av->uid == NOPAG) {
472         /* Afs doesn't use the unix uid for anuthing except a handle
473          * with which to find the actual authentication tokens so I
474          * think it's ok to use the real uid to make setuid
475          * programs (without setpag) to work properly.
476          */
477 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
478         if (acred == NOCRED)
479             av->uid = -2;       /* XXX nobody... ? */
480         else
481             av->uid = afs_cr_uid(acred);        /* bsd creds don't have ruid */
482 #elif defined(AFS_SUN510_ENV)
483         av->uid = crgetruid(acred);
484 #else
485         av->uid = afs_cr_ruid(acred);   /* default when no pag is set */
486 #endif
487     }
488     return 0;
489 }
490
491 /*!
492  * Allocate and setup a vrequest.
493  *
494  * \note The caller must free the allocated vrequest with
495  *       afs_DestroyReq() if this function returns successfully (zero).
496  *
497  * \note The GLOCK must be held on platforms which require the GLOCK
498  *       for osi_AllocSmallSpace() and osi_FreeSmallSpace().
499  *
500  * \param[out] avpp   address of the vrequest pointer
501  * \param[in]  acred  user credentials to setup the vrequest
502  *                    afs_osi_credp should be used for anonymous connections
503  * \return     0 on success
504  */
505 int
506 afs_CreateReq(struct vrequest **avpp, afs_ucred_t *acred)
507 {
508     int code;
509     struct vrequest *treq = NULL;
510
511     if (afs_shuttingdown == AFS_SHUTDOWN) {
512         return EIO;
513     }
514     if (!avpp || !acred) {
515         return EINVAL;
516     }
517     treq = osi_AllocSmallSpace(sizeof(struct vrequest));
518     if (!treq) {
519         return ENOMEM;
520     }
521     code = afs_InitReq(treq, acred);
522     if (code != 0) {
523         osi_FreeSmallSpace(treq);
524         return code;
525     }
526     *avpp = treq;
527     return 0;
528 }
529
530 /*!
531  * Deallocate a vrequest.
532  *
533  * \note The GLOCK must be held on platforms which require the GLOCK
534  *       for osi_FreeSmallSpace().
535  *
536  * \param[in]  av  pointer to the vrequest to free; may be NULL
537  */
538 void
539 afs_DestroyReq(struct vrequest *av)
540 {
541     if (av) {
542         osi_FreeSmallSpace(av);
543     }
544 }
545
546 afs_uint32
547 afs_get_pag_from_groups(gid_t g0a, gid_t g1a)
548 {
549     afs_uint32 g0 = g0a;
550     afs_uint32 g1 = g1a;
551     afs_uint32 h, l, ret;
552
553     AFS_STATCNT(afs_get_pag_from_groups);
554
555     g0 -= 0x3f00;
556     g1 -= 0x3f00;
557     if (g0 < 0xc000 && g1 < 0xc000) {
558         l = ((g0 & 0x3fff) << 14) | (g1 & 0x3fff);
559         h = (g0 >> 14);
560         h = (g1 >> 14) + h + h + h;
561         ret = ((h << 28) | l);
562 # if defined(UKERNEL)
563         return ret;
564 # else
565         /* Additional testing */
566         if (((ret >> 24) & 0xff) == 'A')
567             return ret;
568 # endif /* UKERNEL */
569     }
570     return NOPAG;
571 }
572
573 #ifndef AFS_PAG_ONEGROUP_ENV
574 void
575 afs_get_groups_from_pag(afs_uint32 pag, gid_t * g0p, gid_t * g1p)
576 {
577     unsigned short g0, g1;
578
579     AFS_STATCNT(afs_get_groups_from_pag);
580     *g0p = pag;
581     *g1p = 0;
582 # if !defined(UKERNEL)
583     pag &= 0x7fffffff;
584 # endif /* UKERNEL */
585     g0 = 0x3fff & (pag >> 14);
586     g1 = 0x3fff & pag;
587     g0 |= ((pag >> 28) / 3) << 14;
588     g1 |= ((pag >> 28) % 3) << 14;
589     *g0p = g0 + 0x3f00;
590     *g1p = g1 + 0x3f00;
591 }
592 #else
593 void
594 afs_get_groups_from_pag(afs_uint32 pag, gid_t *g0p, gid_t *g1p)
595 {
596     AFS_STATCNT(afs_get_groups_from_pag);
597     *g0p = pag;
598     *g1p = 0;
599 }
600 #endif
601
602 #ifdef AFS_LINUX26_ENV
603 /* osi_get_group_pag is defined in <ARCH>/osi_groups.c */
604 #elif defined(AFS_PAG_ONEGROUP_ENV)
605 /* osi_get_group_pag is defined in <ARCH>/osi_groups.c */
606 #elif defined(AFS_DARWIN110_ENV)
607 /* We don't have pags, so we do not define an osi_get_group_pag */
608 #else
609 static afs_int32
610 osi_get_group_pag(afs_ucred_t *cred)
611 {
612     afs_int32 pag = NOPAG;
613     gid_t g0, g1;
614 #if defined(AFS_SUN510_ENV)
615     const gid_t *gids;
616     int ngroups;
617 #endif
618
619 #if defined(AFS_SUN510_ENV)
620     gids = crgetgroups(cred);
621     ngroups = crgetngroups(cred);
622 #endif
623 #if defined(AFS_NBSD40_ENV)
624     if (cred == NOCRED || cred == FSCRED)
625       return NOPAG;
626     if (osi_crngroups(cred) < 3)
627       return NOPAG;
628     g0 = osi_crgroupbyid(cred, 1);
629     g1 = osi_crgroupbyid(cred, 2);
630 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
631     if (cred == NOCRED || cred == FSCRED)
632         return NOPAG;
633     if (cred->cr_ngroups < 3)
634         return NOPAG;
635     /* gid is stored in cr_groups[0] */
636     g0 = cred->cr_groups[1];
637     g1 = cred->cr_groups[2];
638 #else
639 # if defined(AFS_AIX_ENV)
640     if (cred->cr_ngrps < 2)
641         return NOPAG;
642 # elif defined(AFS_LINUX26_ENV)
643     if (afs_cr_group_info(cred)->ngroups < AFS_NUMPAGGROUPS)
644         return NOPAG;
645 # elif defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_XBSD_ENV)
646 #  if defined(AFS_SUN510_ENV)
647     if (ngroups < 2) {
648 #  else
649     if (cred->cr_ngroups < 2) {
650 #  endif
651         return NOPAG;
652     }
653 # endif
654 # if defined(AFS_AIX51_ENV)
655     g0 = cred->cr_groupset.gs_union.un_groups[0];
656     g1 = cred->cr_groupset.gs_union.un_groups[1];
657 #elif defined(AFS_SUN510_ENV)
658     g0 = gids[0];
659     g1 = gids[1];
660 #else
661     g0 = cred->cr_groups[0];
662     g1 = cred->cr_groups[1];
663 #endif
664 #endif
665     pag = (afs_int32) afs_get_pag_from_groups(g0, g1);
666     return pag;
667 }
668 #endif
669
670
671 afs_int32
672 PagInCred(afs_ucred_t *cred)
673 {
674     afs_int32 pag = NOPAG;
675
676     AFS_STATCNT(PagInCred);
677     if (cred == NULL || cred == afs_osi_credp) {
678         return NOPAG;
679     }
680 #ifndef AFS_DARWIN110_ENV
681 #if defined(AFS_LINUX26_ENV) && defined(LINUX_KEYRING_SUPPORT)
682     /*
683      * If linux keyrings are in use and we carry the session keyring in our credentials
684      * structure, they should be the only criteria for determining
685      * if we're in a PAG.  Groups are updated for legacy reasons only for now,
686      * and should not be used to infer PAG membership
687      * With keyrings but no kernel credentials, look at groups first and fall back
688      * to looking at the keyrings.
689      */
690 # if !defined(STRUCT_TASK_STRUCT_HAS_CRED)
691     pag = osi_get_group_pag(cred);
692 # endif
693     if (pag == NOPAG)
694         pag = osi_get_keyring_pag(cred);
695 #elif defined(AFS_AIX51_ENV)
696     if (kcred_getpag(cred, PAG_AFS, &pag) < 0 || pag == 0)
697         pag = NOPAG;
698 #else
699     pag = osi_get_group_pag(cred);
700 #endif
701 #endif
702     return pag;
703 }