| /* Copyright (C) 1991-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <hurd.h> | 
 | #include <hurd/msg_server.h> | 
 | #include <hurd/id.h> | 
 | #include <string.h> | 
 |  | 
 | int | 
 | _hurd_refport_secure_p (mach_port_t ref) | 
 | { | 
 |   if (ref == __mach_task_self ()) | 
 |     return 1; | 
 |   if (__USEPORT (AUTH, ref == port)) | 
 |     return 1; | 
 |   return 0; | 
 | } | 
 |  | 
 | kern_return_t | 
 | _S_msg_add_auth (mach_port_t me, | 
 | 		 auth_t addauth) | 
 | { | 
 |   error_t err; | 
 |   auth_t newauth; | 
 |   uid_t *genuids, *gengids, *auxuids, *auxgids; | 
 |   mach_msg_type_number_t ngenuids, ngengids, nauxuids, nauxgids; | 
 |   uid_t *newgenuids, *newgengids, *newauxuids, *newauxgids; | 
 |   mach_msg_type_number_t nnewgenuids, nnewgengids, nnewauxuids, nnewauxgids; | 
 |  | 
 |   /* Create a list of ids and store it in NEWLISTP, length NEWLISTLEN. | 
 |      Keep all the ids in EXIST (len NEXIST), adding in those from NEW | 
 |      (len NNEW) which are not already there.  */ | 
 |   error_t make_list (uid_t **newlistp, mach_msg_type_number_t *newlistlen, | 
 | 		     uid_t *exist, mach_msg_type_number_t nexist, | 
 | 		     uid_t *new, mach_msg_type_number_t nnew) | 
 |     { | 
 |       error_t urp; | 
 |       int i, j, k; | 
 |       vm_size_t offset; | 
 |  | 
 |       urp = vm_allocate (mach_task_self (), (vm_address_t *) newlistp, | 
 | 			 nexist + nnew * sizeof (uid_t), 1); | 
 |       if (urp) | 
 | 	return urp; | 
 |  | 
 |       j = 0; | 
 |       for (i = 0; i < nexist; i++) | 
 | 	(*newlistp)[j++] = exist[i]; | 
 |  | 
 |       for (i = 0; i < nnew; i++) | 
 | 	{ | 
 | 	  for (k = 0; k < nexist; k++) | 
 | 	    if (exist[k] == new[i]) | 
 | 	      break; | 
 | 	  if (k < nexist) | 
 | 	    continue; | 
 |  | 
 | 	  (*newlistp)[j++] = new[i]; | 
 | 	} | 
 |  | 
 |       offset = (round_page (nexist + nnew * sizeof (uid_t)) | 
 | 		- round_page (j * sizeof (uid_t))); | 
 |       if (offset) | 
 | 	vm_deallocate (mach_task_self (), | 
 | 		       (vm_address_t) (*newlistp | 
 | 				       + (nexist + nnew * sizeof (uid_t))), | 
 | 		       offset); | 
 |       *newlistlen = j; | 
 |       return 0; | 
 |     } | 
 |  | 
 |   /* Find out what ids ADDAUTH refers to */ | 
 |  | 
 |   genuids = gengids = auxuids = auxgids = 0; | 
 |   ngenuids = ngengids = nauxuids = nauxgids = 0; | 
 |   err = __auth_getids (addauth, | 
 | 		       &genuids, &ngenuids, | 
 | 		       &auxuids, &nauxuids, | 
 | 		       &gengids, &ngengids, | 
 | 		       &auxgids, &nauxgids); | 
 |   if (err) | 
 |     return err; | 
 |  | 
 |   /* OR in these ids to what we already have, creating a new list. */ | 
 |  | 
 |   HURD_CRITICAL_BEGIN; | 
 |   __mutex_lock (&_hurd_id.lock); | 
 |   _hurd_check_ids (); | 
 |  | 
 | #define MAKE(genaux,uidgid) 						    \ | 
 |   make_list (&new ## genaux ## uidgid ## s, 				    \ | 
 | 	     &nnew ## genaux ## uidgid ## s,				    \ | 
 | 	     _hurd_id.genaux.uidgid ## s,				    \ | 
 | 	     _hurd_id.genaux.n ## uidgid ## s,				    \ | 
 | 	     genaux ## uidgid ## s,					    \ | 
 | 	     n ## genaux ## uidgid ## s) | 
 |  | 
 |   err = MAKE (gen, uid); | 
 |   if (!err) | 
 |     MAKE (aux, uid); | 
 |   if (!err) | 
 |     MAKE (gen, gid); | 
 |   if (!err) | 
 |     MAKE (aux, gid); | 
 | #undef MAKE | 
 |  | 
 |   __mutex_unlock (&_hurd_id.lock); | 
 |   HURD_CRITICAL_END; | 
 |  | 
 |  | 
 |   /* Create the new auth port */ | 
 |  | 
 |   if (!err) | 
 |     err = __USEPORT (AUTH, | 
 | 		     __auth_makeauth (port, | 
 | 				      &addauth, MACH_MSG_TYPE_MOVE_SEND, 1, | 
 | 				      newgenuids, nnewgenuids, | 
 | 				      newauxuids, nnewauxuids, | 
 | 				      newgengids, nnewgengids, | 
 | 				      newauxgids, nnewauxgids, | 
 | 				      &newauth)); | 
 |  | 
 | #define freeup(array, len) \ | 
 |   if (array) \ | 
 |     vm_deallocate (mach_task_self (), (vm_address_t) array, \ | 
 | 		   len * sizeof (uid_t)); | 
 |  | 
 |   freeup (genuids, ngenuids); | 
 |   freeup (auxuids, nauxuids); | 
 |   freeup (gengids, ngengids); | 
 |   freeup (auxgids, nauxgids); | 
 |   freeup (newgenuids, nnewgenuids); | 
 |   freeup (newauxuids, nnewauxuids); | 
 |   freeup (newgengids, nnewgengids); | 
 |   freeup (newauxgids, nnewauxgids); | 
 | #undef freeup | 
 |  | 
 |   if (err) | 
 |     return err; | 
 |  | 
 |   /* And install it. */ | 
 |  | 
 |   err = __setauth (newauth); | 
 |   __mach_port_deallocate (__mach_task_self (), newauth); | 
 |   if (err) | 
 |     return errno; | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | 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) | 
 | { | 
 |   error_t err; | 
 |   auth_t newauth; | 
 |  | 
 |   if (!_hurd_refport_secure_p (task)) | 
 |     return EPERM; | 
 |  | 
 |   HURD_CRITICAL_BEGIN; | 
 |   __mutex_lock (&_hurd_id.lock); | 
 |   err = _hurd_check_ids (); | 
 |  | 
 |   if (!err) | 
 |     { | 
 |       size_t i, j; | 
 |       size_t nu = _hurd_id.gen.nuids, ng = _hurd_id.gen.ngids; | 
 |       uid_t newu[nu]; | 
 |       gid_t newg[ng]; | 
 |  | 
 |       memcpy (newu, _hurd_id.gen.uids, nu * sizeof (uid_t)); | 
 |       memcpy (newg, _hurd_id.gen.gids, ng * sizeof (gid_t)); | 
 |  | 
 |       for (j = 0; j < nuids; ++j) | 
 | 	{ | 
 | 	  const uid_t uid = uids[j]; | 
 | 	  for (i = 0; i < nu; ++i) | 
 | 	    if (newu[i] == uid) | 
 | 	      /* Move the last uid into this slot, and decrease the | 
 | 		 number of uids so the last slot is no longer used.  */ | 
 | 	      newu[i] = newu[--nu]; | 
 | 	} | 
 |       __vm_deallocate (__mach_task_self (), | 
 | 		       (vm_address_t) uids, nuids * sizeof (uid_t)); | 
 |  | 
 |       for (j = 0; j < ngids; ++j) | 
 | 	{ | 
 | 	  const gid_t gid = gids[j]; | 
 | 	  for (i = 0; i < nu; ++i) | 
 | 	    if (newu[i] == gid) | 
 | 	      /* Move the last gid into this slot, and decrease the | 
 | 		 number of gids so the last slot is no longer used.  */ | 
 | 	      newu[i] = newu[--nu]; | 
 | 	} | 
 |       __vm_deallocate (__mach_task_self (), | 
 | 		       (vm_address_t) gids, ngids * sizeof (gid_t)); | 
 |  | 
 |       err = __USEPORT (AUTH, __auth_makeauth | 
 | 		       (port, | 
 | 			NULL, MACH_MSG_TYPE_COPY_SEND, 0, | 
 | 			newu, nu, | 
 | 			_hurd_id.aux.uids, _hurd_id.aux.nuids, | 
 | 			newg, ng, | 
 | 			_hurd_id.aux.uids, _hurd_id.aux.ngids, | 
 | 			&newauth)); | 
 |     } | 
 |   __mutex_unlock (&_hurd_id.lock); | 
 |   HURD_CRITICAL_END; | 
 |  | 
 |   if (err) | 
 |     return err; | 
 |  | 
 |   err = __setauth (newauth); | 
 |   __mach_port_deallocate (__mach_task_self (), newauth); | 
 |   if (err) | 
 |     return errno; | 
 |  | 
 |   return 0; | 
 | } |