1 /* Copyright (C) 2001-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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 License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
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.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, see <https://www.gnu.org/licenses/>. */
20 #include <sys/socket.h>
24 #include <hurd/socket.h>
25 #include <sysdep-cancel.h>
28 contains_uid (unsigned int n
, __uid_t uids
[n
], __uid_t uid
)
32 for (i
= 0; i
< n
; i
++)
39 contains_gid (unsigned int n
, __gid_t gids
[n
], __gid_t gid
)
43 for (i
= 0; i
< n
; i
++)
49 /* Check the passed credentials. */
51 check_auth (mach_port_t rendezvous
,
53 __uid_t uid
, __uid_t euid
,
55 int ngroups
, __gid_t groups
[ngroups
])
58 size_t neuids
= CMGROUP_MAX
, nauids
= CMGROUP_MAX
;
59 size_t negids
= CMGROUP_MAX
, nagids
= CMGROUP_MAX
;
60 __uid_t euids_buf
[neuids
], auids_buf
[nauids
];
61 __gid_t egids_buf
[negids
], agids_buf
[nagids
];
62 __uid_t
*euids
= euids_buf
, *auids
= auids_buf
;
63 __gid_t
*egids
= egids_buf
, *agids
= agids_buf
;
65 struct procinfo
*pi
= NULL
;
66 mach_msg_type_number_t pi_size
= 0;
67 int flags
= PI_FETCH_TASKINFO
;
72 err
= __mach_port_mod_refs (mach_task_self (), rendezvous
,
73 MACH_PORT_RIGHT_SEND
, 1);
79 (AUTH
, __auth_server_authenticate (port
,
80 rendezvous
, MACH_MSG_TYPE_COPY_SEND
,
82 &euids
, &neuids
, &auids
, &nauids
,
83 &egids
, &negids
, &agids
, &nagids
));
88 /* Check whether this process indeed has these IDs */
89 if ( !contains_uid (neuids
, euids
, uid
)
90 && !contains_uid (nauids
, auids
, uid
)
91 || !contains_uid (neuids
, euids
, euid
)
92 && !contains_uid (nauids
, auids
, euid
)
93 || !contains_gid (negids
, egids
, gid
)
94 && !contains_gid (nagids
, agids
, gid
)
102 for (i
= 0; i
< ngroups
; i
++)
103 if ( !contains_gid (negids
, egids
, groups
[i
])
104 && !contains_gid (nagids
, agids
, groups
[i
]))
111 /* XXX: Using proc_getprocinfo until
112 proc_user_authenticate proc_server_authenticate is implemented
114 /* Get procinfo to check the owner. Maybe he faked the pid, but at least we
116 err
= __USEPORT (PROC
, __proc_getprocinfo (port
, pid
, &flags
,
118 &pi_size
, &tw
, &tw_size
));
122 if ( !contains_uid (neuids
, euids
, pi
->owner
)
123 && !contains_uid (nauids
, auids
, pi
->owner
))
127 __mach_port_deallocate (__mach_task_self (), rendezvous
);
128 if (euids
!= euids_buf
)
129 __vm_deallocate (__mach_task_self(), (vm_address_t
) euids
, neuids
* sizeof(uid_t
));
130 if (auids
!= auids_buf
)
131 __vm_deallocate (__mach_task_self(), (vm_address_t
) auids
, nauids
* sizeof(uid_t
));
132 if (egids
!= egids_buf
)
133 __vm_deallocate (__mach_task_self(), (vm_address_t
) egids
, negids
* sizeof(uid_t
));
134 if (agids
!= agids_buf
)
135 __vm_deallocate (__mach_task_self(), (vm_address_t
) agids
, nagids
* sizeof(uid_t
));
137 __vm_deallocate (__mach_task_self(), (vm_address_t
) tw
, tw_size
);
139 __vm_deallocate (__mach_task_self(), (vm_address_t
) pi
, pi_size
);
144 /* Receive a message as described by MESSAGE from socket FD.
145 Returns the number of bytes read or -1 for errors. */
147 __libc_recvmsg (int fd
, struct msghdr
*message
, int flags
)
152 mach_msg_type_number_t len
= 0;
153 mach_port_t
*ports
, *newports
= NULL
;
154 mach_msg_type_number_t nports
= 0;
155 struct cmsghdr
*cmsg
;
157 mach_msg_type_number_t clen
= 0;
160 int nfds
, *opened_fds
= NULL
;
165 error_t
reauthenticate (mach_port_t port
, mach_port_t
*result
)
169 ref
= __mach_reply_port ();
172 cancel_oldtype
= LIBC_CANCEL_ASYNC();
174 err
= __io_reauthenticate (port
, ref
, MACH_MSG_TYPE_MAKE_SEND
);
175 while (err
== EINTR
);
178 err
= __USEPORT_CANCEL (AUTH
, __auth_user_authenticate (port
,
179 ref
, MACH_MSG_TYPE_MAKE_SEND
,
181 while (err
== EINTR
);
182 LIBC_CANCEL_RESET (cancel_oldtype
);
184 __mach_port_destroy (__mach_task_self (), ref
);
188 /* Find the total number of bytes to be read. */
190 for (i
= 0; i
< message
->msg_iovlen
; i
++)
192 amount
+= message
->msg_iov
[i
].iov_len
;
194 /* As an optimization, we set the initial values of DATA and LEN
195 from the first non-empty iovec. This kicks-in in the case
196 where the whole packet fits into that iovec buffer. */
197 if (data
== NULL
&& message
->msg_iov
[i
].iov_len
> 0)
199 data
= message
->msg_iov
[i
].iov_base
;
200 len
= message
->msg_iov
[i
].iov_len
;
205 cancel_oldtype
= LIBC_CANCEL_ASYNC();
206 err
= HURD_DPORT_USE_CANCEL (fd
, __socket_recv (port
, &aport
,
210 &message
->msg_flags
, amount
));
211 LIBC_CANCEL_RESET (cancel_oldtype
);
213 return __hurd_sockfail (fd
, flags
, err
);
215 if (message
->msg_name
!= NULL
&& aport
!= MACH_PORT_NULL
)
217 char *buf
= message
->msg_name
;
218 mach_msg_type_number_t buflen
= message
->msg_namelen
;
221 cancel_oldtype
= LIBC_CANCEL_ASYNC();
222 err
= __socket_whatis_address (aport
, &type
, &buf
, &buflen
);
223 LIBC_CANCEL_RESET (cancel_oldtype
);
225 if (err
== EOPNOTSUPP
)
226 /* If the protocol server can't tell us the address, just return a
229 buf
= message
->msg_name
;
236 __mach_port_deallocate (__mach_task_self (), aport
);
237 return __hurd_sockfail (fd
, flags
, err
);
240 if (message
->msg_namelen
> buflen
)
241 message
->msg_namelen
= buflen
;
243 if (buf
!= message
->msg_name
)
245 memcpy (message
->msg_name
, buf
, message
->msg_namelen
);
246 __vm_deallocate (__mach_task_self (), (vm_address_t
) buf
, buflen
);
250 ((struct sockaddr
*) message
->msg_name
)->sa_family
= type
;
252 else if (message
->msg_name
!= NULL
)
253 message
->msg_namelen
= 0;
255 __mach_port_deallocate (__mach_task_self (), aport
);
261 /* Copy the data into MSG. */
263 message
->msg_flags
|= MSG_TRUNC
;
268 for (i
= 0; i
< message
->msg_iovlen
; i
++)
270 #define min(a, b) ((a) > (b) ? (b) : (a))
271 size_t copy
= min (message
->msg_iov
[i
].iov_len
, amount
);
273 memcpy (message
->msg_iov
[i
].iov_base
, buf
, copy
);
281 __vm_deallocate (__mach_task_self (), (vm_address_t
) data
, len
);
284 /* Copy the control message into MSG. */
285 if (clen
> message
->msg_controllen
)
286 message
->msg_flags
|= MSG_CTRUNC
;
288 message
->msg_controllen
= clen
;
289 memcpy (message
->msg_control
, cdata
, message
->msg_controllen
);
293 newports
= __alloca (nports
* sizeof (mach_port_t
));
294 opened_fds
= __alloca (nports
* sizeof (int));
297 /* This counts how many ports we processed completely. */
299 /* This counts how many new fds we create. */
302 for (cmsg
= CMSG_FIRSTHDR (message
);
304 cmsg
= CMSG_NXTHDR (message
, cmsg
))
306 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_RIGHTS
)
308 /* SCM_RIGHTS support. */
309 /* The fd's flags are passed in the control data. */
310 int *fds
= (int *) CMSG_DATA (cmsg
);
311 nfds
= (cmsg
->cmsg_len
- CMSG_ALIGN (sizeof (struct cmsghdr
)))
314 for (j
= 0; j
< nfds
; j
++)
316 err
= reauthenticate (ports
[i
], &newports
[newfds
]);
319 fds
[j
] = opened_fds
[newfds
] = _hurd_intern_fd (newports
[newfds
],
324 __mach_port_deallocate (__mach_task_self (), newports
[newfds
]);
331 else if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_CREDS
)
333 /* SCM_CREDS support. */
334 /* Check received credentials */
335 struct cmsgcred
*ucredp
= (struct cmsgcred
*) CMSG_DATA(cmsg
);
337 err
= check_auth (ports
[i
],
339 ucredp
->cmcred_uid
, ucredp
->cmcred_euid
,
341 ucredp
->cmcred_ngroups
, ucredp
->cmcred_groups
);
348 for (i
= 0; i
< nports
; i
++)
349 __mach_port_deallocate (mach_task_self (), ports
[i
]);
351 __vm_deallocate (__mach_task_self (), (vm_address_t
) cdata
, clen
);
356 /* Clean up all the file descriptors from port 0 to i-1. */
361 for (cmsg
= CMSG_FIRSTHDR (message
);
363 cmsg
= CMSG_NXTHDR (message
, cmsg
))
365 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_RIGHTS
)
367 nfds
= (cmsg
->cmsg_len
- CMSG_ALIGN (sizeof (struct cmsghdr
)))
369 for (j
= 0; j
< nfds
&& ii
< i
; j
++, ii
++, newfds
++)
371 _hurd_fd_close (_hurd_fd_get (opened_fds
[newfds
]));
372 __mach_port_deallocate (__mach_task_self (), newports
[newfds
]);
373 __mach_port_deallocate (__mach_task_self (), ports
[ii
]);
376 else if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_CREDS
)
378 __mach_port_deallocate (__mach_task_self (), ports
[ii
]);
384 __vm_deallocate (__mach_task_self (), (vm_address_t
) cdata
, clen
);
385 return __hurd_fail (err
);
388 weak_alias (__libc_recvmsg
, recvmsg
)
389 weak_alias (__libc_recvmsg
, __recvmsg
)