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