3c6ef9547e006e423ee3817a558efb861abfc409
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / solaris2 / kopensolaris-gnu / priv.c
1 /* Copyright (C) 2008 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by David Bartley <dtbartle@csclub.uwaterloo.ca>, 2008.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <inline-syscall.h>
21 #include <privP.h>
22 #include <priv.h>
23 #include <sys/priocntl.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <stdarg.h>
27
28 DECLARE_INLINE_SYSCALL (int, privsys, int code, priv_op_t op,
29     priv_ptype_t type, void *buf, size_t bufsize);
30
31 /* Docs: http://docs.sun.com/app/docs/doc/816-5168/6mbb3hrjc
32          http://docs.sun.com/app/docs/doc/816-5168/6mbb3hrj7
33          http://docs.sun.com/app/docs/doc/816-5167/setppriv-2 */
34
35 __libc_lock_define_initialized_recursive (, __priv_lock);
36 libc_freeres_ptr (static priv_impl_info_t *__info);
37
38 /* Note: Almost everything that uses getprivimplinfo assumes it won't fail so
39    we assert that this call succeeds.  */
40 const priv_impl_info_t * getprivimplinfo (void)
41 {
42   if (__info)
43     return __info;
44
45   __libc_lock_lock_recursive (__priv_lock);
46
47   /* First call: get header.  */
48   priv_impl_info_t _info;
49   int res = INLINE_SYSCALL (privsys, 5, PRIVSYS_GETIMPLINFO, 0, 0, &_info,
50       sizeof(_info));
51   if (res == 0)
52     {
53       /* Second call: alloc and get full priv_impl_info_t.  */
54       size_t info_size = PRIV_IMPL_INFO_SIZE (&_info);
55       __info = malloc (info_size);
56       assert (__info);
57       res = INLINE_SYSCALL (privsys, 5, PRIVSYS_GETIMPLINFO, 0, 0, __info,
58           info_size);
59       assert (res == 0);
60     }
61
62   __libc_lock_unlock_recursive (__priv_lock);
63   return __info;
64 }
65
66
67 int getppriv (priv_ptype_t which, priv_set_t *set)
68 {
69   int setn = priv_getsetbyname (which);
70   if (setn == -1)
71     return -1;
72
73   return INLINE_SYSCALL (privsys, 5, PRIVSYS_GETPPRIV, 0, (priv_ptype_t)setn,
74       (void *)set, __PRIVSETSIZE);
75 }
76
77
78 int setppriv (priv_op_t op, priv_ptype_t which, const priv_set_t *set)
79 {
80   int setn = priv_getsetbyname (which);
81   if (setn == -1)
82     return -1;
83
84   return INLINE_SYSCALL (privsys, 5, PRIVSYS_GETPPRIV, op, (priv_ptype_t)setn,
85       (void *)set, __PRIVSETSIZE);
86 }
87
88
89 priv_set_t *priv_allocset (void)
90 {
91   return malloc (__PRIVSETSIZE);
92 }
93
94
95 void priv_freeset (priv_set_t *sp)
96 {
97   free (sp);
98 }
99
100
101 int priv_getbyname (const char *privname)
102 {
103   const priv_data_t *pd = __priv_parse_data_cached ();
104   if (!pd)
105     return -1;
106
107   for (uint32_t i = 0; i < pd->pd_privnames_cnt; i++)
108     {
109       if (strcasecmp (pd->pd_privnames[i], privname) == 0)
110         return i;
111     }
112
113   __set_errno (EINVAL);
114   return -1;
115 }
116
117
118 const char *priv_getbynum (int privnum)
119 {
120   const priv_data_t *pd = __priv_parse_data_cached ();
121   if (!pd)
122     return NULL;
123
124   if (privnum < 0 || privnum >= pd->pd_privnames_cnt)
125     {
126       __set_errno (EINVAL);
127       return NULL;
128     }
129
130   return pd->pd_privnames[privnum];
131 }
132
133
134 int priv_getsetbyname (const char *privsetname)
135 {
136   const priv_data_t *pd = __priv_parse_data_cached ();
137   if (!pd)
138     return -1;
139
140   for (uint32_t i = 0; i < pd->pd_setnames_cnt; i++)
141     {
142       if (strcasecmp (pd->pd_setnames[i], privsetname) == 0)
143         return i;
144     }
145
146   __set_errno (EINVAL);
147   return -1;
148 }
149
150
151 const char *priv_getsetbynum (int privsetnum)
152 {
153   const priv_data_t *pd = __priv_parse_data_cached ();
154   if (!pd)
155     return NULL;
156
157   if (privsetnum < 0 || privsetnum >= pd->pd_setnames_cnt)
158     {
159       __set_errno (EINVAL);
160       return NULL;
161     }
162
163   return pd->pd_setnames[privsetnum];
164 }
165
166
167 void priv_emptyset (priv_set_t *sp)
168 {
169   memset (sp, 0, __PRIVSETSIZE);
170 }
171
172
173 void priv_fillset(priv_set_t *sp)
174 {
175   memset (sp, ~0, __PRIVSETSIZE);
176 }
177
178
179 void priv_copyset (const priv_set_t *src, priv_set_t *dst)
180 {
181   memcpy (dst, src, __PRIVSETSIZE);
182 }
183
184
185 int priv_addset (priv_set_t *sp, const char *priv)
186 {
187   int privn = priv_getbyname (priv);
188   if (privn == -1)
189     return -1;
190
191   ((priv_chunk_t *)sp)[__PRIVELT (privn)] |= __PRIVMASK (privn);
192   return 0;
193 }
194
195
196 int priv_delset (priv_set_t *sp, const char *priv)
197 {
198   int privn = priv_getbyname (priv);
199   if (privn == -1)
200     return -1;
201
202   ((priv_chunk_t *)sp)[__PRIVELT (privn)] &= ~__PRIVMASK (privn);
203   return 0;
204 }
205
206
207 void priv_intersect (const priv_set_t *src, priv_set_t *dst)
208 {
209   priv_chunk_t *pcsrc = (priv_chunk_t *)src;
210   priv_chunk_t *pcdst = (priv_chunk_t *)dst;
211   for (int i = 0; i < __PRIVSETCHUNKS; i++)
212     pcdst[__PRIVELT (i)] &= pcsrc[__PRIVELT (i)];
213 }
214
215
216 void priv_union (const priv_set_t *src, priv_set_t *dst)
217 {
218   priv_chunk_t *pcsrc = (priv_chunk_t *)src;
219   priv_chunk_t *pcdst = (priv_chunk_t *)dst;
220   for (int i = 0; i < __PRIVSETCHUNKS; i++)
221     pcdst[__PRIVELT (i)] |= pcsrc[__PRIVELT (i)];
222 }
223
224
225 void priv_inverse(priv_set_t *sp)
226 {
227   priv_chunk_t *pcsp = (priv_chunk_t *)sp;
228   for (int i = 0; i < __PRIVSETCHUNKS; i++)
229     pcsp[i] = ~pcsp[i];
230 }
231
232
233 boolean_t priv_isemptyset (const priv_set_t *sp)
234 {
235   priv_chunk_t *pcsp = (priv_chunk_t *)sp;
236   for (int i = 0; i < __PRIVSETCHUNKS; i++)
237     if (pcsp[i])
238       return B_FALSE;
239   return B_TRUE;
240 }
241
242
243 boolean_t priv_isfullset (const priv_set_t *sp)
244 {
245   priv_chunk_t *pcsp = (priv_chunk_t *)sp;
246   for (int i = 0; i < __PRIVSETCHUNKS; i++)
247     if (~pcsp[i])
248       return B_FALSE;
249   return B_TRUE;
250 }
251
252
253 boolean_t priv_ismember (const priv_set_t *sp, const char *priv)
254 {
255   int privn = priv_getbyname (priv);
256   if (privn == -1)
257     return B_FALSE;
258
259   return (((priv_chunk_t *)sp)[__PRIVELT (privn)] & __PRIVMASK (privn)) ?
260       B_TRUE : B_FALSE;
261 }
262
263
264 boolean_t priv_issubset (const priv_set_t *src, const priv_set_t *dst)
265 {
266   priv_chunk_t *pcsrc = (priv_chunk_t *)src;
267   priv_chunk_t *pcdst = (priv_chunk_t *)dst;
268   for (int i = 0; i < __PRIVSETCHUNKS; i++)
269     if ((pcsrc[__PRIVELT (i)] & pcdst[__PRIVELT (i)]) != pcsrc[__PRIVELT (i)])
270       return B_FALSE;
271   return B_TRUE;
272 }
273
274
275 int priv_set (priv_op_t op, priv_ptype_t which, ...)
276 {
277   va_list ap;
278   va_start (ap, which);
279
280   priv_set_t *pset = priv_allocset ();
281   if (!pset)
282     return -1;
283
284   const char *priv;
285   while ((priv = va_arg (ap, const char *)))
286     {
287       if (priv_addset (pset, priv) == -1)
288         return -1;
289     }
290
291   int ret;
292   if (which == NULL)
293     {
294       /* Set all sets.  */
295       for (int i = 0; i < __PRIVSETCHUNKS; i++)
296         {
297           ret = setppriv (op, which, pset);
298           if (ret == -1)
299             break;
300         }
301     }
302   else
303     {
304       ret = setppriv (op, which, pset);
305     }
306
307   priv_freeset (pset);
308   return 0;
309 }
310
311 boolean_t priv_ineffect (const char *priv)
312 {
313   priv_set_t *pset = priv_allocset ();
314   if (!pset)
315     return B_FALSE;
316
317   int res = getppriv (PRIV_EFFECTIVE, pset);
318   if (res == -1)
319     return B_FALSE;
320
321   boolean_t ret = priv_ismember (pset, priv);
322
323   priv_freeset (pset);
324
325   return ret;
326 }