solaris-p-crlock-not-safe-to-hold-across-call-to-crset-20020206
[openafs.git] / src / afs / SOLARIS / 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  * setgroups (syscall)
13  * setpag
14  *
15  */
16 #include <afsconfig.h>
17 #include "../afs/param.h"
18
19 RCSID("$Header$");
20
21 #include "../afs/sysincludes.h"
22 #include "../afs/afsincludes.h"
23 #include "../afs/afs_stats.h"  /* statistics */
24
25
26 static int
27 afs_getgroups(
28     struct cred *cred,
29     gid_t *gidset);
30
31 static int
32 afs_setgroups(
33     struct cred **cred,
34     int ngroups,
35     gid_t *gidset,
36     int change_parent);
37
38
39 #if     defined(AFS_SUN55_ENV)
40 int
41 afs_xsetgroups(uap, rvp)
42 u_int uap; /* this is gidsetsize */
43 gid_t *rvp; /* this is gidset */
44 #else 
45 struct setgroupsa {
46     u_int gidsetsize;
47     gid_t *gidset;
48 };
49
50 afs_xsetgroups(uap, rvp) 
51     struct setgroupsa *uap;
52     rval_t *rvp;
53 #endif
54 {
55     int code = 0;
56     struct vrequest treq;
57     struct proc *proc = ttoproc(curthread);
58
59     AFS_STATCNT(afs_xsetgroups);
60     AFS_GLOCK();
61     code = afs_InitReq(&treq, proc->p_cred);
62     AFS_GUNLOCK();
63     if (code) return code;
64     code = setgroups(uap, rvp);
65
66     /* Note that if there is a pag already in the new groups we don't
67      * overwrite it with the old pag.
68      */
69     if (PagInCred(proc->p_cred) == NOPAG) {
70         if (((treq.uid >> 24) & 0xff) == 'A') {
71             AFS_GLOCK();
72             /* we've already done a setpag, so now we redo it */
73             AddPag(treq.uid, &proc->p_cred);
74             AFS_GUNLOCK();
75         }
76     }
77     return code;
78 }
79
80 int
81 setpag(cred, pagvalue, newpag, change_parent)
82     struct cred **cred;
83     afs_uint32 pagvalue;
84     afs_uint32 *newpag;
85     afs_uint32 change_parent;
86 {
87     gid_t *gidset;
88     int ngroups, code;
89     int j;
90
91     AFS_STATCNT(setpag);
92
93     gidset = (gid_t *) osi_AllocSmallSpace(AFS_SMALLOCSIZ);
94
95     mutex_enter(&curproc->p_crlock);
96     ngroups = afs_getgroups(*cred, gidset);
97
98     if (afs_get_pag_from_groups(gidset[0], gidset[1]) == NOPAG) {
99         /* We will have to shift grouplist to make room for pag */
100         if ((sizeof gidset[0])*(ngroups + 2) > AFS_SMALLOCSIZ) {
101             osi_FreeSmallSpace((char *)gidset);
102             return (E2BIG);
103         }
104         for (j = ngroups -1; j >= 0; j--) {
105             gidset[j+2] = gidset[j];
106         }
107         ngroups += 2;
108     }
109     *newpag = (pagvalue == -1 ? genpag(): pagvalue);
110     afs_get_groups_from_pag(*newpag, &gidset[0], &gidset[1]);
111     /* afs_setgroups will release curproc->p_crlock */
112     if (code = afs_setgroups(cred, ngroups, gidset, change_parent)) {
113         osi_FreeSmallSpace((char *)gidset);
114         return (code);
115     }
116     osi_FreeSmallSpace((char *)gidset);
117     return code;
118 }
119
120
121 static int
122 afs_getgroups(
123     struct cred *cred,
124     gid_t *gidset)
125 {
126     int ngrps, savengrps;
127     gid_t *gp;
128
129     AFS_STATCNT(afs_getgroups);
130
131     gidset[0] = gidset[1] = 0;
132     savengrps = ngrps = cred->cr_ngroups;
133     gp = cred->cr_groups;
134     while (ngrps--)
135         *gidset++ = *gp++;   
136     return savengrps;
137 }
138
139
140
141 static int
142 afs_setgroups(
143     struct cred **cred,
144     int ngroups,
145     gid_t *gidset,
146     int change_parent)
147 {
148     int ngrps;
149     int i;
150     gid_t *gp;
151
152     AFS_STATCNT(afs_setgroups);
153
154     if (ngroups > ngroups_max) {
155         mutex_exit(&curproc->p_crlock);
156         return EINVAL;
157     }
158     if (!change_parent)
159         *cred = (struct cred *)crcopy(*cred);
160     (*cred)->cr_ngroups = ngroups;
161     gp = (*cred)->cr_groups;
162     while (ngroups--)
163         *gp++ = *gidset++;
164     mutex_exit(&curproc->p_crlock);
165     if (!change_parent)
166         crset(curproc, *cred); /* broadcast to all threads */
167     return (0);
168 }