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