Home | History | Annotate | Download | only in syscall
      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 2007 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, NULL);
     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