1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #include <sys/ucred.h>
29 #include <sys/file.h>
30 #include <sys/errno.h>
31 #include <sys/systm.h>
32 #include <sys/stream.h>
33 #include <sys/strsun.h>
34 #include <sys/stropts.h>
35 #include <sys/vfs.h>
36 #include <sys/vnode.h>
37 #include <sys/cmn_err.h>
38 #include <sys/socket.h>
39 #include <sys/strsubr.h>
40 #include <c2/audit.h>
41
42 /*
43 * Getpeerucred system call implementation.
44 */
45 static int
getpeerucred(int fd,void * buf)46 getpeerucred(int fd, void *buf)
47 {
48 file_t *fp;
49 struct ucred_s *uc;
50 vnode_t *vp;
51 k_peercred_t kpc;
52 int err;
53 int32_t rval;
54
55 kpc.pc_cr = NULL;
56 kpc.pc_cpid = -1;
57
58 if ((fp = getf(fd)) == NULL)
59 return (set_errno(EBADF));
60
61 vp = fp->f_vnode;
62
63 switch (vp->v_type) {
64 case VFIFO:
65 case VSOCK:
66 err = VOP_IOCTL(vp, _I_GETPEERCRED, (intptr_t)&kpc,
67 FKIOCTL, CRED(), &rval, NULL);
68 break;
69 case VCHR: {
70 struct strioctl strioc;
71
72 if (vp->v_stream == NULL) {
73 err = ENOTSUP;
74 break;
75 }
76 strioc.ic_cmd = _I_GETPEERCRED;
77 strioc.ic_timout = INFTIM;
78 strioc.ic_len = (int)sizeof (k_peercred_t);
79 strioc.ic_dp = (char *)&kpc;
80
81 err = strdoioctl(vp->v_stream, &strioc, FNATIVE|FKIOCTL,
82 STR_NOSIG|K_TO_K, CRED(), &rval);
83
84 /*
85 * Map all unexpected error codes to ENOTSUP.
86 */
87 switch (err) {
88 case 0:
89 case ENOTSUP:
90 case ENOTCONN:
91 case ENOMEM:
92 break;
93 default:
94 err = ENOTSUP;
95 break;
96 }
97 break;
98 }
99 default:
100 err = ENOTSUP;
101 break;
102 }
103 releasef(fd);
104
105 /*
106 * If someone gave us a credential, err will be 0.
107 */
108 if (kpc.pc_cr != NULL) {
109 ASSERT(err == 0);
110
111 uc = cred2ucred(kpc.pc_cr, kpc.pc_cpid, NULL, CRED());
112
113 crfree(kpc.pc_cr);
114
115 err = copyout(uc, buf, uc->uc_size);
116
117 kmem_free(uc, uc->uc_size);
118
119 if (err != 0)
120 return (set_errno(EFAULT));
121
122 return (0);
123 }
124 return (set_errno(err));
125 }
126
127 static int
ucred_get(pid_t pid,void * ubuf)128 ucred_get(pid_t pid, void *ubuf)
129 {
130 proc_t *p;
131 cred_t *pcr;
132 int err;
133 struct ucred_s *uc;
134 uint32_t auditing = AU_AUDITING();
135
136 if (pid == P_MYID || pid == curproc->p_pid) {
137 pcr = CRED();
138 crhold(pcr);
139 pid = curproc->p_pid;
140 } else {
141 cred_t *updcred = NULL;
142
143 if (pid < 0)
144 return (set_errno(EINVAL));
145
146 if (auditing)
147 updcred = cralloc();
148
149 mutex_enter(&pidlock);
150 p = prfind(pid);
151
152 if (p == NULL) {
153 mutex_exit(&pidlock);
154 if (updcred != NULL)
155 crfree(updcred);
156 return (set_errno(ESRCH));
157 }
158
159 /*
160 * Assure that audit data in cred is up-to-date.
161 * updcred will be used or freed.
162 */
163 if (auditing)
164 audit_update_context(p, updcred);
165
166 err = priv_proc_cred_perm(CRED(), p, &pcr, VREAD);
167 mutex_exit(&pidlock);
168
169 if (err != 0)
170 return (set_errno(err));
171 }
172
173 uc = cred2ucred(pcr, pid, NULL, CRED());
174
175 crfree(pcr);
176
177 err = copyout(uc, ubuf, uc->uc_size);
178
179 kmem_free(uc, uc->uc_size);
180
181 if (err)
182 return (set_errno(EFAULT));
183
184 return (0);
185 }
186
187 int
ucredsys(int code,int obj,void * buf)188 ucredsys(int code, int obj, void *buf)
189 {
190 switch (code) {
191 case UCREDSYS_UCREDGET:
192 return (ucred_get((pid_t)obj, buf));
193 case UCREDSYS_GETPEERUCRED:
194 return (getpeerucred(obj, buf));
195 default:
196 return (set_errno(EINVAL));
197 }
198 }
199
200 #ifdef _SYSCALL32_IMPL
201 int
ucredsys32(int arg1,int arg2,caddr32_t arg3)202 ucredsys32(int arg1, int arg2, caddr32_t arg3)
203 {
204 return (ucredsys(arg1, arg2, (void *)(uintptr_t)arg3));
205 }
206 #endif
207