예제 #1
0
/*
 * Derive a new cred from the existing cred, but with a different label.
 */
cred_t *
copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
    uint32_t doi, int flags)
{
	ts_label_t *lbl = labelalloc(blabel, doi, flags);
	cred_t  *newcr = NULL;

	if (lbl != NULL) {
		newcr = copycred_from_tslabel(cr, lbl, flags);
		label_rele(lbl);
	}

	return (newcr);
}
예제 #2
0
/*
 * Derive a new cred from the existing cred, but with a different label.
 * To be used when a cred is being shared, but the label needs to be changed
 * by a caller without affecting other users
 */
cred_t *
copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
{
	cred_t *newcr = NULL;

	if ((newcr = crdup_flags(cr, flags)) != NULL) {
		if (newcr->cr_label != NULL)
			label_rele(newcr->cr_label);
		label_hold(label);
		newcr->cr_label = label;
	}

	return (newcr);
}
예제 #3
0
static int
cgetlabel(bslabel_t *label_p, vnode_t *vp)
{
	ts_label_t	*tsl;
	int		error = 0;

	if ((tsl = getflabel(vp)) == NULL)
		return (EIO);

	if (copyout((caddr_t)label2bslabel(tsl), (caddr_t)label_p,
	    sizeof (*(label_p))) != 0)
		error = EFAULT;

	label_rele(tsl);
	return (error);
}
예제 #4
0
/*
 * Create a new cred based on the supplied label
 */
cred_t *
newcred_from_bslabel(bslabel_t *blabel, uint32_t doi, int flags)
{
	ts_label_t *lbl = labelalloc(blabel, doi, flags);
	cred_t *cr = NULL;

	if (lbl != NULL) {
		if ((cr = crdup_flags(dummycr, flags)) != NULL) {
			cr->cr_label = lbl;
		} else {
			label_rele(lbl);
		}
	}

	return (cr);
}
예제 #5
0
/*
 * Release previous hold on a cred structure.  Free it if refcnt == 0.
 * If cred uses label different from zone label, free it.
 */
void
crfree(cred_t *cr)
{
	if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) {
		ASSERT(cr != kcred);
		if (cr->cr_label)
			label_rele(cr->cr_label);
		if (cr->cr_klpd)
			crklpd_rele(cr->cr_klpd);
		if (cr->cr_zone)
			zone_cred_rele(cr->cr_zone);
		if (cr->cr_ksid)
			kcrsid_rele(cr->cr_ksid);
		if (cr->cr_grps)
			crgrprele(cr->cr_grps);

		kmem_cache_free(cred_cache, cr);
	}
}
예제 #6
0
/*
 * Returns 0 on success, ENOMEM on memory allocation failure, EHOSTUNREACH
 * if the connection credentials fail remote host accreditation or
 * if the new destination does not support the previously established
 * connection security label. If sleep is true, this function should
 * never fail for a memory allocation failure. The boolean parameter
 * "first" decides whether the newly created faddr structure should be
 * added at the beginning of the list or at the end.
 *
 * Note: caller must hold conn fanout lock.
 */
int
sctp_add_faddr(sctp_t *sctp, in6_addr_t *addr, int sleep, boolean_t first)
{
	sctp_faddr_t	*faddr;
	mblk_t		*timer_mp;
	int		err;
	conn_t		*connp = sctp->sctp_connp;

	if (is_system_labeled()) {
		ip_xmit_attr_t	*ixa = connp->conn_ixa;
		ts_label_t	*effective_tsl = NULL;

		ASSERT(ixa->ixa_tsl != NULL);

		/*
		 * Verify the destination is allowed to receive packets
		 * at the security label of the connection we are initiating.
		 *
		 * tsol_check_dest() will create a new effective label for
		 * this connection with a modified label or label flags only
		 * if there are changes from the original label.
		 *
		 * Accept whatever label we get if this is the first
		 * destination address for this connection. The security
		 * label and label flags must match any previuous settings
		 * for all subsequent destination addresses.
		 */
		if (IN6_IS_ADDR_V4MAPPED(addr)) {
			uint32_t dst;
			IN6_V4MAPPED_TO_IPADDR(addr, dst);
			err = tsol_check_dest(ixa->ixa_tsl,
			    &dst, IPV4_VERSION, connp->conn_mac_mode,
			    connp->conn_zone_is_global, &effective_tsl);
		} else {
			err = tsol_check_dest(ixa->ixa_tsl,
			    addr, IPV6_VERSION, connp->conn_mac_mode,
			    connp->conn_zone_is_global, &effective_tsl);
		}
		if (err != 0)
			return (err);

		if (sctp->sctp_faddrs == NULL && effective_tsl != NULL) {
			ip_xmit_attr_replace_tsl(ixa, effective_tsl);
		} else if (effective_tsl != NULL) {
			label_rele(effective_tsl);
			return (EHOSTUNREACH);
		}
	}

	if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL)
		return (ENOMEM);
	bzero(faddr, sizeof (*faddr));
	timer_mp = sctp_timer_alloc((sctp), sctp_rexmit_timer, sleep);
	if (timer_mp == NULL) {
		kmem_cache_free(sctp_kmem_faddr_cache, faddr);
		return (ENOMEM);
	}
	((sctpt_t *)(timer_mp->b_rptr))->sctpt_faddr = faddr;

	/* Start with any options set on the conn */
	faddr->ixa = conn_get_ixa_exclusive(connp);
	if (faddr->ixa == NULL) {
		freemsg(timer_mp);
		kmem_cache_free(sctp_kmem_faddr_cache, faddr);
		return (ENOMEM);
	}
	faddr->ixa->ixa_notify_cookie = connp->conn_sctp;

	sctp_init_faddr(sctp, faddr, addr, timer_mp);
	ASSERT(faddr->ixa->ixa_cred != NULL);

	/* ip_attr_connect didn't allow broadcats/multicast dest */
	ASSERT(faddr->next == NULL);

	if (sctp->sctp_faddrs == NULL) {
		ASSERT(sctp->sctp_lastfaddr == NULL);
		/* only element on list; first and last are same */
		sctp->sctp_faddrs = sctp->sctp_lastfaddr = faddr;
	} else if (first) {
		ASSERT(sctp->sctp_lastfaddr != NULL);
		faddr->next = sctp->sctp_faddrs;
		sctp->sctp_faddrs = faddr;
	} else {
		sctp->sctp_lastfaddr->next = faddr;
		sctp->sctp_lastfaddr = faddr;
	}
	sctp->sctp_nfaddrs++;

	return (0);
}
예제 #7
0
/* Process the COOKIE packet, mp, directed at the listener 'sctp' */
sctp_t *
sctp_conn_request(sctp_t *sctp, mblk_t *mp, uint_t ifindex, uint_t ip_hdr_len,
    sctp_init_chunk_t *iack, ip_recv_attr_t *ira)
{
	sctp_t	*eager;
	ip6_t	*ip6h;
	int	err;
	conn_t	*connp, *econnp;
	sctp_stack_t	*sctps;
	struct sock_proto_props sopp;
	cred_t		*cr;
	pid_t		cpid;
	in6_addr_t	faddr, laddr;
	ip_xmit_attr_t	*ixa;

	/*
	 * No need to check for duplicate as this is the listener
	 * and we are holding the lock.  This means that no new
	 * connection can be created out of it.  And since the
	 * fanout already done cannot find a match, it means that
	 * there is no duplicate.
	 */
	ASSERT(OK_32PTR(mp->b_rptr));

	if ((eager = sctp_create_eager(sctp)) == NULL) {
		return (NULL);
	}

	connp = sctp->sctp_connp;
	sctps = sctp->sctp_sctps;
	econnp = eager->sctp_connp;

	if (connp->conn_policy != NULL) {
		/* Inherit the policy from the listener; use actions from ira */
		if (!ip_ipsec_policy_inherit(econnp, connp, ira)) {
			sctp_close_eager(eager);
			BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
			return (NULL);
		}
	}

	ip6h = (ip6_t *)mp->b_rptr;
	if (ira->ira_flags & IXAF_IS_IPV4) {
		ipha_t	*ipha;

		ipha = (ipha_t *)ip6h;
		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &laddr);
		IN6_IPADDR_TO_V4MAPPED(ipha->ipha_src, &faddr);
	} else {
		laddr = ip6h->ip6_dst;
		faddr = ip6h->ip6_src;
	}

	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
		/*
		 * XXX need to fix the cached policy issue here.
		 * We temporarily set the conn_laddr/conn_faddr here so
		 * that IPsec can use it for the latched policy
		 * selector.  This is obvioursly wrong as SCTP can
		 * use different addresses...
		 */
		econnp->conn_laddr_v6 = laddr;
		econnp->conn_faddr_v6 = faddr;
		econnp->conn_saddr_v6 = laddr;
	}
	if (ipsec_conn_cache_policy(econnp,
	    (ira->ira_flags & IRAF_IS_IPV4) != 0) != 0) {
		sctp_close_eager(eager);
		BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
		return (NULL);
	}

	/* Save for getpeerucred */
	cr = ira->ira_cred;
	cpid = ira->ira_cpid;

	if (is_system_labeled()) {
		ip_xmit_attr_t *ixa = econnp->conn_ixa;

		ASSERT(ira->ira_tsl != NULL);

		/* Discard any old label */
		if (ixa->ixa_free_flags & IXA_FREE_TSL) {
			ASSERT(ixa->ixa_tsl != NULL);
			label_rele(ixa->ixa_tsl);
			ixa->ixa_free_flags &= ~IXA_FREE_TSL;
			ixa->ixa_tsl = NULL;
		}

		if ((connp->conn_mlp_type != mlptSingle ||
		    connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
		    ira->ira_tsl != NULL) {
			/*
			 * If this is an MLP connection or a MAC-Exempt
			 * connection with an unlabeled node, packets are to be
			 * exchanged using the security label of the received
			 * Cookie packet instead of the server application's
			 * label.
			 * tsol_check_dest called from ip_set_destination
			 * might later update TSF_UNLABELED by replacing
			 * ixa_tsl with a new label.
			 */
			label_hold(ira->ira_tsl);
			ip_xmit_attr_replace_tsl(ixa, ira->ira_tsl);
		} else {
			ixa->ixa_tsl = crgetlabel(econnp->conn_cred);
		}
	}

	err = sctp_accept_comm(sctp, eager, mp, ip_hdr_len, iack);
	if (err != 0) {
		sctp_close_eager(eager);
		BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
		return (NULL);
	}

	ASSERT(eager->sctp_current->ixa != NULL);

	ixa = eager->sctp_current->ixa;
	if (!(ira->ira_flags & IXAF_IS_IPV4)) {
		ASSERT(!(ixa->ixa_flags & IXAF_IS_IPV4));

		if (IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_src) ||
		    IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst)) {
			eager->sctp_linklocal = 1;

			ixa->ixa_flags |= IXAF_SCOPEID_SET;
			ixa->ixa_scopeid = ifindex;
			econnp->conn_incoming_ifindex = ifindex;
		}
	}

	/*
	 * On a clustered note send this notification to the clustering
	 * subsystem.
	 */
	if (cl_sctp_connect != NULL) {
		uchar_t	*slist;
		uchar_t	*flist;
		size_t	fsize;
		size_t	ssize;

		fsize = sizeof (in6_addr_t) * eager->sctp_nfaddrs;
		ssize = sizeof (in6_addr_t) * eager->sctp_nsaddrs;
		slist = kmem_alloc(ssize, KM_NOSLEEP);
		flist = kmem_alloc(fsize, KM_NOSLEEP);
		if (slist == NULL || flist == NULL) {
			if (slist != NULL)
				kmem_free(slist, ssize);
			if (flist != NULL)
				kmem_free(flist, fsize);
			sctp_close_eager(eager);
			BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
			SCTP_KSTAT(sctps, sctp_cl_connect);
			return (NULL);
		}
		/* The clustering module frees these list */
		sctp_get_saddr_list(eager, slist, ssize);
		sctp_get_faddr_list(eager, flist, fsize);
		(*cl_sctp_connect)(econnp->conn_family, slist,
		    eager->sctp_nsaddrs, econnp->conn_lport, flist,
		    eager->sctp_nfaddrs, econnp->conn_fport, B_FALSE,
		    (cl_sctp_handle_t)eager);
	}

	/* Connection established, so send up the conn_ind */
	if ((eager->sctp_ulpd = sctp->sctp_ulp_newconn(sctp->sctp_ulpd,
	    (sock_lower_handle_t)eager, NULL, cr, cpid,
	    &eager->sctp_upcalls)) == NULL) {
		sctp_close_eager(eager);
		BUMP_MIB(&sctps->sctps_mib, sctpListenDrop);
		return (NULL);
	}
	ASSERT(SCTP_IS_DETACHED(eager));
	eager->sctp_detached = B_FALSE;
	bzero(&sopp, sizeof (sopp));
	sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF;
	sopp.sopp_maxblk = strmsgsz;
	if (econnp->conn_family == AF_INET) {
		sopp.sopp_wroff = sctps->sctps_wroff_xtra +
		    sizeof (sctp_data_hdr_t) + sctp->sctp_hdr_len;
	} else {
		sopp.sopp_wroff = sctps->sctps_wroff_xtra +
		    sizeof (sctp_data_hdr_t) + sctp->sctp_hdr6_len;
	}
	eager->sctp_ulp_prop(eager->sctp_ulpd, &sopp);
	return (eager);
}
예제 #8
0
/*
 * smbfs_mount_label_policy:
 *	Determine whether the mount is allowed according to MAC check,
 *	by comparing (where appropriate) label of the remote server
 *	against the label of the zone being mounted into.
 *
 *	Returns:
 *		 0 :	access allowed
 *		-1 :	read-only access allowed (i.e., read-down)
 *		>0 :	error code, such as EACCES
 *
 * NB:
 * NFS supports Cipso labels by parsing the vfs_resource
 * to see what the Solaris server global zone has shared.
 * We can't support that for CIFS since resource names
 * contain share names, not paths.
 */
static int
smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr)
{
	bslabel_t	*server_sl, *mntlabel;
	zone_t		*mntzone = NULL;
	ts_label_t	*zlabel;
	tsol_tpc_t	*tp;
	ts_label_t	*tsl = NULL;
	int		retv;

	/*
	 * Get the zone's label.  Each zone on a labeled system has a label.
	 */
	mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE);
	zlabel = mntzone->zone_slabel;
	ASSERT(zlabel != NULL);
	label_hold(zlabel);

	retv = EACCES;				/* assume the worst */

	/*
	 * Next, get the assigned label of the remote server.
	 */
	tp = find_tpc(ipaddr, addr_type, B_FALSE);
	if (tp == NULL)
		goto out;			/* error getting host entry */

	if (tp->tpc_tp.tp_doi != zlabel->tsl_doi)
		goto rel_tpc;			/* invalid domain */
	if ((tp->tpc_tp.host_type != UNLABELED))
		goto rel_tpc;			/* invalid hosttype */

	server_sl = &tp->tpc_tp.tp_def_label;
	mntlabel = label2bslabel(zlabel);

	/*
	 * Now compare labels to complete the MAC check.  If the labels
	 * are equal or if the requestor is in the global zone and has
	 * NET_MAC_AWARE, then allow read-write access.   (Except for
	 * mounts into the global zone itself; restrict these to
	 * read-only.)
	 *
	 * If the requestor is in some other zone, but his label
	 * dominates the server, then allow read-down.
	 *
	 * Otherwise, access is denied.
	 */
	if (blequal(mntlabel, server_sl) ||
	    (crgetzoneid(cr) == GLOBAL_ZONEID &&
	    getpflags(NET_MAC_AWARE, cr) != 0)) {
		if ((mntzone == global_zone) ||
		    !blequal(mntlabel, server_sl))
			retv = -1;		/* read-only */
		else
			retv = 0;		/* access OK */
	} else if (bldominates(mntlabel, server_sl)) {
		retv = -1;			/* read-only */
	} else {
		retv = EACCES;
	}

	if (tsl != NULL)
		label_rele(tsl);

rel_tpc:
	/*LINTED*/
	TPC_RELE(tp);
out:
	if (mntzone)
		zone_rele(mntzone);
	label_rele(zlabel);
	return (retv);
}