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