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