xref: /illumos-gate/usr/src/uts/common/syscall/ucredsys.c (revision 34a0f871d192b33b865455a8812a3d34c1866315)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/param.h>
29 #include <sys/types.h>
30 #include <sys/ucred.h>
31 #include <sys/file.h>
32 #include <sys/errno.h>
33 #include <sys/systm.h>
34 #include <sys/stream.h>
35 #include <sys/strsun.h>
36 #include <sys/stropts.h>
37 #include <sys/vfs.h>
38 #include <sys/vnode.h>
39 #include <sys/cmn_err.h>
40 #include <sys/socket.h>
41 #include <sys/strsubr.h>
42 #include <c2/audit.h>
43 
44 /*
45  * Getpeerucred system call implementation.
46  */
47 static int
48 getpeerucred(int fd, void *buf)
49 {
50 	file_t *fp;
51 	struct ucred_s *uc;
52 	vnode_t *vp;
53 	k_peercred_t kpc;
54 	int err;
55 	int32_t rval;
56 
57 	kpc.pc_cr = NULL;
58 	kpc.pc_cpid = -1;
59 
60 	if ((fp = getf(fd)) == NULL)
61 		return (set_errno(EBADF));
62 
63 	vp = fp->f_vnode;
64 
65 	switch (vp->v_type) {
66 	case VFIFO:
67 	case VSOCK:
68 		err = VOP_IOCTL(vp, _I_GETPEERCRED, (intptr_t)&kpc,
69 		    FKIOCTL, CRED(), &rval);
70 		break;
71 	case VCHR: {
72 		struct strioctl strioc;
73 
74 		if (vp->v_stream == NULL) {
75 			err = ENOTSUP;
76 			break;
77 		}
78 		strioc.ic_cmd = _I_GETPEERCRED;
79 		strioc.ic_timout = INFTIM;
80 		strioc.ic_len = (int)sizeof (k_peercred_t);
81 		strioc.ic_dp = (char *)&kpc;
82 
83 		err = strdoioctl(vp->v_stream, &strioc, FNATIVE|FKIOCTL,
84 		    STR_NOSIG|K_TO_K, CRED(), &rval);
85 
86 		/*
87 		 * Map all unexpected error codes to ENOTSUP.
88 		 */
89 		switch (err) {
90 		case 0:
91 		case ENOTSUP:
92 		case ENOTCONN:
93 		case ENOMEM:
94 			break;
95 		default:
96 			err = ENOTSUP;
97 			break;
98 		}
99 		break;
100 	}
101 	default:
102 		err = ENOTSUP;
103 		break;
104 	}
105 	releasef(fd);
106 
107 	/*
108 	 * If someone gave us a credential, err will be 0.
109 	 */
110 	if (kpc.pc_cr != NULL) {
111 		ASSERT(err == 0);
112 
113 		uc = cred2ucred(kpc.pc_cr, kpc.pc_cpid, NULL, CRED());
114 
115 		crfree(kpc.pc_cr);
116 
117 		err = copyout(uc, buf, uc->uc_size);
118 
119 		kmem_free(uc, uc->uc_size);
120 
121 		if (err != 0)
122 			return (set_errno(EFAULT));
123 
124 		return (0);
125 	}
126 	return (set_errno(err));
127 }
128 
129 static int
130 ucred_get(pid_t pid, void *ubuf)
131 {
132 	proc_t *p;
133 	cred_t *pcr;
134 	int err;
135 	struct ucred_s *uc;
136 
137 	if (pid == P_MYID || pid == curproc->p_pid) {
138 		pcr = CRED();
139 		crhold(pcr);
140 		pid = curproc->p_pid;
141 	} else {
142 		cred_t	*updcred = NULL;
143 
144 		if (pid < 0)
145 			return (set_errno(EINVAL));
146 
147 		if (audit_active)
148 			updcred = cralloc();
149 
150 		mutex_enter(&pidlock);
151 		p = prfind(pid);
152 
153 		if (p == NULL) {
154 			mutex_exit(&pidlock);
155 			if (updcred != NULL)
156 				crfree(updcred);
157 			return (set_errno(ESRCH));
158 		}
159 
160 		/*
161 		 * Assure that audit data in cred is up-to-date.
162 		 * updcred will be used or freed.
163 		 */
164 		if (audit_active)
165 			audit_update_context(p, updcred);
166 
167 		err = priv_proc_cred_perm(CRED(), p, &pcr, VREAD);
168 		mutex_exit(&pidlock);
169 
170 		if (err != 0)
171 			return (set_errno(err));
172 	}
173 
174 	uc = cred2ucred(pcr, pid, NULL, CRED());
175 
176 	crfree(pcr);
177 
178 	err = copyout(uc, ubuf, uc->uc_size);
179 
180 	kmem_free(uc, uc->uc_size);
181 
182 	if (err)
183 		return (set_errno(EFAULT));
184 
185 	return (0);
186 }
187 
188 int
189 ucredsys(int code, int obj, void *buf)
190 {
191 	switch (code) {
192 	case UCREDSYS_UCREDGET:
193 		return (ucred_get((pid_t)obj, buf));
194 	case UCREDSYS_GETPEERUCRED:
195 		return (getpeerucred(obj, buf));
196 	default:
197 		return (set_errno(EINVAL));
198 	}
199 }
200 
201 #ifdef _SYSCALL32_IMPL
202 int
203 ucredsys32(int arg1, int arg2, caddr32_t arg3)
204 {
205 	return (ucredsys(arg1, arg2, (void *)(uintptr_t)arg3));
206 }
207 #endif
208