Fix getpeerucred and ucred_get
[kopensolaris-gnu/glibc.git] / sysdeps / unix / sysv / solaris2 / kopensolaris-gnu / ucred.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 <unistd.h>
22 #include <ucredP.h>
23 #include <auditP.h>
24 #include <priv.h>
25 #include <procfs.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 DECLARE_INLINE_SYSCALL (int, getpeerucred, int fd, ucred_t *ucred);
30 DECLARE_INLINE_SYSCALL (int, ucred_get, pid_t pid, ucred_t *ucred);
31
32 /* Docs: http://docs.sun.com/app/docs/doc/816-5168/ucred-get-3c?a=view
33          http://docs.sun.com/app/docs/doc/816-5168/getpeerucred-3c?l=ru&a=view */
34
35
36 ucred_t *_ucred_alloc (void)
37 {
38   size_t uc_size = ucred_size ();
39   ucred_t *uc = malloc (uc_size);
40   if (uc)
41     uc->uc_size = uc_size;
42   return uc;
43 }
44
45
46 ucred_t *ucred_get (pid_t pid)
47 {
48   ucred_t *uc = _ucred_alloc ();
49   if (!uc)
50     return NULL;
51
52   int res = INLINE_SYSCALL (ucred_get, 2, pid, uc);
53   if (res != 0)
54     return NULL;
55
56   return uc;
57 }
58
59
60 void ucred_free (ucred_t *uc)
61 {
62   free(uc);
63 }
64
65
66 uid_t ucred_geteuid (const ucred_t *uc)
67 {
68   if (uc->uc_credoff == 0)
69     {
70       __set_errno (EINVAL);
71       return (uid_t)-1;
72     }
73
74   return (uid_t)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_euid;
75 }
76
77
78 uid_t ucred_getruid (const ucred_t *uc)
79 {
80   if (uc->uc_credoff == 0)
81     {
82       __set_errno (EINVAL);
83       return (uid_t)-1;
84     }
85
86   return (uid_t)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_ruid;
87 }
88
89
90 uid_t ucred_getsuid (const ucred_t *uc)
91 {
92   if (uc->uc_credoff == 0)
93     {
94       __set_errno (EINVAL);
95       return (uid_t)-1;
96     }
97
98   return (uid_t)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_suid;
99 }
100
101
102 gid_t ucred_getegid (const ucred_t *uc)
103 {
104   if (uc->uc_credoff == 0)
105     {
106       __set_errno (EINVAL);
107       return (gid_t)-1;
108     }
109
110   return (gid_t)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_egid;
111 }
112
113
114 gid_t ucred_getrgid (const ucred_t *uc)
115 {
116   if (uc->uc_credoff == 0)
117     {
118       __set_errno (EINVAL);
119       return (gid_t)-1;
120     }
121
122   return (gid_t)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_rgid;
123 }
124
125
126 gid_t ucred_getsgid (const ucred_t *uc)
127 {
128   if (uc->uc_credoff == 0)
129     {
130       __set_errno(EINVAL);                                                \
131       return (gid_t)-1;                                                    \
132     }
133
134   return (gid_t)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_sgid;
135 }
136
137
138 int ucred_getgroups (const ucred_t *uc, const gid_t **groups)
139 {
140   if (uc->uc_credoff == 0 || groups == NULL)
141     {
142       __set_errno (EINVAL);
143       return -1;
144     }
145
146   /* The docs say that *groups should always be free'd, so we make sure
147      it's NULL if there are no groups.  */
148   prcred_t *cred = (prcred_t *)((char *)uc + uc->uc_credoff);
149   if (cred->pr_ngroups > 0)
150     *groups = cred->pr_groups;
151   else
152     *groups = NULL;
153
154   return cred->pr_ngroups;
155 }
156
157
158 const priv_set_t *ucred_getprivset (const ucred_t *uc, const char *set)
159 {
160   /* Get prpriv_t.  */
161   if (uc->uc_privoff == 0)
162     {
163       __set_errno (EINVAL);
164       return NULL;
165     }
166   prpriv_t * pr = (prpriv_t *)((char *)uc + uc->uc_privoff);
167
168   /* Get priv set number.  */
169   int setnum = priv_getsetbyname (set);
170   if (setnum == -1)
171     return NULL;
172
173   return (priv_set_t *)&pr->pr_sets[setnum * pr->pr_setsize];
174 }
175
176
177 pid_t ucred_getpid (const ucred_t *uc)
178 {
179   if(uc->uc_pid == (pid_t)-1)
180     __set_errno (EINVAL);
181
182   return uc->uc_pid;
183 }
184
185
186 projid_t ucred_getprojid (const ucred_t *uc)
187 {
188   if(uc->uc_projid == (projid_t)-1)
189     __set_errno (EINVAL);
190
191   return uc->uc_projid;
192 }
193
194
195 zoneid_t ucred_getzoneid (const ucred_t *uc)
196 {
197   if(uc->uc_zoneid == (zoneid_t)-1)
198     __set_errno (EINVAL);
199
200   return uc->uc_zoneid;
201 }
202
203
204 unsigned int ucred_getpflags (const ucred_t *uc, unsigned int flags)
205 {
206   /* Get prpriv_t.  */
207   if (uc->uc_privoff == 0)
208     {
209       __set_errno (EINVAL);
210       return (unsigned int)-1;
211     }
212   prpriv_t *pr = (prpriv_t *)((char *)uc + uc->uc_privoff);
213
214   /* Iterate over all priv_info_t's. Note that the first priv_info_t follows
215      the list of priv sets.  */
216   priv_info_t * pi = (priv_info_t *)&pr->pr_sets[pr->pr_nsets * pr->pr_setsize];
217   uint32_t left = pr->pr_infosize;
218   while (left)
219     {
220       if (pi->priv_info_type == PRIV_INFO_FLAGS)
221         return ((priv_info_uint_t *)pi)->val & flags;
222
223       left -= pi->priv_info_size;
224       pi = (priv_info_t *)((char *)pi + pi->priv_info_size);
225     }
226
227   /* We didn't find PRIV_INFO_FLAGS.  */
228   __set_errno (EINVAL);
229   return (unsigned int)-1;
230 }
231
232
233 m_label_t *ucred_getlabel (const ucred_t *uc)
234 {
235   extern int is_system_labeled (void);
236
237   if (!is_system_labeled () || uc->uc_labeloff == 0)
238     {
239       __set_errno (EINVAL);
240       return NULL;
241     }
242
243   return (m_label_t *)((char *)uc + uc->uc_labeloff);
244 }
245
246
247 au_id_t ucred_getauid (const ucred_t *uc)
248 {
249   if (uc->uc_audoff == 0)
250     return AU_NOAUDITID;
251   const auditinfo64_addr_t *info = (auditinfo64_addr_t *)
252       ((char *)uc + uc->uc_audoff);
253
254   return info->ai_auid;
255 }
256
257
258 au_asid_t ucred_getasid (const ucred_t *uc)
259 {
260   if (uc->uc_audoff == 0)
261     return (au_asid_t)-1;
262   const auditinfo64_addr_t *info = (auditinfo64_addr_t *)
263       ((char *)uc + uc->uc_audoff);
264
265   return info->ai_asid;
266 }
267
268
269 const au_tid64_addr_t * ucred_getatid (const ucred_t *uc)
270 {
271   if (uc->uc_audoff == 0)
272     {
273       __set_errno (EINVAL);
274       return NULL;
275     }
276   const auditinfo64_addr_t *info = (auditinfo64_addr_t *)
277       ((char *)uc + uc->uc_audoff);
278
279   return &info->ai_termid;
280 }
281
282
283 const au_mask_t * ucred_getamask (const ucred_t *uc)
284 {
285   if (uc->uc_audoff == 0)
286     {
287       __set_errno (EINVAL);
288       return NULL;
289     }
290   const auditinfo64_addr_t *info = (auditinfo64_addr_t *)
291       ((char *)uc + uc->uc_audoff);
292
293   return &info->ai_mask;
294 }
295
296
297 size_t ucred_size (void)
298 {
299   const priv_impl_info_t *info = getprivimplinfo ();
300
301   return sizeof (ucred_t) + sizeof (prcred_t) + sizeof (prpriv_t) +
302     ((int)sysconf (_SC_NGROUPS_MAX) - 1) * sizeof (gid_t) +
303     sizeof (priv_chunk_t) * (info->priv_setsize * info->priv_nsets - 1) +
304     info->priv_infosize + sizeof (auditinfo64_addr_t) + BSLABEL_T_SIZE;
305 }
306
307
308 int getpeerucred (int fd, ucred_t **ucred)
309 {
310   ucred_t *uc = *ucred;
311
312   /* alloc ucred if needed */
313   if (*ucred == NULL)
314     {
315       uc = _ucred_alloc ();
316       if (!uc)
317         return -1;
318       *ucred = uc;
319     }
320
321   int res = INLINE_SYSCALL (getpeerucred, 2, fd, uc);
322   if (res == -1 && *ucred == NULL)
323       free (uc);
324   else if (res == 0 && *ucred == NULL)
325       *ucred = uc;
326
327   return res;
328 }