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