1 /* Copyright (C) 1991-2021 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
_hurd_refport_secure_p(mach_port_t ref)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
_S_msg_add_auth(mach_port_t me,auth_t addauth)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   make_list (&new ## genaux ## uidgid ## s, 				    \
106 	     &nnew ## genaux ## uidgid ## s,				    \
107 	     _hurd_id.genaux.uidgid ## s,				    \
108 	     _hurd_id.genaux.n ## uidgid ## s,				    \
109 	     genaux ## uidgid ## s,					    \
110 	     n ## genaux ## uidgid ## s)
111 
112   err = MAKE (gen, uid);
113   if (!err)
114     MAKE (aux, uid);
115   if (!err)
116     MAKE (gen, gid);
117   if (!err)
118     MAKE (aux, gid);
119 #undef MAKE
120 
121   __mutex_unlock (&_hurd_id.lock);
122   HURD_CRITICAL_END;
123 
124 
125   /* Create the new auth port */
126 
127   if (!err)
128     err = __USEPORT (AUTH,
129 		     __auth_makeauth (port,
130 				      &addauth, MACH_MSG_TYPE_MOVE_SEND, 1,
131 				      newgenuids, nnewgenuids,
132 				      newauxuids, nnewauxuids,
133 				      newgengids, nnewgengids,
134 				      newauxgids, nnewauxgids,
135 				      &newauth));
136 
137 #define freeup(array, len) \
138   if (array) \
139     __vm_deallocate (mach_task_self (), (vm_address_t) array, \
140 		     len * sizeof (uid_t));
141 
142   freeup (genuids, ngenuids);
143   freeup (auxuids, nauxuids);
144   freeup (gengids, ngengids);
145   freeup (auxgids, nauxgids);
146   freeup (newgenuids, nnewgenuids);
147   freeup (newauxuids, nnewauxuids);
148   freeup (newgengids, nnewgengids);
149   freeup (newauxgids, nnewauxgids);
150 #undef freeup
151 
152   if (err)
153     return err;
154 
155   /* And install it. */
156 
157   err = __setauth (newauth);
158   __mach_port_deallocate (__mach_task_self (), newauth);
159   if (err)
160     return errno;
161 
162   return 0;
163 }
164 
165 kern_return_t
_S_msg_del_auth(mach_port_t me,task_t task,intarray_t uids,mach_msg_type_number_t nuids,intarray_t gids,mach_msg_type_number_t ngids)166 _S_msg_del_auth (mach_port_t me,
167 		 task_t task,
168 		 intarray_t uids, mach_msg_type_number_t nuids,
169 		 intarray_t gids, mach_msg_type_number_t ngids)
170 {
171   error_t err;
172   auth_t newauth;
173 
174   if (!_hurd_refport_secure_p (task))
175     return EPERM;
176 
177   HURD_CRITICAL_BEGIN;
178   __mutex_lock (&_hurd_id.lock);
179   err = _hurd_check_ids ();
180 
181   if (!err)
182     {
183       size_t i, j;
184       size_t nu = _hurd_id.gen.nuids, ng = _hurd_id.gen.ngids;
185       uid_t newu[nu];
186       gid_t newg[ng];
187 
188       memcpy (newu, _hurd_id.gen.uids, nu * sizeof (uid_t));
189       memcpy (newg, _hurd_id.gen.gids, ng * sizeof (gid_t));
190 
191       for (j = 0; j < nuids; ++j)
192 	{
193 	  const uid_t uid = uids[j];
194 	  for (i = 0; i < nu; ++i)
195 	    if (newu[i] == uid)
196 	      /* Move the last uid into this slot, and decrease the
197 		 number of uids so the last slot is no longer used.  */
198 	      newu[i] = newu[--nu];
199 	}
200       __vm_deallocate (__mach_task_self (),
201 		       (vm_address_t) uids, nuids * sizeof (uid_t));
202 
203       for (j = 0; j < ngids; ++j)
204 	{
205 	  const gid_t gid = gids[j];
206 	  for (i = 0; i < nu; ++i)
207 	    if (newu[i] == gid)
208 	      /* Move the last gid into this slot, and decrease the
209 		 number of gids so the last slot is no longer used.  */
210 	      newu[i] = newu[--nu];
211 	}
212       __vm_deallocate (__mach_task_self (),
213 		       (vm_address_t) gids, ngids * sizeof (gid_t));
214 
215       err = __USEPORT (AUTH, __auth_makeauth
216 		       (port,
217 			NULL, MACH_MSG_TYPE_COPY_SEND, 0,
218 			newu, nu,
219 			_hurd_id.aux.uids, _hurd_id.aux.nuids,
220 			newg, ng,
221 			_hurd_id.aux.uids, _hurd_id.aux.ngids,
222 			&newauth));
223     }
224   __mutex_unlock (&_hurd_id.lock);
225   HURD_CRITICAL_END;
226 
227   if (err)
228     return err;
229 
230   err = __setauth (newauth);
231   __mach_port_deallocate (__mach_task_self (), newauth);
232   if (err)
233     return errno;
234 
235   return 0;
236 }
237