ac0d24c8213ad671a365fd2b6d1e6b6163d44654
[openafs.git] / src / afs / NBSD / osi_groups.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  * osi_groups.c
12  *
13  * Implements:
14  * Afs_xsetgroups (syscall)
15  * setpag
16  *
17  */
18 #include <afsconfig.h>
19 #include "afs/param.h"
20
21 RCSID
22     ("$Header$");
23
24 #include "afs/sysincludes.h"
25 #include "afsincludes.h"
26 #include "afs/afs_stats.h"      /* statistics */
27
28 #define NOCRED  ((struct ucred *) -1)
29 #define NOUID   ((uid_t) -1)
30 #define NOGID   ((gid_t) -1)
31
32
33 static int
34   afs_getgroups(struct ucred *cred, int ngroups, gid_t * gidset);
35
36 static int
37   afs_setgroups(struct proc *proc, struct ucred **cred, int ngroups,
38                 gid_t * gidset, int change_parent);
39
40 int
41 Afs_xsetgroups(p, args, retval)
42      struct proc *p;
43      void *args;
44      int *retval;
45 {
46     int code = 0;
47     struct vrequest treq;
48
49     AFS_STATCNT(afs_xsetgroups);
50     AFS_GLOCK();
51
52     /*    code = afs_InitReq(&treq, u.u_cred); */
53     code = afs_InitReq(&treq, curproc->p_cred->pc_ucred);
54     AFS_GUNLOCK();
55     if (code)
56         return code;
57
58     code = setgroups(p, args, retval);
59     /* Note that if there is a pag already in the new groups we don't
60      * overwrite it with the old pag.
61      */
62     if (PagInCred(curproc->p_cred->pc_ucred) == NOPAG) {
63         if (((treq.uid >> 24) & 0xff) == 'A') {
64             AFS_GLOCK();
65             /* we've already done a setpag, so now we redo it */
66             AddPag(p, treq.uid, &p->p_rcred);
67             AFS_GUNLOCK();
68         }
69     }
70     return code;
71 }
72
73
74 int
75 setpag(proc, cred, pagvalue, newpag, change_parent)
76      struct proc *proc;
77      struct ucred **cred;
78      afs_uint32 pagvalue;
79      afs_uint32 *newpag;
80      afs_uint32 change_parent;
81 {
82     gid_t gidset[NGROUPS];
83     int ngroups, code;
84     int j;
85
86     AFS_STATCNT(setpag);
87     ngroups = afs_getgroups(*cred, NGROUPS, gidset);
88     if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
89         /* We will have to shift grouplist to make room for pag */
90         if (ngroups + 2 > NGROUPS) {
91             return (E2BIG);
92         }
93         for (j = ngroups - 1; j >= 0; j--) {
94             gidset[j + 2] = gidset[j];
95         }
96         ngroups += 2;
97     }
98     *newpag = (pagvalue == -1 ? genpag() : pagvalue);
99     afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
100     code = afs_setgroups(proc, cred, ngroups, gidset, change_parent);
101     return code;
102 }
103
104
105 static int
106 afs_getgroups(struct ucred *cred, int ngroups, gid_t * gidset)
107 {
108     int ngrps, savengrps;
109     gid_t *gp;
110
111     AFS_STATCNT(afs_getgroups);
112     savengrps = ngrps = MIN(ngroups, cred->cr_ngroups);
113     gp = cred->cr_groups;
114     while (ngrps--)
115         *gidset++ = *gp++;
116     return savengrps;
117 }
118
119
120
121 static int
122 afs_setgroups(struct proc *proc, struct ucred **cred, int ngroups,
123               gid_t * gidset, int change_parent)
124 {
125     int ngrps;
126     int i;
127     gid_t *gp;
128     struct ucred *newcr, *cr;
129
130     AFS_STATCNT(afs_setgroups);
131     /*
132      * The real setgroups() call does this, so maybe we should too.
133      *
134      */
135     if (ngroups > NGROUPS)
136         return EINVAL;
137     cr = *cred;
138     if (!change_parent) {
139         crhold(cr);
140         newcr = crcopy(cr);
141     } else
142         newcr = cr;
143     newcr->cr_ngroups = ngroups;
144     gp = newcr->cr_groups;
145     while (ngroups--)
146         *gp++ = *gidset++;
147     if (!change_parent) {
148         substitute_real_creds(proc, NOUID, NOUID, NOGID, NOGID, newcr);
149     }
150     *cred = newcr;
151     return (0);
152 }