openbsd-20030417
[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) return code;
61
62     code = setgroups(p, args, retval);
63     /* Note that if there is a pag already in the new groups we don't
64      * overwrite it with the old pag.
65      */
66     if (PagInCred(osi_curcred()) == NOPAG) {
67         if (((treq.uid >> 24) & 0xff) == 'A') {
68             AFS_GLOCK();
69             /* we've already done a setpag, so now we redo it */
70             AddPag(p, treq.uid, &p->p_rcred);
71             AFS_GUNLOCK();
72         }
73     }
74     return code;
75 }
76
77
78 int
79 setpag(struct proc *proc, struct ucred **cred, afs_uint32 pagvalue,
80        afs_uint32 *newpag, int 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[1], gidset[2]) == 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[1], &gidset[2]);
100     code = afs_setgroups(proc, cred, ngroups, gidset, change_parent);
101     return code;
102 }
103
104
105 static int
106 afs_getgroups(
107     struct ucred *cred,
108     int ngroups,
109     gid_t *gidset)
110 {
111     int ngrps, savengrps;
112     gid_t *gp;
113
114     AFS_STATCNT(afs_getgroups);
115     savengrps = ngrps = MIN(ngroups, cred->cr_ngroups);
116     gp = cred->cr_groups;
117     while (ngrps--)
118         *gidset++ = *gp++;
119     return savengrps;
120 }
121
122
123
124 static int
125 afs_setgroups(
126     struct proc *proc,
127     struct ucred **cred,
128     int ngroups,
129     gid_t *gidset,
130     int change_parent)
131 {
132     gid_t *gp;
133     struct ucred *newcr, *cr;
134
135     AFS_STATCNT(afs_setgroups);
136     /*
137      * The real setgroups() call does this, so maybe we should too.
138      *
139      */
140     if (ngroups > NGROUPS)
141         return EINVAL;
142     cr = *cred;
143     if (!change_parent) {
144         crhold(cr);
145         newcr = crcopy(cr);
146     } else
147         newcr = cr;
148     newcr->cr_ngroups = ngroups;
149     gp = newcr->cr_groups;
150     while (ngroups--)
151         *gp++ = *gidset++;
152     for ( ; gp < &(*cred)->cr_groups[NGROUPS]; gp++)
153         *gp = NOGROUP;
154     *cred = newcr;
155     return(0);
156 }