1/* Copyright (C) 1992-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/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
34kern_return_t
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 error_t err;
39
40 AUTHCHECK;
41
42 *result_type = MACH_MSG_TYPE_MOVE_SEND;
43 /* This function adds a new user reference for the *RESULT it gives back.
44 Our reply message uses a move-send right that consumes this reference. */
45 err = _hurd_ports_get (which, result);
46 if (!err && MACH_PORT_VALID (auth))
47 __mach_port_deallocate (__mach_task_self (), auth);
48 return err;
49}
50
51kern_return_t
52_S_msg_set_init_port (mach_port_t msgport, mach_port_t auth,
53 int which, mach_port_t port)
54{
55 error_t err;
56
57 AUTHCHECK;
58
59 err = _hurd_ports_set (which, port);
60
61 if (!err && MACH_PORT_VALID (port))
62 __mach_port_deallocate (__mach_task_self (), port);
63 if (!err && MACH_PORT_VALID (auth))
64 __mach_port_deallocate (__mach_task_self (), auth);
65
66 return err;
67}
68
69kern_return_t
70_S_msg_get_init_ports (mach_port_t msgport, mach_port_t auth,
71 mach_port_t **ports,
72 mach_msg_type_name_t *ports_type,
73 mach_msg_type_number_t *nports)
74{
75 mach_msg_type_number_t i;
76 error_t err;
77
78 AUTHCHECK;
79
80 if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) ports,
81 _hurd_nports * sizeof (mach_port_t), 1))
82 return err;
83 *nports = _hurd_nports;
84
85 for (i = 0; i < _hurd_nports; ++i)
86 /* This function adds a new user ref for the *RESULT it gives back.
87 Our reply message uses move-send rights that consumes this ref. */
88 if (err = _hurd_ports_get (i, &(*ports)[i]))
89 {
90 /* Died part way through. Deallocate the ports already fetched. */
91 while (i-- > 0)
92 __mach_port_deallocate (__mach_task_self (), (*ports)[i]);
93 __vm_deallocate (__mach_task_self (),
94 (vm_address_t) *ports,
95 *nports * sizeof (mach_port_t));
96 return err;
97 }
98
99 *ports_type = MACH_MSG_TYPE_MOVE_SEND;
100 if (MACH_PORT_VALID (auth))
101 __mach_port_deallocate (__mach_task_self (), auth);
102 return 0;
103}
104
105kern_return_t
106_S_msg_set_init_ports (mach_port_t msgport, mach_port_t auth,
107 const mach_port_t *ports, mach_msg_type_number_t nports)
108{
109 mach_msg_type_number_t i;
110 error_t err;
111
112 AUTHCHECK;
113
114 for (i = 0; i < _hurd_nports; ++i)
115 {
116 if (err = _hurd_ports_set (i, ports[i]))
117 return err;
118 else
119 __mach_port_deallocate (__mach_task_self (), ports[i]);
120 }
121
122 if (MACH_PORT_VALID (auth))
123 __mach_port_deallocate (__mach_task_self (), auth);
124 return 0;
125}
126
127/* Snarfing and frobbing the init ints. */
128
129static kern_return_t
130get_int (int which, int *value)
131{
132 switch (which)
133 {
134 case INIT_UMASK:
135 *value = _hurd_umask;
136 return 0;
137 case INIT_SIGPENDING:
138 {
139 struct hurd_sigstate *ss = _hurd_global_sigstate;
140 __spin_lock (&ss->lock);
141 *value = ss->pending;
142 __spin_unlock (&ss->lock);
143 return 0;
144 }
145 case INIT_SIGIGN:
146 {
147 struct hurd_sigstate *ss = _hurd_global_sigstate;
148 sigset_t ign;
149 int sig;
150 __spin_lock (&ss->lock);
151 __sigemptyset (&ign);
152 for (sig = 1; sig < NSIG; ++sig)
153 if (ss->actions[sig].sa_handler == SIG_IGN)
154 __sigaddset (&ign, sig);
155 __spin_unlock (&ss->lock);
156 *value = ign;
157 return 0;
158 }
159 default:
160 return EINVAL;
161 }
162}
163
164kern_return_t
165_S_msg_get_init_int (mach_port_t msgport, mach_port_t auth,
166 int which, int *value)
167{
168 error_t err;
169
170 AUTHCHECK;
171
172 err = get_int (which, value);
173 if (err)
174 return err;
175 if (MACH_PORT_VALID (auth))
176 __mach_port_deallocate (__mach_task_self (), auth);
177 return 0;
178}
179
180kern_return_t
181_S_msg_get_init_ints (mach_port_t msgport, mach_port_t auth,
182 int **values, mach_msg_type_number_t *nvalues)
183{
184 error_t err;
185 mach_msg_type_number_t i;
186
187 AUTHCHECK;
188
189 if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) values,
190 INIT_INT_MAX * sizeof (int), 1))
191 return err;
192 *nvalues = INIT_INT_MAX;
193
194 for (i = 0; i < INIT_INT_MAX; ++i)
195 switch (err = get_int (i, &(*values)[i]))
196 {
197 case 0: /* Success. */
198 break;
199 case EINVAL: /* Unknown index. */
200 (*values)[i] = 0;
201 break;
202 default: /* Lossage. */
203 __vm_deallocate (__mach_task_self (),
204 (vm_address_t) *values, INIT_INT_MAX * sizeof (int));
205 return err;
206 }
207
208 if (MACH_PORT_VALID (auth))
209 __mach_port_deallocate (__mach_task_self (), auth);
210 return 0;
211}
212
213
214static kern_return_t
215set_int (int which, int value)
216{
217 switch (which)
218 {
219 case INIT_UMASK:
220 _hurd_umask = value;
221 return 0;
222
223 /* These are pretty odd things to do. But you asked for it. */
224 case INIT_SIGPENDING:
225 {
226 struct hurd_sigstate *ss = _hurd_global_sigstate;
227 __spin_lock (&ss->lock);
228 ss->pending = value;
229 __spin_unlock (&ss->lock);
230 return 0;
231 }
232 case INIT_SIGIGN:
233 {
234 struct hurd_sigstate *ss = _hurd_global_sigstate;
235 int sig;
236 const sigset_t ign = value;
237 __spin_lock (&ss->lock);
238 for (sig = 1; sig < NSIG; ++sig)
239 {
240 if (__sigismember (&ign, sig))
241 ss->actions[sig].sa_handler = SIG_IGN;
242 else if (ss->actions[sig].sa_handler == SIG_IGN)
243 ss->actions[sig].sa_handler = SIG_DFL;
244 }
245 __spin_unlock (&ss->lock);
246 return 0;
247
248 case INIT_TRACEMASK:
249 _hurdsig_traced = value;
250 return 0;
251 }
252 default:
253 return EINVAL;
254 }
255}
256
257kern_return_t
258_S_msg_set_init_int (mach_port_t msgport, mach_port_t auth,
259 int which, int value)
260{
261 error_t err;
262
263 AUTHCHECK;
264
265 err = set_int (which, value);
266 if (err)
267 return err;
268 if (MACH_PORT_VALID (auth))
269 __mach_port_deallocate (__mach_task_self (), auth);
270 return 0;
271}
272
273kern_return_t
274_S_msg_set_init_ints (mach_port_t msgport, mach_port_t auth,
275 const int *values, mach_msg_type_number_t nvalues)
276{
277 error_t err;
278 mach_msg_type_number_t i;
279
280 AUTHCHECK;
281
282 for (i = 0; i < INIT_INT_MAX; ++i)
283 switch (err = set_int (i, values[i]))
284 {
285 case 0: /* Success. */
286 break;
287 case EINVAL: /* Unknown index. */
288 break;
289 default: /* Lossage. */
290 return err;
291 }
292
293 if (MACH_PORT_VALID (auth))
294 __mach_port_deallocate (__mach_task_self (), auth);
295 return 0;
296}
297
298
299kern_return_t
300_S_msg_get_fd (mach_port_t msgport, mach_port_t auth, int which,
301 mach_port_t *result, mach_msg_type_name_t *result_type)
302{
303 AUTHCHECK;
304
305 /* This creates a new user reference for the send right.
306 Our reply message will move that reference to the caller. */
307 *result = __getdport (which);
308 if (*result == MACH_PORT_NULL)
309 return errno;
310 *result_type = MACH_MSG_TYPE_MOVE_SEND;
311
312 if (MACH_PORT_VALID (auth))
313 __mach_port_deallocate (__mach_task_self (), auth);
314 return 0;
315}
316
317kern_return_t
318_S_msg_set_fd (mach_port_t msgport, mach_port_t auth,
319 int which, mach_port_t port)
320{
321 error_t err;
322
323 AUTHCHECK;
324
325 /* We consume the reference if successful. */
326 err = HURD_FD_USE (which,
327 ({
328 int flags = (descriptor->flags & FD_CLOEXEC)
329 ? O_CLOEXEC : 0;
330 _hurd_port2fd (descriptor, port, flags);
331 0;
332 }));
333 if (err)
334 return err;
335
336 if (MACH_PORT_VALID (auth))
337 __mach_port_deallocate (__mach_task_self (), auth);
338 return 0;
339}
340
341/* Snarfing and frobbing environment variables. */
342
343kern_return_t
344_S_msg_get_env_variable (mach_port_t msgport,
345 const_string_t variable,
346 char **data, mach_msg_type_number_t *datalen)
347{
348 error_t err;
349 mach_msg_type_number_t valuelen;
350 const char *value = getenv (variable);
351
352 if (value == NULL)
353 return ENOENT;
354
355 valuelen = strlen (value);
356 if (valuelen > *datalen)
357 {
358 if (err = __vm_allocate (__mach_task_self (),
359 (vm_address_t *) data, valuelen, 1))
360 return err;
361 }
362
363 memcpy (*data, value, valuelen);
364 *datalen = valuelen;
365
366 return 0;
367}
368
369
370kern_return_t
371_S_msg_set_env_variable (mach_port_t msgport, mach_port_t auth,
372 const_string_t variable,
373 const_string_t value,
374 int replace)
375{
376 AUTHCHECK;
377
378 if (__setenv (variable, value, replace)) /* XXX name space */
379 return errno;
380
381 if (MACH_PORT_VALID (auth))
382 __mach_port_deallocate (__mach_task_self (), auth);
383 return 0;
384}
385
386kern_return_t
387_S_msg_get_environment (mach_port_t msgport,
388 char **data, mach_msg_type_number_t *datalen)
389{
390 /* Pack the environment into an array with nulls separating elements. */
391 if (__environ != NULL)
392 {
393 char *ap, **p;
394 size_t envlen = 0;
395
396 for (p = __environ; *p != NULL; ++p)
397 envlen += strlen (s: *p) + 1;
398
399 if (envlen > *datalen)
400 {
401 if (__vm_allocate (__mach_task_self (),
402 (vm_address_t *) data, envlen, 1))
403 return ENOMEM;
404 }
405
406 ap = *data;
407 for (p = __environ; *p != NULL; ++p)
408 ap = __memccpy (dest: ap, src: *p, c: '\0', ULONG_MAX);
409
410 *datalen = envlen;
411 }
412 else
413 *datalen = 0;
414
415 return 0;
416}
417
418kern_return_t
419_S_msg_set_environment (mach_port_t msgport, mach_port_t auth,
420 const char *data, mach_msg_type_number_t datalen)
421{
422 int _hurd_split_args (char *, mach_msg_type_number_t, char **);
423 int envc;
424 char **envp;
425
426 AUTHCHECK;
427
428 envc = __argz_count (argz: data, len: datalen);
429 envp = malloc ((envc + 1) * sizeof (char *));
430 if (envp == NULL)
431 return errno;
432 __argz_extract (argz: data, len: datalen, argv: envp);
433 __environ = envp; /* XXX cooperate with loadenv et al */
434
435 if (MACH_PORT_VALID (auth))
436 __mach_port_deallocate (__mach_task_self (), auth);
437 return 0;
438}
439
440
441kern_return_t
442_S_msg_get_dtable (mach_port_t process,
443 mach_port_t auth,
444 portarray_t *dtable,
445 mach_msg_type_name_t *dtablePoly,
446 mach_msg_type_number_t *dtableCnt)
447{
448 mach_port_t *ports;
449 mach_msg_type_number_t i;
450 error_t err;
451
452 AUTHCHECK;
453
454 HURD_CRITICAL_BEGIN;
455 __mutex_lock (&_hurd_dtable_lock);
456
457 if (err = __vm_allocate (__mach_task_self (), (vm_address_t *) &ports,
458 _hurd_dtablesize * sizeof(mach_port_t), 1))
459 goto out;
460
461 for (i = 0; i < _hurd_dtablesize; i++)
462 {
463 struct hurd_fd *cell = _hurd_dtable[i];
464 if (cell == NULL)
465 ports[i] = MACH_PORT_NULL;
466 else
467 {
468 __spin_lock (&cell->port.lock);
469 if (cell->port.port == MACH_PORT_NULL)
470 ports[i] = MACH_PORT_NULL;
471 else
472 {
473 ports[i] = cell->port.port;
474 /* We will move this send right. */
475 __mach_port_mod_refs (__mach_task_self (), ports[i],
476 MACH_PORT_RIGHT_SEND, +1);
477 }
478 __spin_unlock (&cell->port.lock);
479 }
480 }
481
482 *dtable = ports;
483 *dtablePoly = MACH_MSG_TYPE_MOVE_SEND;
484 *dtableCnt = _hurd_dtablesize;
485
486out:
487 __mutex_unlock (&_hurd_dtable_lock);
488 HURD_CRITICAL_END;
489 if (!err && MACH_PORT_VALID (auth))
490 __mach_port_deallocate (__mach_task_self (), auth);
491 return err;
492}
493
494/* XXX */
495
496kern_return_t
497_S_msg_set_dtable (mach_port_t process,
498 mach_port_t refport,
499 const_portarray_t dtable,
500 mach_msg_type_number_t dtableCnt)
501{ return EOPNOTSUPP; }
502

source code of glibc/hurd/hurdmsg.c