1 | /* Copyright (C) 1991-2024 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | #include <hurd.h> |
19 | #include <hurd/msg_server.h> |
20 | #include <hurd/id.h> |
21 | #include <string.h> |
22 | |
23 | int |
24 | _hurd_refport_secure_p (mach_port_t ref) |
25 | { |
26 | if (ref == __mach_task_self ()) |
27 | return 1; |
28 | if (__USEPORT (AUTH, ref == port)) |
29 | return 1; |
30 | return 0; |
31 | } |
32 | |
33 | kern_return_t |
34 | _S_msg_add_auth (mach_port_t me, |
35 | auth_t addauth) |
36 | { |
37 | error_t err; |
38 | auth_t newauth; |
39 | uid_t *genuids, *gengids, *auxuids, *auxgids; |
40 | mach_msg_type_number_t ngenuids, ngengids, nauxuids, nauxgids; |
41 | uid_t *newgenuids, *newgengids, *newauxuids, *newauxgids; |
42 | mach_msg_type_number_t nnewgenuids, nnewgengids, nnewauxuids, nnewauxgids; |
43 | |
44 | /* Create a list of ids and store it in NEWLISTP, length NEWLISTLEN. |
45 | Keep all the ids in EXIST (len NEXIST), adding in those from NEW |
46 | (len NNEW) which are not already there. */ |
47 | error_t make_list (uid_t **newlistp, mach_msg_type_number_t *newlistlen, |
48 | uid_t *exist, mach_msg_type_number_t nexist, |
49 | uid_t *new, mach_msg_type_number_t nnew) |
50 | { |
51 | error_t urp; |
52 | int i, j, k; |
53 | vm_size_t offset; |
54 | |
55 | urp = __vm_allocate (mach_task_self (), (vm_address_t *) newlistp, |
56 | nexist + nnew * sizeof (uid_t), 1); |
57 | if (urp) |
58 | return urp; |
59 | |
60 | j = 0; |
61 | for (i = 0; i < nexist; i++) |
62 | (*newlistp)[j++] = exist[i]; |
63 | |
64 | for (i = 0; i < nnew; i++) |
65 | { |
66 | for (k = 0; k < nexist; k++) |
67 | if (exist[k] == new[i]) |
68 | break; |
69 | if (k < nexist) |
70 | continue; |
71 | |
72 | (*newlistp)[j++] = new[i]; |
73 | } |
74 | |
75 | offset = (round_page (nexist + nnew * sizeof (uid_t)) |
76 | - round_page (j * sizeof (uid_t))); |
77 | if (offset) |
78 | __vm_deallocate (mach_task_self (), |
79 | (vm_address_t) (*newlistp |
80 | + (nexist + nnew * sizeof (uid_t))), |
81 | offset); |
82 | *newlistlen = j; |
83 | return 0; |
84 | } |
85 | |
86 | /* Find out what ids ADDAUTH refers to */ |
87 | |
88 | genuids = gengids = auxuids = auxgids = 0; |
89 | ngenuids = ngengids = nauxuids = nauxgids = 0; |
90 | err = __auth_getids (addauth, |
91 | &genuids, &ngenuids, |
92 | &auxuids, &nauxuids, |
93 | &gengids, &ngengids, |
94 | &auxgids, &nauxgids); |
95 | if (err) |
96 | return err; |
97 | |
98 | /* OR in these ids to what we already have, creating a new list. */ |
99 | |
100 | HURD_CRITICAL_BEGIN; |
101 | __mutex_lock (&_hurd_id.lock); |
102 | _hurd_check_ids (); |
103 | |
104 | #define MAKE(genaux,uidgid) ({ \ |
105 | new ## genaux ## uidgid ## s = 0; \ |
106 | nnew ## genaux ## uidgid ## s = 0; \ |
107 | make_list (&new ## genaux ## uidgid ## s, \ |
108 | &nnew ## genaux ## uidgid ## s, \ |
109 | _hurd_id.genaux.uidgid ## s, \ |
110 | _hurd_id.genaux.n ## uidgid ## s, \ |
111 | genaux ## uidgid ## s, \ |
112 | n ## genaux ## uidgid ## s); \ |
113 | }) |
114 | |
115 | err = MAKE (gen, uid); |
116 | if (!err) |
117 | err = MAKE (aux, uid); |
118 | if (!err) |
119 | err = MAKE (gen, gid); |
120 | if (!err) |
121 | err = MAKE (aux, gid); |
122 | #undef MAKE |
123 | |
124 | __mutex_unlock (&_hurd_id.lock); |
125 | HURD_CRITICAL_END; |
126 | |
127 | |
128 | /* Create the new auth port */ |
129 | |
130 | if (!err) |
131 | err = __USEPORT (AUTH, |
132 | __auth_makeauth (port, |
133 | &addauth, MACH_MSG_TYPE_MOVE_SEND, 1, |
134 | newgenuids, nnewgenuids, |
135 | newauxuids, nnewauxuids, |
136 | newgengids, nnewgengids, |
137 | newauxgids, nnewauxgids, |
138 | &newauth)); |
139 | |
140 | #define freeup(array, len) \ |
141 | if (array) \ |
142 | __vm_deallocate (mach_task_self (), (vm_address_t) array, \ |
143 | len * sizeof (uid_t)); |
144 | |
145 | freeup (genuids, ngenuids); |
146 | freeup (auxuids, nauxuids); |
147 | freeup (gengids, ngengids); |
148 | freeup (auxgids, nauxgids); |
149 | freeup (newgenuids, nnewgenuids); |
150 | freeup (newauxuids, nnewauxuids); |
151 | freeup (newgengids, nnewgengids); |
152 | freeup (newauxgids, nnewauxgids); |
153 | #undef freeup |
154 | |
155 | if (err) |
156 | return err; |
157 | |
158 | /* And install it. */ |
159 | |
160 | err = __setauth (newauth); |
161 | __mach_port_deallocate (__mach_task_self (), newauth); |
162 | if (err) |
163 | return errno; |
164 | |
165 | return 0; |
166 | } |
167 | |
168 | kern_return_t |
169 | _S_msg_del_auth (mach_port_t me, |
170 | task_t task, |
171 | const_intarray_t uids, mach_msg_type_number_t nuids, |
172 | const_intarray_t gids, mach_msg_type_number_t ngids) |
173 | { |
174 | error_t err; |
175 | auth_t newauth; |
176 | |
177 | if (!_hurd_refport_secure_p (task)) |
178 | return EPERM; |
179 | |
180 | HURD_CRITICAL_BEGIN; |
181 | __mutex_lock (&_hurd_id.lock); |
182 | err = _hurd_check_ids (); |
183 | |
184 | if (!err) |
185 | { |
186 | size_t i, j; |
187 | size_t nu = _hurd_id.gen.nuids, ng = _hurd_id.gen.ngids; |
188 | uid_t newu[nu]; |
189 | gid_t newg[ng]; |
190 | |
191 | memcpy (dest: newu, src: _hurd_id.gen.uids, n: nu * sizeof (uid_t)); |
192 | memcpy (dest: newg, src: _hurd_id.gen.gids, n: ng * sizeof (gid_t)); |
193 | |
194 | for (j = 0; j < nuids; ++j) |
195 | { |
196 | const uid_t uid = uids[j]; |
197 | for (i = 0; i < nu; ++i) |
198 | if (newu[i] == uid) |
199 | /* Move the last uid into this slot, and decrease the |
200 | number of uids so the last slot is no longer used. */ |
201 | newu[i] = newu[--nu]; |
202 | } |
203 | __vm_deallocate (__mach_task_self (), |
204 | (vm_address_t) uids, nuids * sizeof (uid_t)); |
205 | |
206 | for (j = 0; j < ngids; ++j) |
207 | { |
208 | const gid_t gid = gids[j]; |
209 | for (i = 0; i < nu; ++i) |
210 | if (newu[i] == gid) |
211 | /* Move the last gid into this slot, and decrease the |
212 | number of gids so the last slot is no longer used. */ |
213 | newu[i] = newu[--nu]; |
214 | } |
215 | __vm_deallocate (__mach_task_self (), |
216 | (vm_address_t) gids, ngids * sizeof (gid_t)); |
217 | |
218 | err = __USEPORT (AUTH, __auth_makeauth |
219 | (port, |
220 | NULL, MACH_MSG_TYPE_COPY_SEND, 0, |
221 | newu, nu, |
222 | _hurd_id.aux.uids, _hurd_id.aux.nuids, |
223 | newg, ng, |
224 | _hurd_id.aux.uids, _hurd_id.aux.ngids, |
225 | &newauth)); |
226 | } |
227 | __mutex_unlock (&_hurd_id.lock); |
228 | HURD_CRITICAL_END; |
229 | |
230 | if (err) |
231 | return err; |
232 | |
233 | err = __setauth (newauth); |
234 | __mach_port_deallocate (__mach_task_self (), newauth); |
235 | if (err) |
236 | return errno; |
237 | |
238 | return 0; |
239 | } |
240 | |