1 /* Copyright (C) 1992-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/fd.h>
21 #include <unistd.h>
22 #include <limits.h>
23 #include <string.h>
24 #include <argz.h>
25 
26 
27 #define AUTHCHECK \
28   if (auth != mach_task_self () && ! __USEPORT (AUTH, port == auth)) \
29     return EPERM
30 
31 
32 /* Snarfing and frobbing the init ports.  */
33 
34 kern_return_t
_S_msg_get_init_port(mach_port_t msgport,mach_port_t auth,int which,mach_port_t * result,mach_msg_type_name_t * result_type)35   _S_msg_get_init_port (mach_port_t msgport, mach_port_t auth, int which,
36 			mach_port_t *result, mach_msg_type_name_t *result_type)
37 {
38   AUTHCHECK;
39   *result_type = MACH_MSG_TYPE_MOVE_SEND;
40   /* This function adds a new user reference for the *RESULT it gives back.
41      Our reply message uses a move-send right that consumes this reference.  */
42   return _hurd_ports_get (which, result);
43 }
44 
45 kern_return_t
_S_msg_set_init_port(mach_port_t msgport,mach_port_t auth,int which,mach_port_t port)46 _S_msg_set_init_port (mach_port_t msgport, mach_port_t auth,
47 		      int which, mach_port_t port)
48 {
49   error_t err;
50 
51   AUTHCHECK;
52 
53   err = _hurd_ports_set (which, port);
54   if (err == 0)
55     __mach_port_deallocate (__mach_task_self (), port);
56 
57   return 0;
58 }
59 
60 kern_return_t
_S_msg_get_init_ports(mach_port_t msgport,mach_port_t auth,mach_port_t ** ports,mach_msg_type_name_t * ports_type,mach_msg_type_number_t * nports)61 _S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth,
62 		       mach_port_t **ports,
63 		       mach_msg_type_name_t *ports_type,
64 		       mach_msg_type_number_t *nports)
65 {
66   mach_msg_type_number_t i;
67   error_t err;
68 
69   AUTHCHECK;
70 
71   if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports,
72 			   _hurd_nports * sizeof (mach_port_t), 1))
73     return err;
74   *nports = _hurd_nports;
75 
76   for (i = 0; i < _hurd_nports; ++i)
77     /* This function adds a new user ref for the *RESULT it gives back.
78        Our reply message uses move-send rights that consumes this ref.  */
79     if (err = _hurd_ports_get (i, &(*ports)[i]))
80       {
81 	/* Died part way through.  Deallocate the ports already fetched.  */
82 	while (i-- > 0)
83 	  __mach_port_deallocate (__mach_task_self (), (*ports)[i]);
84 	__vm_deallocate (__mach_task_self (),
85 			 (vm_address_t) *ports,
86 			 *nports * sizeof (mach_port_t));
87 	return err;
88       }
89 
90   *ports_type = MACH_MSG_TYPE_MOVE_SEND;
91   return 0;
92 }
93 
94 kern_return_t
_S_msg_set_init_ports(mach_port_t msgport,mach_port_t auth,mach_port_t * ports,mach_msg_type_number_t nports)95 _S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth,
96 		       mach_port_t *ports, mach_msg_type_number_t nports)
97 {
98   mach_msg_type_number_t i;
99   error_t err;
100 
101   AUTHCHECK;
102 
103   for (i = 0; i < _hurd_nports; ++i)
104     {
105       if (err = _hurd_ports_set (i, ports[i]))
106 	return err;
107       else
108 	__mach_port_deallocate (__mach_task_self (), ports[i]);
109     }
110 
111   return 0;
112 }
113 
114 /* Snarfing and frobbing the init ints.  */
115 
116 static kern_return_t
get_int(int which,int * value)117 get_int (int which, int *value)
118 {
119   switch (which)
120     {
121     case INIT_UMASK:
122       *value = _hurd_umask;
123       return 0;
124     case INIT_SIGPENDING:
125       {
126 	struct hurd_sigstate *ss = _hurd_global_sigstate;
127 	__spin_lock (&ss->lock);
128 	*value = ss->pending;
129 	__spin_unlock (&ss->lock);
130 	return 0;
131       }
132     case INIT_SIGIGN:
133       {
134 	struct hurd_sigstate *ss = _hurd_global_sigstate;
135 	sigset_t ign;
136 	int sig;
137 	__spin_lock (&ss->lock);
138 	__sigemptyset (&ign);
139 	for (sig = 1; sig < NSIG; ++sig)
140 	  if (ss->actions[sig].sa_handler == SIG_IGN)
141 	    __sigaddset (&ign, sig);
142 	__spin_unlock (&ss->lock);
143 	*value = ign;
144 	return 0;
145       }
146     default:
147       return EINVAL;
148     }
149 }
150 
151 kern_return_t
_S_msg_get_init_int(mach_port_t msgport,mach_port_t auth,int which,int * value)152 _S_msg_get_init_int (mach_port_t msgport, mach_port_t auth,
153 		     int which, int *value)
154 {
155   AUTHCHECK;
156 
157   return get_int (which, value);
158 }
159 
160 kern_return_t
_S_msg_get_init_ints(mach_port_t msgport,mach_port_t auth,int ** values,mach_msg_type_number_t * nvalues)161 _S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth,
162 		      int **values, mach_msg_type_number_t *nvalues)
163 {
164   error_t err;
165   mach_msg_type_number_t i;
166 
167   AUTHCHECK;
168 
169   if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values,
170 			   INIT_INT_MAX * sizeof (int), 1))
171     return err;
172   *nvalues = INIT_INT_MAX;
173 
174   for (i = 0; i < INIT_INT_MAX; ++i)
175     switch (err = get_int (i, &(*values)[i]))
176       {
177       case 0:			/* Success.  */
178 	break;
179       case EINVAL:		/* Unknown index.  */
180 	(*values)[i] = 0;
181 	break;
182       default:			/* Lossage.  */
183 	__vm_deallocate (__mach_task_self (),
184 			 (vm_address_t) *values, INIT_INT_MAX * sizeof (int));
185 	return err;
186       }
187 
188   return 0;
189 }
190 
191 
192 static kern_return_t
set_int(int which,int value)193 set_int (int which, int value)
194 {
195   switch (which)
196     {
197     case INIT_UMASK:
198       _hurd_umask = value;
199       return 0;
200 
201       /* These are pretty odd things to do.  But you asked for it.  */
202     case INIT_SIGPENDING:
203       {
204 	struct hurd_sigstate *ss = _hurd_global_sigstate;
205 	__spin_lock (&ss->lock);
206 	ss->pending = value;
207 	__spin_unlock (&ss->lock);
208 	return 0;
209       }
210     case INIT_SIGIGN:
211       {
212 	struct hurd_sigstate *ss = _hurd_global_sigstate;
213 	int sig;
214 	const sigset_t ign = value;
215 	__spin_lock (&ss->lock);
216 	for (sig = 1; sig < NSIG; ++sig)
217 	  {
218 	    if (__sigismember (&ign, sig))
219 	      ss->actions[sig].sa_handler = SIG_IGN;
220 	    else if (ss->actions[sig].sa_handler == SIG_IGN)
221 	      ss->actions[sig].sa_handler = SIG_DFL;
222 	  }
223 	__spin_unlock (&ss->lock);
224 	return 0;
225 
226       case INIT_TRACEMASK:
227 	_hurdsig_traced = value;
228 	return 0;
229       }
230     default:
231       return EINVAL;
232     }
233 }
234 
235 kern_return_t
_S_msg_set_init_int(mach_port_t msgport,mach_port_t auth,int which,int value)236 _S_msg_set_init_int (mach_port_t msgport, mach_port_t auth,
237 		     int which, int value)
238 {
239   AUTHCHECK;
240 
241   return set_int (which, value);
242 }
243 
244 kern_return_t
_S_msg_set_init_ints(mach_port_t msgport,mach_port_t auth,int * values,mach_msg_type_number_t nvalues)245 _S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth,
246 		      int *values, mach_msg_type_number_t nvalues)
247 {
248   error_t err;
249   mach_msg_type_number_t i;
250 
251   AUTHCHECK;
252 
253   for (i = 0; i < INIT_INT_MAX; ++i)
254     switch (err = set_int (i, values[i]))
255       {
256       case 0:			/* Success.  */
257 	break;
258       case EINVAL:		/* Unknown index.  */
259 	break;
260       default:			/* Lossage.  */
261 	return err;
262       }
263 
264   return 0;
265 }
266 
267 
268 kern_return_t
_S_msg_get_fd(mach_port_t msgport,mach_port_t auth,int which,mach_port_t * result,mach_msg_type_name_t * result_type)269 _S_msg_get_fd (mach_port_t msgport, mach_port_t auth, int which,
270 	       mach_port_t *result, mach_msg_type_name_t *result_type)
271 {
272   AUTHCHECK;
273 
274   /* This creates a new user reference for the send right.
275      Our reply message will move that reference to the caller.  */
276   *result = __getdport (which);
277   if (*result == MACH_PORT_NULL)
278     return errno;
279   *result_type = MACH_MSG_TYPE_MOVE_SEND;
280 
281   return 0;
282 }
283 
284 kern_return_t
_S_msg_set_fd(mach_port_t msgport,mach_port_t auth,int which,mach_port_t port)285 _S_msg_set_fd (mach_port_t msgport, mach_port_t auth,
286 	       int which, mach_port_t port)
287 {
288   AUTHCHECK;
289 
290   /* We consume the reference if successful.  */
291   return HURD_FD_USE (which, (_hurd_port2fd (descriptor, port, 0), 0));
292 }
293 
294 /* Snarfing and frobbing environment variables.  */
295 
296 kern_return_t
_S_msg_get_env_variable(mach_port_t msgport,string_t variable,char ** data,mach_msg_type_number_t * datalen)297 _S_msg_get_env_variable (mach_port_t msgport,
298 			 string_t variable, //
299 			 char **data, mach_msg_type_number_t *datalen)
300 {
301   error_t err;
302   mach_msg_type_number_t valuelen;
303   const char *value = getenv (variable);
304 
305   if (value == NULL)
306     return ENOENT;
307 
308   valuelen = strlen (value);
309   if (valuelen > *datalen)
310     {
311       if (err = __vm_allocate (__mach_task_self (),
312 			       (vm_address_t *) data, valuelen, 1))
313 	return err;
314     }
315 
316   memcpy (*data, value, valuelen);
317   *datalen = valuelen;
318 
319   return 0;
320 }
321 
322 
323 kern_return_t
_S_msg_set_env_variable(mach_port_t msgport,mach_port_t auth,string_t variable,string_t value,int replace)324 _S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth,
325 			 string_t variable, //
326 			 string_t value, //
327 			 int replace)
328 {
329   AUTHCHECK;
330 
331   if (__setenv (variable, value, replace)) /* XXX name space */
332     return errno;
333   return 0;
334 }
335 
336 kern_return_t
_S_msg_get_environment(mach_port_t msgport,char ** data,mach_msg_type_number_t * datalen)337 _S_msg_get_environment (mach_port_t msgport,
338 			char **data, mach_msg_type_number_t *datalen)
339 {
340   /* Pack the environment into an array with nulls separating elements.  */
341   if (__environ != NULL)
342     {
343       char *ap, **p;
344       size_t envlen = 0;
345 
346       for (p = __environ; *p != NULL; ++p)
347 	envlen += strlen (*p) + 1;
348 
349       if (envlen > *datalen)
350 	{
351 	  if (__vm_allocate (__mach_task_self (),
352 			     (vm_address_t *) data, envlen, 1))
353 	    return ENOMEM;
354 	}
355 
356       ap = *data;
357       for (p = __environ; *p != NULL; ++p)
358 	ap = __memccpy (ap, *p, '\0', ULONG_MAX);
359 
360       *datalen = envlen;
361     }
362   else
363     *datalen = 0;
364 
365   return 0;
366 }
367 
368 kern_return_t
_S_msg_set_environment(mach_port_t msgport,mach_port_t auth,char * data,mach_msg_type_number_t datalen)369 _S_msg_set_environment (mach_port_t msgport, mach_port_t auth,
370 			char *data, mach_msg_type_number_t datalen)
371 {
372   int _hurd_split_args (char *, mach_msg_type_number_t, char **);
373   int envc;
374   char **envp;
375 
376   AUTHCHECK;
377 
378   envc = __argz_count (data, datalen);
379   envp = malloc ((envc + 1) * sizeof (char *));
380   if (envp == NULL)
381     return errno;
382   __argz_extract (data, datalen, envp);
383   __environ = envp;		/* XXX cooperate with loadenv et al */
384   return 0;
385 }
386 
387 
388 /* XXX */
389 
390 kern_return_t
_S_msg_get_dtable(mach_port_t process,mach_port_t refport,portarray_t * dtable,mach_msg_type_name_t * dtablePoly,mach_msg_type_number_t * dtableCnt)391 _S_msg_get_dtable (mach_port_t process,
392 		   mach_port_t refport,
393 		   portarray_t *dtable,
394 		   mach_msg_type_name_t *dtablePoly,
395 		   mach_msg_type_number_t *dtableCnt)
396 { return EOPNOTSUPP; }
397 
398 kern_return_t
_S_msg_set_dtable(mach_port_t process,mach_port_t refport,portarray_t dtable,mach_msg_type_number_t dtableCnt)399 _S_msg_set_dtable (mach_port_t process,
400 		   mach_port_t refport,
401 		   portarray_t dtable,
402 		   mach_msg_type_number_t dtableCnt)
403 { return EOPNOTSUPP; }
404