Merge branch 'master' of /opt/gnu-chroot/home/dtbartle/glibc-opensolaris
[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 <priv.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 #define MAKE_PRCRED_T_CALL(field, type)                                     \
67   type ucred_get##field (const ucred_t *uc)                                 \
68   {                                                                         \
69     if (uc->uc_credoff == 0)                                                \
70       {                                                                     \
71         __set_errno(EINVAL);                                                \
72         return (type)-1;                                                    \
73       }                                                                     \
74     return (type)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_##field;   \
75    }
76
77 MAKE_PRCRED_T_CALL (euid, uid_t)
78 MAKE_PRCRED_T_CALL (ruid, uid_t)
79 MAKE_PRCRED_T_CALL (suid, uid_t)
80 MAKE_PRCRED_T_CALL (egid, gid_t)
81 MAKE_PRCRED_T_CALL (rgid, gid_t)
82 MAKE_PRCRED_T_CALL (sgid, gid_t)
83
84
85 int ucred_getgroups (const ucred_t *uc, const gid_t **groups)
86 {
87   if (uc->uc_credoff == 0 || groups == NULL)
88     {
89       __set_errno (EINVAL);
90       return -1;
91     }
92
93   /* The docs say that *groups should always be free'd, so we make sure
94      it's NULL if there are no groups.  */
95   prcred_t *cred = (prcred_t *)((char *)uc + uc->uc_credoff);
96   if (cred->pr_ngroups > 0)
97     *groups = cred->pr_groups;
98   else
99     *groups = NULL;
100
101   return cred->pr_ngroups;
102 }
103
104
105 const priv_set_t *ucred_getprivset (const ucred_t *uc, const char *set)
106 {
107   /* Get prpriv_t.  */
108   if (uc->uc_privoff == 0)
109     {
110       __set_errno (EINVAL);
111       return NULL;
112     }
113   prpriv_t * pr = (prpriv_t *)((char *)uc + uc->uc_privoff);
114
115   /* Get priv set number.  */
116   int setnum = priv_getsetbyname (set);
117   if (setnum == -1)
118     return NULL;
119
120   return (priv_set_t *)&pr->pr_sets[setnum * pr->pr_setsize];
121 }
122
123
124 pid_t ucred_getpid (const ucred_t *uc)
125 {
126   if(uc->uc_pid == (pid_t)-1)
127     __set_errno (EINVAL);
128
129   return uc->uc_pid;
130 }
131
132
133 projid_t ucred_getprojid (const ucred_t *uc)
134 {
135   if(uc->uc_projid == (projid_t)-1)
136     __set_errno (EINVAL);
137
138   return uc->uc_projid;
139 }
140
141
142 zoneid_t ucred_getzoneid (const ucred_t *uc)
143 {
144   if(uc->uc_zoneid == (zoneid_t)-1)
145     __set_errno (EINVAL);
146
147   return uc->uc_zoneid;
148 }
149
150
151 unsigned int ucred_getpflags (const ucred_t *uc, unsigned int flags)
152 {
153   /* Get prpriv_t.  */
154   if (uc->uc_privoff == 0)
155     {
156       __set_errno (EINVAL);
157       return (unsigned int)-1;
158     }
159   prpriv_t *pr = (prpriv_t *)((char *)uc + uc->uc_privoff);
160
161   /* Iterate over all priv_info_t's. Note that the first priv_info_t follows
162      the list of priv sets.  */
163   priv_info_t * pi = (priv_info_t *)&pr->pr_sets[pr->pr_nsets * pr->pr_setsize];
164   uint32_t left = pr->pr_infosize;
165   while (left)
166     {
167       if (pi->priv_info_type == PRIV_INFO_FLAGS)
168         return ((priv_info_uint_t *)pi)->val & flags;
169
170       left -= pi->priv_info_size;
171       pi = (priv_info_t *)((char *)pi + pi->priv_info_size);
172     }
173
174   /* We didn't find PRIV_INFO_FLAGS.  */
175   __set_errno (EINVAL);
176   return (unsigned int)-1;
177 }
178
179
180 m_label_t *ucred_getlabel (const ucred_t *uc)
181 {
182   extern int is_system_labeled (void);
183
184   if (!is_system_labeled () || uc->uc_labeloff == 0)
185     {
186       __set_errno (EINVAL);
187       return NULL;
188     }
189
190   return (m_label_t *)((char *)uc + uc->uc_labeloff);
191 }
192
193
194 size_t ucred_size (void)
195 {
196     const priv_impl_info_t *info = getprivimplinfo ();
197
198     /* ucred_size cannot fail.  */
199     assert (info);
200
201     return UCRED_SIZE (info);
202 }
203
204
205 int getpeerucred (int fd, ucred_t **ucred)
206 {
207   ucred_t *uc = *ucred;
208
209   /* alloc ucred if needed */
210   if(*ucred == NULL)
211     {
212       ucred_t *uc = _ucred_alloc ();
213       if (!uc)
214         return -1;
215       *ucred = uc;
216     }
217
218   int res = INLINE_SYSCALL (getpeerucred, 2, fd, uc);
219   if (res == -1 && *ucred == NULL)
220       free (uc);
221   else if (res == 0 && *ucred == NULL)
222       *ucred = uc;
223
224   return res;
225 }