Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / hurd / hurdauth.c
1 /* Copyright (C) 1991-2013 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    <http://www.gnu.org/licenses/>.  */
17
18 #include <hurd.h>
19 #include <hurd/msg_server.h>
20 #include <hurd/id.h>
21 #include <string.h>
22
23 int
24 _hurd_refport_secure_p (mach_port_t ref)
25 {
26   if (ref == __mach_task_self ())
27     return 1;
28   if (__USEPORT (AUTH, ref == port))
29     return 1;
30   return 0;
31 }
32
33 kern_return_t
34 _S_msg_add_auth (mach_port_t me,
35                  auth_t addauth)
36 {
37   error_t err;
38   auth_t newauth;
39   uid_t *genuids, *gengids, *auxuids, *auxgids;
40   mach_msg_type_number_t ngenuids, ngengids, nauxuids, nauxgids;
41   uid_t *newgenuids, *newgengids, *newauxuids, *newauxgids;
42   mach_msg_type_number_t nnewgenuids, nnewgengids, nnewauxuids, nnewauxgids;
43
44   /* Create a list of ids and store it in NEWLISTP, length NEWLISTLEN.
45      Keep all the ids in EXIST (len NEXIST), adding in those from NEW
46      (len NNEW) which are not already there.  */
47   error_t make_list (uid_t **newlistp, mach_msg_type_number_t *newlistlen,
48                      uid_t *exist, mach_msg_type_number_t nexist,
49                      uid_t *new, mach_msg_type_number_t nnew)
50     {
51       error_t urp;
52       int i, j, k;
53       vm_size_t offset;
54
55       urp = vm_allocate (mach_task_self (), (vm_address_t *) newlistp,
56                          nexist + nnew * sizeof (uid_t), 1);
57       if (urp)
58         return urp;
59
60       j = 0;
61       for (i = 0; i < nexist; i++)
62         (*newlistp)[j++] = exist[i];
63
64       for (i = 0; i < nnew; i++)
65         {
66           for (k = 0; k < nexist; k++)
67             if (exist[k] == new[i])
68               break;
69           if (k < nexist)
70             continue;
71
72           (*newlistp)[j++] = new[i];
73         }
74
75       offset = (round_page (nexist + nnew * sizeof (uid_t))
76                 - round_page (j * sizeof (uid_t)));
77       if (offset)
78         vm_deallocate (mach_task_self (),
79                        (vm_address_t) (*newlistp
80                                        + (nexist + nnew * sizeof (uid_t))),
81                        offset);
82       *newlistlen = j;
83       return 0;
84     }
85
86   /* Find out what ids ADDAUTH refers to */
87
88   genuids = gengids = auxuids = auxgids = 0;
89   ngenuids = ngengids = nauxuids = nauxgids = 0;
90   err = __auth_getids (addauth,
91                        &genuids, &ngenuids,
92                        &auxuids, &nauxuids,
93                        &gengids, &ngengids,
94                        &auxgids, &nauxgids);
95   if (err)
96     return err;
97
98   /* OR in these ids to what we already have, creating a new list. */
99
100   HURD_CRITICAL_BEGIN;
101   __mutex_lock (&_hurd_id.lock);
102   _hurd_check_ids ();
103
104 #define MAKE(genaux,uidgid)                                                 \
105   make_list (&new ## genaux ## uidgid ## s,                                 \
106              &nnew ## genaux ## uidgid ## s,                                \
107              _hurd_id.genaux.uidgid ## s,                                   \
108              _hurd_id.genaux.n ## uidgid ## s,                              \
109              genaux ## uidgid ## s,                                         \
110              n ## genaux ## uidgid ## s)
111
112   err = MAKE (gen, uid);
113   if (!err)
114     MAKE (aux, uid);
115   if (!err)
116     MAKE (gen, gid);
117   if (!err)
118     MAKE (aux, gid);
119 #undef MAKE
120
121   __mutex_unlock (&_hurd_id.lock);
122   HURD_CRITICAL_END;
123
124
125   /* Create the new auth port */
126
127   if (!err)
128     err = __USEPORT (AUTH,
129                      __auth_makeauth (port,
130                                       &addauth, MACH_MSG_TYPE_MOVE_SEND, 1,
131                                       newgenuids, nnewgenuids,
132                                       newauxuids, nnewauxuids,
133                                       newgengids, nnewgengids,
134                                       newauxgids, nnewauxgids,
135                                       &newauth));
136
137 #define freeup(array, len) \
138   if (array) \
139     vm_deallocate (mach_task_self (), (vm_address_t) array, \
140                    len * sizeof (uid_t));
141
142   freeup (genuids, ngenuids);
143   freeup (auxuids, nauxuids);
144   freeup (gengids, ngengids);
145   freeup (auxgids, nauxgids);
146   freeup (newgenuids, nnewgenuids);
147   freeup (newauxuids, nnewauxuids);
148   freeup (newgengids, nnewgengids);
149   freeup (newauxgids, nnewauxgids);
150 #undef freeup
151
152   if (err)
153     return err;
154
155   /* And install it. */
156
157   err = __setauth (newauth);
158   __mach_port_deallocate (__mach_task_self (), newauth);
159   if (err)
160     return errno;
161
162   return 0;
163 }
164
165 kern_return_t
166 _S_msg_del_auth (mach_port_t me,
167                  task_t task,
168                  intarray_t uids, mach_msg_type_number_t nuids,
169                  intarray_t gids, mach_msg_type_number_t ngids)
170 {
171   error_t err;
172   auth_t newauth;
173
174   if (!_hurd_refport_secure_p (task))
175     return EPERM;
176
177   HURD_CRITICAL_BEGIN;
178   __mutex_lock (&_hurd_id.lock);
179   err = _hurd_check_ids ();
180
181   if (!err)
182     {
183       size_t i, j;
184       size_t nu = _hurd_id.gen.nuids, ng = _hurd_id.gen.ngids;
185       uid_t newu[nu];
186       gid_t newg[ng];
187
188       memcpy (newu, _hurd_id.gen.uids, nu * sizeof (uid_t));
189       memcpy (newg, _hurd_id.gen.gids, ng * sizeof (gid_t));
190
191       for (j = 0; j < nuids; ++j)
192         {
193           const uid_t uid = uids[j];
194           for (i = 0; i < nu; ++i)
195             if (newu[i] == uid)
196               /* Move the last uid into this slot, and decrease the
197                  number of uids so the last slot is no longer used.  */
198               newu[i] = newu[--nu];
199         }
200       __vm_deallocate (__mach_task_self (),
201                        (vm_address_t) uids, nuids * sizeof (uid_t));
202
203       for (j = 0; j < ngids; ++j)
204         {
205           const gid_t gid = gids[j];
206           for (i = 0; i < nu; ++i)
207             if (newu[i] == gid)
208               /* Move the last gid into this slot, and decrease the
209                  number of gids so the last slot is no longer used.  */
210               newu[i] = newu[--nu];
211         }
212       __vm_deallocate (__mach_task_self (),
213                        (vm_address_t) gids, ngids * sizeof (gid_t));
214
215       err = __USEPORT (AUTH, __auth_makeauth
216                        (port,
217                         NULL, MACH_MSG_TYPE_COPY_SEND, 0,
218                         newu, nu,
219                         _hurd_id.aux.uids, _hurd_id.aux.nuids,
220                         newg, ng,
221                         _hurd_id.aux.uids, _hurd_id.aux.ngids,
222                         &newauth));
223     }
224   __mutex_unlock (&_hurd_id.lock);
225   HURD_CRITICAL_END;
226
227   if (err)
228     return err;
229
230   err = __setauth (newauth);
231   __mach_port_deallocate (__mach_task_self (), newauth);
232   if (err)
233     return errno;
234
235   return 0;
236 }