1 | /** |
---|
2 | * @file |
---|
3 | * |
---|
4 | * @ingroup rtems_bsd_rtems |
---|
5 | * |
---|
6 | * @brief TODO. |
---|
7 | */ |
---|
8 | |
---|
9 | /* |
---|
10 | * Copyright (c) 2009, 2010 embedded brains GmbH. All rights reserved. |
---|
11 | * |
---|
12 | * embedded brains GmbH |
---|
13 | * Obere Lagerstr. 30 |
---|
14 | * 82178 Puchheim |
---|
15 | * Germany |
---|
16 | * <rtems@embedded-brains.de> |
---|
17 | * |
---|
18 | * The license and distribution terms for this file may be |
---|
19 | * found in the file LICENSE in this distribution or at |
---|
20 | * http://www.rtems.com/license/LICENSE. |
---|
21 | */ |
---|
22 | |
---|
23 | #include <rtems/freebsd/machine/rtems-bsd-config.h> |
---|
24 | |
---|
25 | #include <rtems/freebsd/sys/types.h> |
---|
26 | #include <rtems/freebsd/sys/systm.h> |
---|
27 | #include <rtems/freebsd/vm/uma.h> |
---|
28 | #include <rtems/freebsd/sys/malloc.h> |
---|
29 | #include <rtems/freebsd/sys/ucred.h> |
---|
30 | #include <rtems/freebsd/sys/refcount.h> |
---|
31 | |
---|
32 | static MALLOC_DEFINE(M_CRED, "cred", "credentials"); |
---|
33 | |
---|
34 | static void crextend(struct ucred *cr, int n); |
---|
35 | static void crsetgroups_locked(struct ucred *cr, int ngrp, |
---|
36 | gid_t *groups); |
---|
37 | |
---|
38 | |
---|
39 | |
---|
40 | /* |
---|
41 | * Allocate a zeroed cred structure. |
---|
42 | */ |
---|
43 | struct ucred * |
---|
44 | crget(void) |
---|
45 | { |
---|
46 | register struct ucred *cr; |
---|
47 | |
---|
48 | cr = malloc(sizeof(*cr), M_CRED, M_WAITOK | M_ZERO); |
---|
49 | refcount_init(&cr->cr_ref, 1); |
---|
50 | #ifdef AUDIT |
---|
51 | audit_cred_init(cr); |
---|
52 | #endif |
---|
53 | #ifdef MAC |
---|
54 | mac_cred_init(cr); |
---|
55 | #endif |
---|
56 | crextend(cr, XU_NGROUPS); |
---|
57 | return (cr); |
---|
58 | } |
---|
59 | |
---|
60 | /* |
---|
61 | * Claim another reference to a ucred structure. |
---|
62 | */ |
---|
63 | struct ucred * |
---|
64 | crhold(struct ucred *cr) |
---|
65 | { |
---|
66 | |
---|
67 | refcount_acquire(&cr->cr_ref); |
---|
68 | return (cr); |
---|
69 | } |
---|
70 | |
---|
71 | /* |
---|
72 | * Free a cred structure. Throws away space when ref count gets to 0. |
---|
73 | */ |
---|
74 | void |
---|
75 | crfree(struct ucred *cr) |
---|
76 | { |
---|
77 | |
---|
78 | KASSERT(cr->cr_ref > 0, ("bad ucred refcount: %d", cr->cr_ref)); |
---|
79 | KASSERT(cr->cr_ref != 0xdeadc0de, ("dangling reference to ucred")); |
---|
80 | if (refcount_release(&cr->cr_ref)) { |
---|
81 | /* |
---|
82 | * Some callers of crget(), such as nfs_statfs(), |
---|
83 | * allocate a temporary credential, but don't |
---|
84 | * allocate a uidinfo structure. |
---|
85 | */ |
---|
86 | if (cr->cr_uidinfo != NULL) |
---|
87 | uifree(cr->cr_uidinfo); |
---|
88 | if (cr->cr_ruidinfo != NULL) |
---|
89 | uifree(cr->cr_ruidinfo); |
---|
90 | /* |
---|
91 | * Free a prison, if any. |
---|
92 | */ |
---|
93 | if (cr->cr_prison != NULL) |
---|
94 | prison_free(cr->cr_prison); |
---|
95 | #ifdef AUDIT |
---|
96 | audit_cred_destroy(cr); |
---|
97 | #endif |
---|
98 | #ifdef MAC |
---|
99 | mac_cred_destroy(cr); |
---|
100 | #endif |
---|
101 | free(cr->cr_groups, M_CRED); |
---|
102 | free(cr, M_CRED); |
---|
103 | } |
---|
104 | } |
---|
105 | |
---|
106 | /* |
---|
107 | * Check to see if this ucred is shared. |
---|
108 | */ |
---|
109 | int |
---|
110 | crshared(struct ucred *cr) |
---|
111 | { |
---|
112 | |
---|
113 | return (cr->cr_ref > 1); |
---|
114 | } |
---|
115 | |
---|
116 | /* |
---|
117 | * Copy a ucred's contents from a template. Does not block. |
---|
118 | */ |
---|
119 | void |
---|
120 | crcopy(struct ucred *dest, struct ucred *src) |
---|
121 | { |
---|
122 | |
---|
123 | KASSERT(crshared(dest) == 0, ("crcopy of shared ucred")); |
---|
124 | bcopy(&src->cr_startcopy, &dest->cr_startcopy, |
---|
125 | (unsigned)((caddr_t)&src->cr_endcopy - |
---|
126 | (caddr_t)&src->cr_startcopy)); |
---|
127 | crsetgroups(dest, src->cr_ngroups, src->cr_groups); |
---|
128 | uihold(dest->cr_uidinfo); |
---|
129 | uihold(dest->cr_ruidinfo); |
---|
130 | prison_hold(dest->cr_prison); |
---|
131 | #ifdef AUDIT |
---|
132 | audit_cred_copy(src, dest); |
---|
133 | #endif |
---|
134 | #ifdef MAC |
---|
135 | mac_cred_copy(src, dest); |
---|
136 | #endif |
---|
137 | } |
---|
138 | |
---|
139 | /* |
---|
140 | * Dup cred struct to a new held one. |
---|
141 | */ |
---|
142 | struct ucred * |
---|
143 | crdup(struct ucred *cr) |
---|
144 | { |
---|
145 | struct ucred *newcr; |
---|
146 | |
---|
147 | newcr = crget(); |
---|
148 | crcopy(newcr, cr); |
---|
149 | return (newcr); |
---|
150 | } |
---|
151 | |
---|
152 | /* |
---|
153 | * Extend the passed in credential to hold n items. |
---|
154 | */ |
---|
155 | static void |
---|
156 | crextend(struct ucred *cr, int n) |
---|
157 | { |
---|
158 | int cnt; |
---|
159 | |
---|
160 | /* Truncate? */ |
---|
161 | if (n <= cr->cr_agroups) |
---|
162 | return; |
---|
163 | |
---|
164 | /* |
---|
165 | * We extend by 2 each time since we're using a power of two |
---|
166 | * allocator until we need enough groups to fill a page. |
---|
167 | * Once we're allocating multiple pages, only allocate as many |
---|
168 | * as we actually need. The case of processes needing a |
---|
169 | * non-power of two number of pages seems more likely than |
---|
170 | * a real world process that adds thousands of groups one at a |
---|
171 | * time. |
---|
172 | */ |
---|
173 | if ( n < PAGE_SIZE / sizeof(gid_t) ) { |
---|
174 | if (cr->cr_agroups == 0) |
---|
175 | cnt = MINALLOCSIZE / sizeof(gid_t); |
---|
176 | else |
---|
177 | cnt = cr->cr_agroups * 2; |
---|
178 | |
---|
179 | while (cnt < n) |
---|
180 | cnt *= 2; |
---|
181 | } else |
---|
182 | cnt = roundup2(n, PAGE_SIZE / sizeof(gid_t)); |
---|
183 | |
---|
184 | /* Free the old array. */ |
---|
185 | if (cr->cr_groups) |
---|
186 | free(cr->cr_groups, M_CRED); |
---|
187 | |
---|
188 | cr->cr_groups = malloc(cnt * sizeof(gid_t), M_CRED, M_WAITOK | M_ZERO); |
---|
189 | cr->cr_agroups = cnt; |
---|
190 | } |
---|
191 | |
---|
192 | /* |
---|
193 | * Copy groups in to a credential, preserving any necessary invariants. |
---|
194 | * Currently this includes the sorting of all supplemental gids. |
---|
195 | * crextend() must have been called before hand to ensure sufficient |
---|
196 | * space is available. |
---|
197 | */ |
---|
198 | static void |
---|
199 | crsetgroups_locked(struct ucred *cr, int ngrp, gid_t *groups) |
---|
200 | { |
---|
201 | int i; |
---|
202 | int j; |
---|
203 | gid_t g; |
---|
204 | |
---|
205 | KASSERT(cr->cr_agroups >= ngrp, ("cr_ngroups is too small")); |
---|
206 | |
---|
207 | bcopy(groups, cr->cr_groups, ngrp * sizeof(gid_t)); |
---|
208 | cr->cr_ngroups = ngrp; |
---|
209 | |
---|
210 | /* |
---|
211 | * Sort all groups except cr_groups[0] to allow groupmember to |
---|
212 | * perform a binary search. |
---|
213 | * |
---|
214 | * XXX: If large numbers of groups become common this should |
---|
215 | * be replaced with shell sort like linux uses or possibly |
---|
216 | * heap sort. |
---|
217 | */ |
---|
218 | for (i = 2; i < ngrp; i++) { |
---|
219 | g = cr->cr_groups[i]; |
---|
220 | for (j = i-1; j >= 1 && g < cr->cr_groups[j]; j--) |
---|
221 | cr->cr_groups[j + 1] = cr->cr_groups[j]; |
---|
222 | cr->cr_groups[j + 1] = g; |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | /* |
---|
227 | * Copy groups in to a credential after expanding it if required. |
---|
228 | * Truncate the list to (ngroups_max + 1) if it is too large. |
---|
229 | */ |
---|
230 | void |
---|
231 | crsetgroups(struct ucred *cr, int ngrp, gid_t *groups) |
---|
232 | { |
---|
233 | |
---|
234 | if (ngrp > ngroups_max + 1) |
---|
235 | ngrp = ngroups_max + 1; |
---|
236 | |
---|
237 | crextend(cr, ngrp); |
---|
238 | crsetgroups_locked(cr, ngrp, groups); |
---|
239 | } |
---|
240 | |
---|