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