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 #include <ucred_priv.h>
25 #include <assert.h>
26
27 DECLARE_INLINE_SYSCALL (int, getpeerucred, int fd, ucred_t *ucred);
28 DECLARE_INLINE_SYSCALL (int, ucred_get, pid_t pid, ucred_t *ucred);
29 DECLARE_INLINE_SYSCALL (int, syslabeling, void);
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 ucred_t *ucred_get (pid_t pid)
35 {
36   size_t uc_size = ucred_size ();
37   ucred_t *uc = malloc (uc_size);
38   if (!uc)
39     return NULL;
40   uc->uc_size = uc_size;
41
42   INLINE_SYSCALL (ucred_get, 2, pid, uc);
43
44   return uc;
45 }
46
47
48 void ucred_free (ucred_t *uc)
49 {
50   free(uc);
51 }
52
53
54 #define MAKE_PRCRED_T_CALL(field, type)                                     \
55   type ucred_get##field (const ucred_t *uc)                                 \
56   {                                                                         \
57     if (uc->uc_credoff == 0)                                                \
58       {                                                                     \
59         __set_errno(EINVAL);                                                \
60         return (type)-1;                                                    \
61       }                                                                     \
62     return (type)((prcred_t *)((char *)uc + uc->uc_credoff))->pr_##field;   \
63    }
64
65 MAKE_PRCRED_T_CALL (euid, uid_t)
66 MAKE_PRCRED_T_CALL (ruid, uid_t)
67 MAKE_PRCRED_T_CALL (suid, uid_t)
68 MAKE_PRCRED_T_CALL (egid, gid_t)
69 MAKE_PRCRED_T_CALL (rgid, gid_t)
70 MAKE_PRCRED_T_CALL (sgid, gid_t)
71
72
73 int ucred_getgroups (const ucred_t *uc, const gid_t **groups)
74 {
75   if (uc->uc_credoff == 0 || groups == NULL)
76     {
77       __set_errno(EINVAL);
78       return -1;
79     }
80
81   /* The docs say that *groups should always be free'd, so we make sure
82      it's NULL if there are no groups.  */
83   prcred_t *cred = (prcred_t *)((char *)uc + uc->uc_credoff);
84   if (cred->pr_ngroups > 0)
85     *groups = cred->pr_groups;
86   else
87     *groups = NULL;
88
89   return cred->pr_ngroups;
90 }
91
92
93 const priv_set_t *ucred_getprivset (const ucred_t *uc, const char *set)
94 {
95   // TODO
96   __set_errno (ENOSYS);
97   return NULL;
98 }
99
100
101 pid_t ucred_getpid (const ucred_t *uc)
102 {
103   if(uc->uc_pid == (pid_t)-1)
104     __set_errno (EINVAL);
105
106   return uc->uc_pid;
107 }
108
109
110 projid_t ucred_getprojid (const ucred_t *uc)
111 {
112   if(uc->uc_projid == (projid_t)-1)
113     __set_errno (EINVAL);
114
115   return uc->uc_projid;
116 }
117
118
119 zoneid_t ucred_getzoneid (const ucred_t *uc)
120 {
121   if(uc->uc_zoneid == (zoneid_t)-1)
122     __set_errno (EINVAL);
123
124   return uc->uc_zoneid;
125 }
126
127
128 unsigned int ucred_getpflags (const ucred_t *uc, unsigned int flags)
129 {
130   // TODO
131   __set_errno (ENOSYS);
132   return -1;
133 }
134
135
136 m_label_t *ucred_getlabel (const ucred_t *uc)
137 {
138   int syslabeling = INLINE_SYSCALL (syslabeling, 0);
139   if (!syslabeling || uc->uc_labeloff == 0)
140     {
141       __set_errno (EINVAL);
142       return NULL;
143     }
144
145   return (m_label_t *)((char *)uc + uc->uc_labeloff);
146 }
147
148
149 size_t ucred_size (void)
150 {
151     extern int __getprivimplinfo_cached (priv_impl_info_t **info);
152
153     /* the docs don't say what to do in case of error */
154     priv_impl_info_t *info;
155     assert (__getprivimplinfo_cached (&info) == 0);
156
157     /* XXX: We shouldn't use AUDITINFO64_ADDR_T_SIZE and BSLABEL_T_SIZE.  */
158     return sizeof(ucred_t) + sizeof(prcred_t) + sizeof(prpriv_t) +
159         ((int)sysconf (_SC_NGROUPS_MAX) - 1) * sizeof(gid_t) +
160         sizeof(priv_chunk_t) * (info->priv_setsize * info->priv_nsets - 1) +
161         info->priv_infosize + AUDITINFO64_ADDR_T_SIZE + BSLABEL_T_SIZE;
162 }
163
164
165 int getpeerucred (int fd, ucred_t **ucred)
166 {
167   ucred_t *uc = *ucred;
168
169   /* alloc ucred if needed */
170   if(*ucred == NULL)
171     {
172       size_t uc_size = ucred_size ();
173       ucred_t *uc = malloc (uc_size);
174       if (!uc)
175         return -1;
176       uc->uc_size = uc_size;
177       *ucred = uc;
178     }
179
180   int result = INLINE_SYSCALL (getpeerucred, 2, fd, uc);
181   if (result == -1 && *ucred == NULL)
182       free (uc);
183   else if (result == 0 && *ucred == NULL)
184       *ucred = uc;
185
186   return result;
187 }