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