e3cd3c442547fdd3ce22aef0b08555dd158ec79c
[openafs.git] / src / afs / DUX / 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  * Implements:
12  * Afs_xsetgroups (syscall)
13  * setpag
14  *
15  */
16 #include "../afs/param.h"
17 #include "../afs/sysincludes.h"
18 #include "../afs/afsincludes.h"
19 #include "../afs/afs_stats.h"  /* statistics */
20
21 static int
22 afs_getgroups(
23     struct ucred *cred,
24     int ngroups,
25     gid_t *gidset);
26
27 static int
28 afs_setgroups(
29     struct proc *proc,
30     struct ucred **cred,
31     int ngroups,
32     gid_t *gidset,
33     int change_parent);
34
35 int
36 Afs_xsetgroups(p, args, retval)
37     struct proc *p;
38     void *args;
39     int *retval;
40 {
41     int code = 0;
42     struct vrequest treq;
43
44     AFS_STATCNT(afs_xsetgroups);
45     AFS_GLOCK();
46
47     code = afs_InitReq(&treq, u.u_cred);
48     AFS_GUNLOCK();
49     if (code) return code;
50
51     code = setgroups(p, args, retval);
52     /* Note that if there is a pag already in the new groups we don't
53      * overwrite it with the old pag.
54      */
55     if (PagInCred(u.u_cred) == NOPAG) {
56         if (((treq.uid >> 24) & 0xff) == 'A') {
57             AFS_GLOCK();
58             /* we've already done a setpag, so now we redo it */
59             AddPag(p, treq.uid, &p->p_rcred);
60             AFS_GUNLOCK();
61         }
62     }
63     return code;
64 }
65
66
67 int
68 setpag(proc, cred, pagvalue, newpag, change_parent)
69     struct proc *proc;
70     struct ucred **cred;
71     afs_uint32 pagvalue;
72     afs_uint32 *newpag;
73     afs_uint32 change_parent;
74 {
75     gid_t gidset[NGROUPS];
76     int ngroups, code;
77     int j;
78
79     AFS_STATCNT(setpag);
80     ngroups = afs_getgroups(*cred, NGROUPS, gidset);
81     if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
82         /* We will have to shift grouplist to make room for pag */
83         if (ngroups + 2 > NGROUPS) {
84             return (E2BIG);
85         }
86         for (j = ngroups -1; j >= 0; j--) {
87             gidset[j+2] = gidset[j];
88         }
89         ngroups += 2;
90     }
91     *newpag = (pagvalue == -1 ? genpag(): pagvalue);
92     afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
93     code = afs_setgroups(proc, cred, ngroups, gidset, change_parent);
94     return code;
95 }
96
97
98 static int
99 afs_getgroups(
100     struct ucred *cred,
101     int ngroups,
102     gid_t *gidset)
103 {
104     int ngrps, savengrps;
105     gid_t *gp;
106
107     AFS_STATCNT(afs_getgroups);
108     savengrps = ngrps = MIN(ngroups, cred->cr_ngroups);
109     gp = cred->cr_groups;
110     while (ngrps--)
111         *gidset++ = *gp++;   
112     return savengrps;
113 }
114
115
116
117 static int
118 afs_setgroups(
119     struct proc *proc,
120     struct ucred **cred,
121     int ngroups,
122     gid_t *gidset,
123     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 }