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