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 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 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 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 202 ucredsys32(int arg1, int arg2, caddr32_t arg3) 203 { 204 return (ucredsys(arg1, arg2, (void *)(uintptr_t)arg3)); 205 } 206 #endif 207